@Override public LdapEntry[] groupSearch(DirContext dirContext, LdapEntry entry) throws IOException, NamingException { Set<LdapEntry> foundEntries = new HashSet<LdapEntry>(); // Load the list of group. Attributes groups = dirContext.getAttributes(entry.getDistinguishedName(), new String[] {groupAttribute}); Attribute groupRef = groups.get(groupAttribute); if (groupRef != null && groupRef.size() > 0) { NamingEnumeration<String> groupRefValues = (NamingEnumeration<String>) groupRef.getAll(); while (groupRefValues.hasMore()) { String distingushedName = groupRefValues.next(); SECURITY_LOGGER.tracef("Group found with distinguishedName=%s", distingushedName); String simpleName = null; if (groupNameAttribute != null) { // Load the Name Attributes groupNameAttrs = dirContext.getAttributes(distingushedName, new String[] {groupNameAttribute}); Attribute groupNameAttr = groupNameAttrs.get(groupNameAttribute); simpleName = (String) groupNameAttr.get(); SECURITY_LOGGER.tracef( "simpleName %s loaded for group with distinguishedName=%s", simpleName, distingushedName); } else { SECURITY_LOGGER.trace("No groupNameAttribute to load simpleName"); } foundEntries.add(new LdapEntry(simpleName, distingushedName)); } } else { SECURITY_LOGGER.tracef("No groups found for %s", entry); } return foundEntries.toArray(new LdapEntry[foundEntries.size()]); }
/** * Infer the root DN. * * @return null if not found. */ private String inferRootDN(String server) { try { Hashtable<String, String> props = new Hashtable<String, String>(); if (managerDN != null) { props.put(Context.SECURITY_PRINCIPAL, managerDN); props.put(Context.SECURITY_CREDENTIALS, getManagerPassword()); } props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); props.put(Context.PROVIDER_URL, toProviderUrl(fixNull(getServerUrl()), "")); DirContext ctx = new InitialDirContext(props); Attributes atts = ctx.getAttributes(""); Attribute a = atts.get("defaultNamingContext"); if (a != null && a.get() != null) { // this entry is available on Active Directory. See // http://msdn2.microsoft.com/en-us/library/ms684291(VS.85).aspx return a.get().toString(); } a = atts.get("namingcontexts"); if (a == null) { LOGGER.warning("namingcontexts attribute not found in root DSE of " + server); return null; } return a.get().toString(); } catch (NamingException e) { LOGGER.log(Level.WARNING, "Failed to connect to LDAP to infer Root DN for " + server, e); return null; } }
/** * Returns the host name and port that the specified XMPP server can be reached at for * client-to-server communication. A DNS lookup for a SRV record in the form * "_xmpp-client._tcp.example.com" is attempted, according to section 14.4 of RFC 3920. If that * lookup fails, a lookup in the older form of "_jabber._tcp.example.com" is attempted since * servers that implement an older version of the protocol may be listed using that notation. If * that lookup fails as well, it's assumed that the XMPP server lives at the host resolved by a * DNS lookup at the specified domain on the default port of 5222. * * <p>As an example, a lookup for "example.com" may return "im.example.com:5269". * * <p>Note on SRV record selection. We now check priority and weight, but we still don't do this * correctly. The missing behavior is this: if we fail to reach a host based on its SRV record * then we need to select another host from the other SRV records. In Smack 3.1.1 we're not going * to be able to do the major system redesign to correct this. * * @param domain the domain. * @return a HostAddress, which encompasses the hostname and port that the XMPP server can be * reached at for the specified domain. */ public static HostAddress resolveXMPPDomain(String domain) { if (context == null) { return new HostAddress(domain, 5222); } String key = "c" + domain; // Return item from cache if it exists. if (cache.containsKey(key)) { HostAddress address = (HostAddress) cache.get(key); if (address != null) { return address; } } String bestHost = domain; int bestPort = 5222; int bestPriority = 0; int bestWeight = 0; try { Attributes dnsLookup = context.getAttributes("_xmpp-client._tcp." + domain, new String[] {"SRV"}); Attribute srvAttribute = dnsLookup.get("SRV"); NamingEnumeration srvRecords = srvAttribute.getAll(); while (srvRecords.hasMore()) { String srvRecord = (String) srvRecords.next(); String[] srvRecordEntries = srvRecord.split(" "); int priority = Integer.parseInt(srvRecordEntries[srvRecordEntries.length - 4]); int port = Integer.parseInt(srvRecordEntries[srvRecordEntries.length - 2]); int weight = Integer.parseInt(srvRecordEntries[srvRecordEntries.length - 3]); String host = srvRecordEntries[srvRecordEntries.length - 1]; // Randomize the weight. weight *= Math.random() * weight; if ((bestPriority == 0) || (priority < bestPriority)) { // Choose a server with the lowest priority. bestPriority = priority; bestWeight = weight; bestHost = host; bestPort = port; } else if (priority == bestPriority) { // When we have like priorities then randomly choose a server based on its weight // The weights were randomized above. if (weight > bestWeight) { bestWeight = weight; bestHost = host; bestPort = port; } } } } catch (Exception e) { // Ignore. } // Host entries in DNS should end with a ".". if (bestHost.endsWith(".")) { bestHost = bestHost.substring(0, bestHost.length() - 1); } HostAddress address = new HostAddress(bestHost, bestPort); // Add item to cache. cache.put(key, address); return address; }
public UserDTO doLdapAuthentication(UserDTO dto) throws Exception { log.info("INSIDE LDAP AUTHENTICATION 2"); UserDTO ldapDTO = null; String url = "ldap://172.18.20.0:10389"; Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, url); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system"); env.put(Context.SECURITY_CREDENTIALS, "secret"); try { ldapDTO = new UserDTO(); DirContext ctx = new InitialDirContext(env); Attributes attrs = ctx.getAttributes("cn=" + dto.getUsername() + ",ou=users,ou=system"); Attribute userPassword = attrs.get("userPassword"); String ldapPasswordFromDB = new String((byte[]) userPassword.get()); String md5EncryptedPassword = encryptLdapPassword("md5", dto.getPassword()); if (md5EncryptedPassword.equalsIgnoreCase(ldapPasswordFromDB)) { ldapDTO.setEmployeeId((String) (attrs.get("employeeNumber").get())); ldapDTO.setEmployeeType((String) (attrs.get("employeeType").get())); ldapDTO.setUsername((String) (attrs.get("cn").get())); } ctx.close(); } catch (Exception e) { e.printStackTrace(); } return ldapDTO; }
/** * Connect to the DirContext, and retrieve the bound object, as well as its attributes. If no * object is bound with the name specified in the URL, then an IOException is thrown. * * @throws IOException Object not found */ @Override public void connect() throws IOException { if (!connected) { try { date = System.currentTimeMillis(); String path = URL_DECODER.convert(getURL().getFile(), false); if (context instanceof ProxyDirContext) { ProxyDirContext proxyDirContext = (ProxyDirContext) context; String hostName = proxyDirContext.getHostName(); String contextPath = proxyDirContext.getContextPath(); if (hostName != null) { if (!path.startsWith("/" + hostName + "/")) return; path = path.substring(hostName.length() + 1); } if (contextPath != null) { if (!path.startsWith(contextPath + "/")) { return; } path = path.substring(contextPath.length()); } } object = context.lookup(path); attributes = context.getAttributes(path); if (object instanceof Resource) resource = (Resource) object; if (object instanceof DirContext) collection = (DirContext) object; } catch (NamingException e) { // Object not found } connected = true; } }
public FormValidation doServerCheck( @QueryParameter final String server, @QueryParameter final String managerDN, @QueryParameter final String managerPassword) { if (!Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER)) return FormValidation.ok(); try { Hashtable<String, String> props = new Hashtable<String, String>(); if (managerDN != null && managerDN.trim().length() > 0 && !"undefined".equals(managerDN)) { props.put(Context.SECURITY_PRINCIPAL, managerDN); } if (managerPassword != null && managerPassword.trim().length() > 0 && !"undefined".equals(managerPassword)) { props.put(Context.SECURITY_CREDENTIALS, managerPassword); } props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); props.put(Context.PROVIDER_URL, toProviderUrl(server, "")); DirContext ctx = new InitialDirContext(props); ctx.getAttributes(""); return FormValidation.ok(); // connected } catch (NamingException e) { // trouble-shoot Matcher m = Pattern.compile( "(ldaps?://)?([^:]+)(?:\\:(\\d+))?(\\s+(ldaps?://)?([^:]+)(?:\\:(\\d+))?)*") .matcher(server.trim()); if (!m.matches()) return FormValidation.error( hudson.security.Messages.LDAPSecurityRealm_SyntaxOfServerField()); try { InetAddress adrs = InetAddress.getByName(m.group(2)); int port = m.group(1) != null ? 636 : 389; if (m.group(3) != null) port = Integer.parseInt(m.group(3)); Socket s = new Socket(adrs, port); s.close(); } catch (UnknownHostException x) { return FormValidation.error( hudson.security.Messages.LDAPSecurityRealm_UnknownHost(x.getMessage())); } catch (IOException x) { return FormValidation.error( x, hudson.security.Messages.LDAPSecurityRealm_UnableToConnect(server, x.getMessage())); } // otherwise we don't know what caused it, so fall back to the general error report // getMessage() alone doesn't offer enough return FormValidation.error( e, hudson.security.Messages.LDAPSecurityRealm_UnableToConnect(server, e)); } catch (NumberFormatException x) { // The getLdapCtxInstance method throws this if it fails to parse the port number return FormValidation.error(hudson.security.Messages.LDAPSecurityRealm_InvalidPortNumber()); } }
public Attributes getAttributes(String name, String[] attrIds) throws NamingException { ResolveResult res = getRootURLContext(name, myEnv); DirContext ctx = (DirContext) res.getResolvedObj(); try { return ctx.getAttributes(res.getRemainingName(), attrIds); } finally { ctx.close(); } }
/** * @see net.jforum.sso.LoginAuthenticator#validateLogin(java.lang.String, java.lang.String, * java.util.Map) */ public User validateLogin(String username, String password, Map extraParams) { Hashtable environment = this.prepareEnvironment(); StringBuffer principal = new StringBuffer(256) .append(SystemGlobals.getValue(ConfigKeys.LDAP_LOGIN_PREFIX)) .append(username) .append(',') .append(SystemGlobals.getValue(ConfigKeys.LDAP_LOGIN_SUFFIX)); environment.put(Context.SECURITY_PRINCIPAL, principal.toString()); environment.put(Context.SECURITY_CREDENTIALS, password); DirContext dir = null; try { dir = new InitialDirContext(environment); String lookupPrefix = SystemGlobals.getValue(ConfigKeys.LDAP_LOOKUP_PREFIX); String lookupSuffix = SystemGlobals.getValue(ConfigKeys.LDAP_LOOKUP_SUFFIX); if (lookupPrefix == null || lookupPrefix.length() == 0) { lookupPrefix = SystemGlobals.getValue(ConfigKeys.LDAP_LOGIN_PREFIX); } if (lookupSuffix == null || lookupSuffix.length() == 0) { lookupSuffix = SystemGlobals.getValue(ConfigKeys.LDAP_LOGIN_SUFFIX); } String lookupPrincipal = lookupPrefix + username + "," + lookupSuffix; Attribute att = dir.getAttributes(lookupPrincipal) .get(SystemGlobals.getValue(ConfigKeys.LDAP_FIELD_EMAIL)); SSOUtils utils = new SSOUtils(); if (!utils.userExists(username)) { String email = att != null ? (String) att.get() : "noemail"; utils.register("ldap", email); } return utils.getUser(); } catch (AuthenticationException e) { return null; } catch (NamingException e) { return null; } finally { if (dir != null) { try { dir.close(); } catch (NamingException e) { // close jndi context } } } }
public static String doLookup(String hostName) throws NamingException { int pos = hostName.indexOf('@'); String domain = hostName.substring(++pos); Hashtable<String, String> env = new Hashtable<String, String>(); env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory"); DirContext ictx = new InitialDirContext(env); Attributes attrs = ictx.getAttributes(domain, new String[] {"MX"}); Attribute attr = attrs.get("MX"); if ((attr == null) || (attr.size() == 0)) { attrs = ictx.getAttributes(domain, new String[] {"A"}); attr = attrs.get("A"); } if (attr == null) return "no server found"; return (String) (attr.get()); }
/** * Returns the host name and port that the specified XMPP server can be reached at for * server-to-server communication. A DNS lookup for a SRV record in the form * "_xmpp-server._tcp.example.com" is attempted, according to section 14.4 of RFC 3920. If that * lookup fails, a lookup in the older form of "_jabber._tcp.example.com" is attempted since * servers that implement an older version of the protocol may be listed using that notation. If * that lookup fails as well, it's assumed that the XMPP server lives at the host resolved by a * DNS lookup at the specified domain on the default port of 5269. * * <p>As an example, a lookup for "example.com" may return "im.example.com:5269". * * @param domain the domain. * @return a HostAddress, which encompasses the hostname and port that the XMPP server can be * reached at for the specified domain. */ public static HostAddress resolveXMPPServerDomain(String domain) { if (context == null) { return new HostAddress(domain, 5269); } String key = "s" + domain; // Return item from cache if it exists. if (cache.containsKey(key)) { HostAddress address = (HostAddress) cache.get(key); if (address != null) { return address; } } String host = domain; int port = 5269; try { Attributes dnsLookup = context.getAttributes("_xmpp-server._tcp." + domain, new String[] {"SRV"}); String srvRecord = (String) dnsLookup.get("SRV").get(); String[] srvRecordEntries = srvRecord.split(" "); port = Integer.parseInt(srvRecordEntries[srvRecordEntries.length - 2]); host = srvRecordEntries[srvRecordEntries.length - 1]; } catch (Exception e) { // Attempt lookup with older "jabber" name. try { Attributes dnsLookup = context.getAttributes("_jabber._tcp." + domain, new String[] {"SRV"}); String srvRecord = (String) dnsLookup.get("SRV").get(); String[] srvRecordEntries = srvRecord.split(" "); port = Integer.parseInt(srvRecordEntries[srvRecordEntries.length - 2]); host = srvRecordEntries[srvRecordEntries.length - 1]; } catch (Exception e2) { // Ignore. } } // Host entries in DNS should end with a ".". if (host.endsWith(".")) { host = host.substring(0, host.length() - 1); } HostAddress address = new HostAddress(host, port); // Add item to cache. cache.put(key, address); return address; }
static LdapType guessType(final DirContext ctx) throws NamingException { final Attributes rootAtts = ctx.getAttributes(""); Attribute supported = rootAtts.get("supportedCapabilities"); if (supported != null && (supported.contains("1.2.840.113556.1.4.800") || supported.contains("1.2.840.113556.1.4.1851"))) { return new ActiveDirectory(); } return RFC_2307; }
public Attributes getAttributes(Name name, String[] attrIds) throws NamingException { if (name.size() == 1) { return getAttributes(name.get(0), attrIds); } else { DirContext ctx = getContinuationDirContext(name); try { return ctx.getAttributes(name.getSuffix(1), attrIds); } finally { ctx.close(); } } }
/** * Gets values of an entry attribute using a Distinguished Name and the name of the attribute * * @param DN Distinguished Name of the entry * @param attribute name of the attribute * @return List<Object> * @exception LDAPException */ public List<Object> getEntryAttribute(final String DN, final String attribute) throws LDAPException { List<Object> _values = new ArrayList<Object>(); try { DirContext ctx = connection.connect(); if (ctx == null) { throw new LDAPException("directory service not available"); } Attributes _atts = null; if ("modifyTimestamp".equals(attribute)) { String[] _attributeName = new String[1]; _attributeName[0] = attribute; _atts = ctx.getAttributes(DN, _attributeName); } else { _atts = ctx.getAttributes(DN); if (_atts == null) { throw new LDAPException("entry not found [" + DN + "]"); } } Attribute _att = _atts.get(attribute); if (_att == null) { throw new LDAPException("attribute [" + attribute + "] not found in entry"); } @SuppressWarnings("unchecked") NamingEnumeration<Object> _ne = (NamingEnumeration<Object>) _att.getAll(); while (_ne.hasMore()) { _values.add(_ne.next()); } return _values; } catch (NullPointerException e) { _log.log(java.util.logging.Level.ALL, "getEntryAttribute() null pointer"); throw new LDAPException("get entry attribute null pointer"); } catch (NamingException e) { _log.log(java.util.logging.Level.ALL, "getEntryAttribute() - " + e.getMessage()); throw new LDAPException(e.getMessage()); } finally { connection.disconnect(); } }
private void getAllAttributes() { System.out.println("Inside getAllAttributes"); Attributes attrs = null; try { DirContext ctx = LDAPConstants.getLdapContext(); attrs = ctx.getAttributes(""); NamingEnumeration enm = attrs.getAll(); while (enm.hasMore()) { System.out.println(enm.next()); } } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
// 创建一个用于测试的用户组(当用户组不存在时创建) private void createGroup() throws NamingException { try { Attributes attr = ctx.getAttributes(BASE_DN); } catch (NamingException ne) { Attribute objclass = new BasicAttribute("objectclass"); objclass.add("top"); objclass.add("groupofuniquenames"); Attribute cn = new BasicAttribute("cn", "student"); Attributes attrs = new BasicAttributes(); attrs.put(objclass); attrs.put(cn); ctx.bind(BASE_DN, null, attrs); System.out.println("Group created.n"); } }
/** * Send anonymous email. Note that although we could give any address as from address, (for * example: <b>'[email protected]' is valid</b>), the from of MailMessage should always be the correct format * of email address(for example the <b>'aaaa' is invalid</b>). Otherwise an exception would be * thrown say that username is invalid. * * @param mail The MailMessage object which contains at least all the required attributes to be * sent. */ public static void sendAnonymousEmail(MailMessage mail) { String dns = "dns://"; Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); env.put(Context.PROVIDER_URL, dns); String[] tos = mail.getTos(); try { DirContext ctx = new InitialDirContext(env); for (String to : tos) { String domain = to.substring(to.indexOf('@') + 1); // Get MX(Mail eXchange) records from DNS Attributes attrs = ctx.getAttributes(domain, new String[] {"MX"}); if (attrs == null || attrs.size() <= 0) { throw new java.lang.IllegalStateException( "Error: Your DNS server has no Mail eXchange records!"); } @SuppressWarnings("rawtypes") NamingEnumeration servers = attrs.getAll(); String smtpHost = null; boolean isSend = false; StringBuffer buf = new StringBuffer(); // try all the mail exchange server to send the email. while (servers.hasMore()) { Attribute hosts = (Attribute) servers.next(); for (int i = 0; i < hosts.size(); ++i) { // sample: 20 mx2.qq.com smtpHost = (String) hosts.get(i); // parse the string to get smtpHost. sample: mx2.qq.com smtpHost = smtpHost.substring(smtpHost.lastIndexOf(' ') + 1); try { sendEmail(smtpHost, mail, true); isSend = true; return; } catch (Exception e) { LOGGER.error("", e); buf.append(e.toString()).append("\r\n"); continue; } } } if (!isSend) { throw new java.lang.IllegalStateException("Error: Send email error." + buf.toString()); } } } catch (NamingException e) { LOGGER.error("", e); } }
/** * Gets an <code>LDAPDirectoryEntry</code> object that represent an entry on directory. You can * provide a list of attributes to be ignored when load the entry data. Look for attribute matches * using a map of values * * @param DN Distinguished Name of the entry * @param ignore_attributes You can indicate here a list of attribute to be ignored when load all * entry data. this is useful if you have some big data in some attributes and do you want to * ignore that * @param attribute_matches Map with attribute names and values to match * @return LDAPDirectoryEntry * @exception LDAPException */ public LDAPDirectoryEntry getEntry( final String DN, final List<String> ignore_attributes, final Map<String, String> attribute_matches) throws LDAPException { LDAPDirectoryEntry _e = null; try { _e = new LDAPDirectoryEntry(DN); DirContext ctx = connection.connect(); if (ctx == null) { throw new LDAPException("directory service not available"); } Attributes atts = ctx.getAttributes(DN); if (atts == null) { return null; } @SuppressWarnings("unchecked") NamingEnumeration<Attribute> ne = (NamingEnumeration<Attribute>) atts.getAll(); while (ne.hasMore()) { Attribute att = ne.next(); if (ignore_attributes == null || !ignore_attributes.contains(att.getID())) { List<Object> _values = new ArrayList<Object>(); @SuppressWarnings("unchecked") NamingEnumeration<Object> nea = (NamingEnumeration<Object>) att.getAll(); while (nea.hasMore()) { Object _value = nea.next(); if (attribute_matches == null || !attribute_matches.containsKey(att.getID())) { _values.add(_value); } else if (attribute_matches.get(att.getID()) != null && String.valueOf(_value).contains(attribute_matches.get(att.getID()))) { _values.add(_value); } } _e.setAttribute(att.getID(), _values.toArray()); } } } catch (NullPointerException e) { _log.log(java.util.logging.Level.ALL, "getEntry() null pointer"); throw new LDAPException("get entry null pointer"); } catch (NamingException e) { _log.log(java.util.logging.Level.ALL, "getEntry() - " + e.getMessage()); throw new LDAPException(e.getMessage()); } finally { connection.disconnect(); } return _e; }
/** Test that the partition has been correctly created */ public void testPartition() throws NamingException { // We should be able to read it DirContext appRoot = createContext("o=sevenSeas"); assertNotNull(appRoot); // Let's get the entry associated to the top level Attributes attributes = appRoot.getAttributes(""); assertNotNull(attributes); assertEquals("sevenseas", attributes.get("o").get()); Attribute attribute = attributes.get("objectClass"); assertNotNull(attribute); assertTrue(attribute.contains("top")); assertTrue(attribute.contains("organization")); // Ok, everything is fine }
/** Parse the URL in the following formats:<br> */ protected void parseServerURLs() { int dbPos = url.indexOf('/'); if (dbPos == -1) { // SHORT FORM addHost(getDefaultHost()); name = url; } else { name = url.substring(dbPos + 1); for (String host : url.substring(0, dbPos).split(ADDRESS_SEPARATOR)) host = addHost(host); } if (serverURLs.size() == 1 && OGlobalConfiguration.NETWORK_BINARY_DNS_LOADBALANCING_ENABLED.getValueAsBoolean()) { // LOOK FOR LOAD BALANCING DNS TXT RECORD final String primaryServer = serverURLs.get(0); try { final Hashtable<String, String> env = new Hashtable<String, String>(); env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory"); env.put( "com.sun.jndi.ldap.connect.timeout", OGlobalConfiguration.NETWORK_BINARY_DNS_LOADBALANCING_TIMEOUT.getValueAsString()); final DirContext ictx = new InitialDirContext(env); final String hostName = primaryServer.indexOf(":") == -1 ? primaryServer : primaryServer.substring(0, primaryServer.indexOf(":")); final Attributes attrs = ictx.getAttributes(hostName, new String[] {"TXT"}); final Attribute attr = attrs.get("TXT"); if (attr != null) { String configuration = (String) attr.get(); if (configuration.startsWith("")) configuration = configuration.substring(1, configuration.length() - 1); if (configuration != null) { final String[] parts = configuration.split(" "); for (String part : parts) { if (part.startsWith("s=")) { addHost(part.substring("s=".length())); } } } } } catch (NamingException e) { } } }
/** * Verify if an entry Distinguished Name already exists on directory * * @param DN Distinguished Name of the entry * @return boolean * @exception LDAPException */ public boolean checkEntry(final String DN) throws LDAPException { try { DirContext ctx = connection.connect(); if (ctx == null) { throw new LDAPException("directory service not available"); } if (ctx.getAttributes(DN) != null) { return true; } } catch (NullPointerException e) { _log.log(java.util.logging.Level.ALL, "checkEntry() null pointer"); throw new LDAPException("add entry null pointer"); } catch (NamingException e) { _log.log(java.util.logging.Level.ALL, "checkEntry() - " + e.getMessage()); throw new LDAPException(e.getMessage()); } finally { connection.disconnect(); } return false; }
/** * This method retrieves data using LDAP protocol. - CRL from given LDAP url, e.g. * ldap://ldap.infonotary.com/dc=identity-ca,dc=infonotary,dc=com * * @param urlString * @return */ private byte[] ldapGet(final String urlString) { final Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, urlString); try { final DirContext ctx = new InitialDirContext(env); final Attributes attributes = ctx.getAttributes(""); final javax.naming.directory.Attribute attribute = attributes.get("certificateRevocationList;binary"); final byte[] ldapBytes = (byte[]) attribute.get(); if (ldapBytes == null || ldapBytes.length == 0) { throw new DSSException("Cannot download CRL from: " + urlString); } return ldapBytes; } catch (Exception e) { LOG.warn(e.getMessage(), e); } return null; }
protected boolean bindUser(DirContext context, String dn, String password) throws NamingException { boolean isValid = false; if (ActiveMQServerLogger.LOGGER.isDebugEnabled()) { ActiveMQServerLogger.LOGGER.debug("Binding the user."); } context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn); context.addToEnvironment(Context.SECURITY_CREDENTIALS, password); try { context.getAttributes("", null); isValid = true; if (ActiveMQServerLogger.LOGGER.isDebugEnabled()) { ActiveMQServerLogger.LOGGER.debug("User " + dn + " successfully bound."); } } catch (AuthenticationException e) { isValid = false; if (ActiveMQServerLogger.LOGGER.isDebugEnabled()) { ActiveMQServerLogger.LOGGER.debug("Authentication failed for dn=" + dn); } } if (isLoginPropertySet(CONNECTION_USERNAME)) { context.addToEnvironment( Context.SECURITY_PRINCIPAL, getLDAPPropertyValue(CONNECTION_USERNAME)); } else { context.removeFromEnvironment(Context.SECURITY_PRINCIPAL); } if (isLoginPropertySet(CONNECTION_PASSWORD)) { context.addToEnvironment( Context.SECURITY_CREDENTIALS, getLDAPPropertyValue(CONNECTION_PASSWORD)); } else { context.removeFromEnvironment(Context.SECURITY_CREDENTIALS); } return isValid; }
/** * Use DNS and obtains the LDAP servers that we should try. * * @param preferredServers If non-null, these servers are reported instead of doing the * discovery. In previous versions, this was simply added on top of the auto-discovered * list, but this option is useful when you have many domain controllers (because a single * mistyped password can cause an authentication attempt with every listed server, which can * lock the user out!) This also puts this feature in alignment with {@link * #DOMAIN_CONTROLLERS}, which seems to indicate that there are users who prefer this * behaviour. * @return A list with at least one item. */ public List<SocketInfo> obtainLDAPServer( DirContext ictx, String domainName, String site, String preferredServers) throws NamingException { List<SocketInfo> result = new ArrayList<SocketInfo>(); if (preferredServers == null) preferredServers = DOMAIN_CONTROLLERS; if (preferredServers != null) { for (String token : preferredServers.split(",")) { result.add(new SocketInfo(token.trim())); } return result; } String ldapServer = null; Attribute a = null; NamingException failure = null; // try global catalog if it exists first, then the particular domain for (String candidate : CANDIDATES) { ldapServer = candidate + (site != null ? site + "._sites." : "") + domainName; LOGGER.fine("Attempting to resolve " + ldapServer + " to SRV record"); try { Attributes attributes = ictx.getAttributes(ldapServer, new String[] {"SRV"}); a = attributes.get("SRV"); if (a != null) break; } catch (NamingException e) { // failed retrieval. try next option. failure = e; } } if (a != null) { // discover servers class PrioritizedSocketInfo implements Comparable<PrioritizedSocketInfo> { SocketInfo socket; int priority; PrioritizedSocketInfo(SocketInfo socket, int priority) { this.socket = socket; this.priority = priority; } public int compareTo(PrioritizedSocketInfo that) { return that.priority - this.priority; // sort them so that bigger priority comes first } } List<PrioritizedSocketInfo> plist = new ArrayList<PrioritizedSocketInfo>(); for (NamingEnumeration ne = a.getAll(); ne.hasMoreElements(); ) { String record = ne.next().toString(); LOGGER.fine("SRV record found: " + record); String[] fields = record.split(" "); // fields[1]: weight // fields[2]: port // fields[3]: target host name String hostName = fields[3]; // cut off trailing ".". JENKINS-2647 if (hostName.endsWith(".")) hostName = hostName.substring(0, hostName.length() - 1); int port = Integer.parseInt(fields[2]); if (FORCE_LDAPS) { // map to LDAPS ports. I don't think there's any SRV records specifically for LDAPS. // I think Microsoft considers LDAP+TLS the way to go, or else there should have been // separate SRV entries. if (port == 389) port = 686; if (port == 3268) port = 3269; } int p = Integer.parseInt(fields[0]); plist.add(new PrioritizedSocketInfo(new SocketInfo(hostName, port), p)); } Collections.sort(plist); for (PrioritizedSocketInfo psi : plist) result.add(psi.socket); } if (result.isEmpty()) { NamingException x = new NamingException("No SRV record found for " + ldapServer); if (failure != null) x.initCause(failure); throw x; } LOGGER.fine(ldapServer + " resolved to " + result); return result; }
// 查找用户 private Attributes findUser(String uid) throws NamingException { return ctx.getAttributes("uid=" + uid + "," + BASE_DN); }
/** * List all the attributes of an LDAP node. * * @param root The root DirContext. * @param dn The DN of the node, relative to the root DirContext. */ public static void listAttributes(DirContext root, String dn) throws NamingException { final Attributes attrs = root.getAttributes(dn); System.out.println("dn: " + dn); System.out.println("attributes: " + attrs); }
/** * Resolves all the groups that the user is in. * * <p>We now use <a * href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms680275(v=vs.85).aspx">tokenGroups</a> * attribute, which is a computed attribute that lists all the SIDs of the groups that the user is * directly/indirectly in. We then use that to retrieve all the groups in one query and resolve * their canonical names. * * @param userDN User's distinguished name. * @param context Used for making queries. */ private Set<GrantedAuthority> resolveGroups(String domainDN, String userDN, DirContext context) throws NamingException { LOGGER.finer("Looking up group of " + userDN); Attributes id = context.getAttributes(userDN, new String[] {"tokenGroups", "memberOf", "CN"}); Attribute tga = id.get("tokenGroups"); if (tga == null) { // see JENKINS-11644. still trying to figure out when this happens LOGGER.warning("Failed to retrieve tokenGroups for " + userDN); HashSet<GrantedAuthority> r = new HashSet<GrantedAuthority>(); r.add(new GrantedAuthorityImpl("unable-to-retrieve-tokenGroups")); return r; } // build up the query to retrieve all the groups StringBuilder query = new StringBuilder("(|"); List<byte[]> sids = new ArrayList<byte[]>(); NamingEnumeration<?> tokenGroups = tga.getAll(); while (tokenGroups.hasMore()) { byte[] gsid = (byte[]) tokenGroups.next(); query.append("(objectSid={" + sids.size() + "})"); sids.add(gsid); } tokenGroups.close(); query.append(")"); Set<GrantedAuthority> groups = new HashSet<GrantedAuthority>(); NamingEnumeration<SearchResult> renum = new LDAPSearchBuilder(context, domainDN) .subTreeScope() .returns("cn") .search(query.toString(), sids.toArray()); while (renum.hasMore()) { Attributes a = renum.next().getAttributes(); Attribute cn = a.get("cn"); if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine(userDN + " is a member of " + cn); groups.add(new GrantedAuthorityImpl(cn.get().toString())); } renum.close(); { /* stage 2: use memberOf to find groups that aren't picked up by tokenGroups. This includes distribution groups */ LOGGER.fine("Stage 2: looking up via memberOf"); Stack<Attributes> q = new Stack<Attributes>(); q.push(id); while (!q.isEmpty()) { Attributes identity = q.pop(); LOGGER.finer("Looking up group of " + identity); Attribute memberOf = identity.get("memberOf"); if (memberOf == null) continue; for (int i = 0; i < memberOf.size(); i++) { try { Attributes group = context.getAttributes( new LdapName(memberOf.get(i).toString()), new String[] {"CN", "memberOf"}); Attribute cn = group.get("CN"); if (cn == null) { LOGGER.fine("Failed to obtain CN of " + memberOf.get(i)); continue; } if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine(cn.get() + " is a member of " + memberOf.get(i)); if (groups.add(new GrantedAuthorityImpl(cn.get().toString()))) { q.add(group); // recursively look for groups that this group is a member of. } } catch (NameNotFoundException e) { LOGGER.fine("Failed to obtain CN of " + memberOf.get(i)); } } } } return groups; }
public FormValidation doValidate( @QueryParameter(fixEmpty = true) String domain, @QueryParameter(fixEmpty = true) String site, @QueryParameter(fixEmpty = true) String bindName, @QueryParameter(fixEmpty = true) String bindPassword, @QueryParameter(fixEmpty = true) String server) throws IOException, ServletException, NamingException { ClassLoader ccl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); try { Functions.checkPermission(Hudson.ADMINISTER); String n = Util.fixEmptyAndTrim(domain); if (n == null) { // no value given yet return FormValidation.error("No domain name set"); } Secret password = Secret.fromString(bindPassword); if (bindName != null && password == null) return FormValidation.error("DN is specified but not password"); String[] names = n.split(","); for (String name : names) { if (!name.endsWith(".")) name += '.'; DirContext ictx; // first test the sanity of the domain name itself try { LOGGER.fine("Attempting to resolve " + name + " to NS record"); ictx = createDNSLookupContext(); Attributes attributes = ictx.getAttributes(name, new String[] {"NS"}); Attribute ns = attributes.get("NS"); if (ns == null) { LOGGER.fine("Attempting to resolve " + name + " to A record"); attributes = ictx.getAttributes(name, new String[] {"A"}); Attribute a = attributes.get("A"); if (a == null) throw new NamingException(name + " doesn't look like a domain name"); } LOGGER.log(Level.FINE, "{0} resolved to {1}", new Object[] {name, ns}); } catch (NamingException e) { LOGGER.log(Level.WARNING, "Failed to resolve " + name + " to A record", e); return FormValidation.error(e, name + " doesn't look like a valid domain name"); } // then look for the LDAP server List<SocketInfo> servers; try { servers = obtainLDAPServer(ictx, name, site, server); } catch (NamingException e) { String msg = site == null ? "No LDAP server was found in " + name : "No LDAP server was found in the " + site + " site of " + name; LOGGER.log(Level.WARNING, msg, e); return FormValidation.error(e, msg); } if (bindName != null) { // make sure the bind actually works try { DirContext context = bind(bindName, Secret.toString(password), servers); try { // actually do a search to make sure the credential is valid new LDAPSearchBuilder(context, toDC(domain)).searchOne("(objectClass=user)"); } finally { context.close(); } } catch (BadCredentialsException e) { return FormValidation.error(e, "Bad bind username or password"); } catch (javax.naming.AuthenticationException e) { return FormValidation.error(e, "Bad bind username or password"); } catch (Exception e) { return FormValidation.error(e, e.getMessage()); } } else { // just some connection test // try to connect to LDAP port to make sure this machine has LDAP service IOException error = null; for (SocketInfo si : servers) { try { si.connect().close(); break; // looks good } catch (IOException e) { LOGGER.log(Level.FINE, "Failed to connect to " + si, e); error = e; // try the next server in the list } } if (error != null) { LOGGER.log(Level.WARNING, "Failed to connect to " + servers, error); return FormValidation.error(error, "Failed to connect to " + servers); } } } // looks good return FormValidation.ok("Success"); } finally { Thread.currentThread().setContextClassLoader(ccl); } }
/** * This method will test if a user has access to the LDAP, if so it will then check the list of * groups and check for is access * * @param String username as named via a uid in the LDAP * @param String password clear text in LDAP * @return Hashtable authenticate object */ public Hashtable authenticate(String username, String password, String keyfob_id) { Hashtable authHT = new Hashtable(); if (keyfob_id != null) { System.out.println("attempted keyfob value: " + keyfob_id); // we need to bind with our anon bind user username = this.AD_ANON_BIND_UNAME; password = this.AD_ANON_BIND_PWORD; } // assume they will not pass the test boolean authenticated = false; // first check to see if we even need to hit LDAP (not overridden) if (this.LDAP_OVERRIDE) { System.out.println("Override Authentication"); // just check against stored username/password, put in all groups if (username.equals(this.LDAP_OVERRIDE_UNAME) && password.equals(this.LDAP_OVERRIDE_PWORD)) { authenticated = true; // just add then to each group for (String key : groups.keySet()) { // push the name of the group and access to it boolean authHT.put(key, true); // method throws NamingException } } } else { // authenticate agianst creditials server System.err.println("Trying " + this.PROVIDER_TYPE + " authentication by: " + username); try { // build a hash table to pass as a bindable event // Set up environment for creating initial context Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, this.INITIAL_CONTEXT_FACTORY); env.put(Context.SECURITY_AUTHENTICATION, this.SECURITY_AUTHENTICATION); // we take the uid to authenticate, pair it with the username, and append the base location env.put(Context.PROVIDER_URL, this.PROVIDER_URL); if (this.PROVIDER_TYPE.equals("AD")) { env.put(Context.SECURITY_PRINCIPAL, username + "@" + this.AD_DOMAIN); } else if (this.PROVIDER_TYPE.equals("LDAP")) { env.put( Context.SECURITY_PRINCIPAL, "uid=" + username + "," + this.USERS_LOC + this.BASE_DN); } // we don't need to throw errors here because first try/catch finds it env.put(Context.SECURITY_CREDENTIALS, password); // send env assigments to console // enumerateContents(env.elements()); /** now that we have our hash values lets go authenticate */ // first we want to connect to the LDAP Server and create initial context // making sure the user name and password are valid ctx = new InitialDirContext( env); // Throws AuthenticationException if not valid username/password // WE NEVER GO PAST HERE IF AuthenticationException THROWN System.err.println("connection and creditials valid"); /** * we just split the two paths of AD and LDAP authentication because the LDAP way worked and * we are migrating to AD. However we want to be able to easily switch back until the LDAP * service is discontinued. Theoretically both services should be 'searchable' the same way * at some point the LDAP code should be removed or universal code written */ if (this.PROVIDER_TYPE.equals("AD")) { /** AD way, get the group list, if they match add */ SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); // either search by user name or by keyfob id. either way will return a user if one is // found NamingEnumeration results = null; if (keyfob_id != null) { // we don't challenge on keyfob. assumed if you have keyfob you are that user System.out.println("searching for keyfob id: >" + keyfob_id + "<"); results = ctx.search( this.USERS_LOC + this.BASE_DN, "(" + this.ATTRIBUTE_NAME_KEYFOB_ID + "=" + keyfob_id + ")", constraints); authHT.put("keyfob_id", keyfob_id); // pass it back as proof positive we found it } else { results = ctx.search( this.USERS_LOC + this.BASE_DN, "(" + this.ATTRIBUTE_NAME_UNAME + "=" + username + ")", constraints); } while (results != null && results.hasMore()) { SearchResult sr = (SearchResult) results.next(); String dn = sr.getName() + ", " + this.USERS_LOC + this.BASE_DN; Attributes ar = ctx.getAttributes(dn, MY_ATTRS); if (ar == null) { // we need the user to have attributes throw new Exception("Entry " + dn + " has none of the specified attributes\n"); } for (int i = 0; i < MY_ATTRS.length; i++) { Attribute attr = ar.get(MY_ATTRS[i]); if (attr == null) { continue; } System.out.println(MY_ATTRS[i] + ":"); for (Enumeration vals = attr.getAll(); vals.hasMoreElements(); ) { String temp_next_element = vals.nextElement().toString(); // returns generic Object System.out.println("\t" + temp_next_element); // push the attributes to the auth HT if (!(authHT.containsKey(MY_ATTRS[i]))) { // push the name of the group and access to it boolean authHT.put(MY_ATTRS[i], temp_next_element); } // see if this element value matches any of my groups for (String key : groups.keySet()) { if (temp_next_element .toLowerCase() .startsWith("cn=" + groups.get(key).toLowerCase())) { // push the name of the group and access to it boolean authHT.put(key, true); // if user is found in ANY of the predefined groups they are 'authenticated' to // login. // RolemManager.as handles ACL authenticated = true; } } } } } // now for any groups not found, set them to false for (String key : groups.keySet()) { if (!(authHT.containsKey(key))) { // push the name of the group and access to it boolean authHT.put(key, false); } } // end AD WAY } else if (this.PROVIDER_TYPE.equals("LDAP")) { // authenticated only in the sense they are a valid AD user authenticated = true; // now that we have verified they are a valid user, lets see what type of access they have // groups are specified in the config file as "GROUP_<name>" key=value pairs where value // is the LDAP group name // and key is what we are looking for in the scheduling app for (String key : groups.keySet()) { // push the name of the group and access to it boolean authHT.put( key, new Boolean( userInGroup(username, groups.get(key)))); // method throws NamingException } } else { throw new Exception("Provider type not found."); } // Close the context when we're done ctx.close(); } catch (AuthenticationException e) { // binding to LDAP server with provided username/password failed // e.printStackTrace(); System.err.println( "AuthenticationException: " + e.getMessage()); // outputs -> [LDAP: error code 49 - Invalid Credentials] errorStack += e.getMessage() + "\n"; } catch (NamingException e) { // catches invalid DN. Should not be thrown unless changes made to DN // Could also fail from the context of the called method userInGroup System.err.println("NamingException: " + e.getMessage()); // e.printStackTrace(); errorStack += e.getMessage() + "\n"; } catch (Exception e) { e.printStackTrace(); System.err.println("Exception: " + e.getMessage()); errorStack += e.getMessage() + "\n"; } finally { // make sure our connection is closed if relevant if (ctx != null) { try { ctx.close(); } catch (NamingException e) { throw new RuntimeException(e); } } } } // push whether or not it was authenticated authHT.put("authenticated", new Boolean(authenticated)); // spill contents to catalina.out file enumerateContents(authHT.keys()); enumerateContents(authHT.elements()); return (authHT); }