LDAP Authentication using Java

前端 未结 4 1422
面向向阳花
面向向阳花 2020-12-12 15:23

I need to do LDAP Authentication for an application.

I tried the following program:

import java.util.Hashtable;  

import javax.naming.Context;  
imp         


        
相关标签:
4条回答
  • 2020-12-12 15:48

    You will have to provide the entire user dn in SECURITY_PRINCIPAL

    like this

    env.put(Context.SECURITY_PRINCIPAL, "cn=username,ou=testOu,o=test"); 
    
    0 讨论(0)
  • 2020-12-12 15:51

    This is my LDAP Java login test application supporting LDAP:// and LDAPS:// self-signed test certificate. Code is taken from few SO posts, simplified implementation and removed legacy sun.java.* imports.

    • how to accept self-signed certificates for JNDI/LDAP connections?
    • Authenticating against Active Directory with Java on Linux

    Usage
    I have run this in Windows7 and Linux machines against WinAD directory service. Application prints username and member groups.

    $ java -cp classes test.LoginLDAP url=ldap://1.2.3.4:389 username=myname@company.fi password=mypwd

    $ java -cp classes test.LoginLDAP url=ldaps://1.2.3.4:636 username=myname@company.fi password=mypwd

    Test application supports temporary self-signed test certificates for ldaps:// protocol, this DummySSLFactory accepts any server cert so man-in-the-middle is possible. Real life installation should import server certificate to a local JKS keystore file and not using dummy factory.

    Application uses enduser's username+password for initial context and ldap queries, it works for WinAD but don't know if can be used for all ldap server implementations. You could create context with internal username+pwd then run queries to see if given enduser is found.

    LoginLDAP.java

    package test;
    
    import java.util.*;
    import javax.naming.*;
    import javax.naming.directory.*;
    
    public class LoginLDAP {
    
        public static void main(String[] args) throws Exception {
            Map<String,String> params = createParams(args);
    
            String url = params.get("url"); // ldap://1.2.3.4:389 or ldaps://1.2.3.4:636
            String principalName = params.get("username"); // firstname.lastname@mydomain.com
            String domainName = params.get("domain"); // mydomain.com or empty
    
            if (domainName==null || "".equals(domainName)) {
                int delim = principalName.indexOf('@');
                domainName = principalName.substring(delim+1);
            }
    
            Properties props = new Properties();
            props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            props.put(Context.PROVIDER_URL, url); 
            props.put(Context.SECURITY_PRINCIPAL, principalName); 
            props.put(Context.SECURITY_CREDENTIALS, params.get("password")); // secretpwd
            if (url.toUpperCase().startsWith("LDAPS://")) {
                props.put(Context.SECURITY_PROTOCOL, "ssl");
                props.put(Context.SECURITY_AUTHENTICATION, "simple");
                props.put("java.naming.ldap.factory.socket", "test.DummySSLSocketFactory");         
            }
    
            InitialDirContext context = new InitialDirContext(props);
            try {
                SearchControls ctrls = new SearchControls();
                ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
                NamingEnumeration<SearchResult> results = context.search(toDC(domainName),"(& (userPrincipalName="+principalName+")(objectClass=user))", ctrls);
                if(!results.hasMore())
                    throw new AuthenticationException("Principal name not found");
    
                SearchResult result = results.next();
                System.out.println("distinguisedName: " + result.getNameInNamespace() ); // CN=Firstname Lastname,OU=Mycity,DC=mydomain,DC=com
    
                Attribute memberOf = result.getAttributes().get("memberOf");
                if(memberOf!=null) {
                    for(int idx=0; idx<memberOf.size(); idx++) {
                        System.out.println("memberOf: " + memberOf.get(idx).toString() ); // CN=Mygroup,CN=Users,DC=mydomain,DC=com
                        //Attribute att = context.getAttributes(memberOf.get(idx).toString(), new String[]{"CN"}).get("CN");
                        //System.out.println( att.get().toString() ); //  CN part of groupname
                    }
                }
            } finally {
                try { context.close(); } catch(Exception ex) { }
            }       
        }
    
        /**
         * Create "DC=sub,DC=mydomain,DC=com" string
         * @param domainName    sub.mydomain.com
         * @return
         */
        private static String toDC(String domainName) {
            StringBuilder buf = new StringBuilder();
            for (String token : domainName.split("\\.")) {
                if(token.length()==0) continue;
                if(buf.length()>0)  buf.append(",");
                buf.append("DC=").append(token);
            }
            return buf.toString();
        }
    
        private static Map<String,String> createParams(String[] args) {
            Map<String,String> params = new HashMap<String,String>();  
            for(String str : args) {
                int delim = str.indexOf('=');
                if (delim>0) params.put(str.substring(0, delim).trim(), str.substring(delim+1).trim());
                else if (delim==0) params.put("", str.substring(1).trim());
                else params.put(str, null);
            }
            return params;
        }
    
    }
    

    And SSL helper class.

    package test;
    
    import java.io.*;
    import java.net.*;
    import java.security.SecureRandom;
    import java.security.cert.X509Certificate;    
    import javax.net.*;
    import javax.net.ssl.*;
    
    public class DummySSLSocketFactory extends SSLSocketFactory {
        private SSLSocketFactory socketFactory;
        public DummySSLSocketFactory() {
            try {
              SSLContext ctx = SSLContext.getInstance("TLS");
              ctx.init(null, new TrustManager[]{ new DummyTrustManager()}, new SecureRandom());
              socketFactory = ctx.getSocketFactory();
            } catch ( Exception ex ){ throw new IllegalArgumentException(ex); }
        }
    
          public static SocketFactory getDefault() { return new DummySSLSocketFactory(); }
    
          @Override public String[] getDefaultCipherSuites() { return socketFactory.getDefaultCipherSuites(); }
          @Override public String[] getSupportedCipherSuites() { return socketFactory.getSupportedCipherSuites(); }
    
          @Override public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException {
            return socketFactory.createSocket(socket, string, i, bln);
          }
          @Override public Socket createSocket(String string, int i) throws IOException, UnknownHostException {
            return socketFactory.createSocket(string, i);
          }
          @Override public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException, UnknownHostException {
            return socketFactory.createSocket(string, i, ia, i1);
          }
          @Override public Socket createSocket(InetAddress ia, int i) throws IOException {
            return socketFactory.createSocket(ia, i);
          }
          @Override public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException {
            return socketFactory.createSocket(ia, i, ia1, i1);
          }
    }
    
    class DummyTrustManager implements X509TrustManager {
        @Override public void checkClientTrusted(X509Certificate[] xcs, String str) {
            // do nothing
        }
        @Override public void checkServerTrusted(X509Certificate[] xcs, String str) {
            /*System.out.println("checkServerTrusted for authType: " + str); // RSA
            for(int idx=0; idx<xcs.length; idx++) {
                X509Certificate cert = xcs[idx];
                System.out.println("X500Principal: " + cert.getSubjectX500Principal().getName());
            }*/
        }
        @Override public X509Certificate[] getAcceptedIssuers() {
            return new java.security.cert.X509Certificate[0];
        }
    }
    
    0 讨论(0)
  • 2020-12-12 15:53

    Following Code authenticates from LDAP using pure Java JNDI. The Principle is:-

    1. First Lookup the user using a admin or DN user.
    2. The user object needs to be passed to LDAP again with the user credential
    3. No Exception means - Authenticated Successfully. Else Authentication Failed.

    Code Snippet

    public static boolean authenticateJndi(String username, String password) throws Exception{
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.put(Context.PROVIDER_URL, "ldap://LDAPSERVER:PORT");
        props.put(Context.SECURITY_PRINCIPAL, "uid=adminuser,ou=special users,o=xx.com");//adminuser - User with special priviledge, dn user
        props.put(Context.SECURITY_CREDENTIALS, "adminpassword");//dn user password
    
    
        InitialDirContext context = new InitialDirContext(props);
    
        SearchControls ctrls = new SearchControls();
        ctrls.setReturningAttributes(new String[] { "givenName", "sn","memberOf" });
        ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    
        NamingEnumeration<javax.naming.directory.SearchResult> answers = context.search("o=xx.com", "(uid=" + username + ")", ctrls);
        javax.naming.directory.SearchResult result = answers.nextElement();
    
        String user = result.getNameInNamespace();
    
        try {
            props = new Properties();
            props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            props.put(Context.PROVIDER_URL, "ldap://LDAPSERVER:PORT");
            props.put(Context.SECURITY_PRINCIPAL, user);
            props.put(Context.SECURITY_CREDENTIALS, password);
    
       context = new InitialDirContext(props);
        } catch (Exception e) {
            return false;
        }
        return true;
    }
    
    0 讨论(0)
  • 2020-12-12 15:58
    // this class will authenticate LDAP UserName or Email
    
    // simply call LdapAuth.authenticateUserAndGetInfo (username,password);
    
    //Note: Configure ldapURI ,requiredAttributes ,ADSearchPaths,accountSuffex 
    
    import java.util.*;
    
    import javax.naming.*;
    
    import java.util.regex.*;
    
    import javax.naming.directory.*;
    
    import javax.naming.ldap.InitialLdapContext;
    
    import javax.naming.ldap.LdapContext;
    
    public class LdapAuth {
    
    
    private final static String ldapURI = "ldap://20.200.200.200:389/DC=corp,DC=local";
    
    private final static String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
    
    private  static String[] requiredAttributes = {"cn","givenName","sn","displayName","userPrincipalName","sAMAccountName","objectSid","userAccountControl"};
    
    
    // see you active directory user OU's hirarchy 
    
    private  static String[] ADSearchPaths = 
    
    { 
    
        "OU=O365 Synced Accounts,OU=ALL USERS",
    
        "OU=Users,OU=O365 Synced Accounts,OU=ALL USERS",
    
        "OU=In-House,OU=Users,OU=O365 Synced Accounts,OU=ALL USERS",
    
        "OU=Torbram Users,OU=Users,OU=O365 Synced Accounts,OU=ALL USERS",
    
        "OU=Migrated Users,OU=TES-Users"
    
    };
    
    
    private static String accountSuffex = "@corp.local"; // this will be used if user name is just provided
    
    
    private static void authenticateUserAndGetInfo (String user, String password) throws Exception {
    
        try {
    
    
            Hashtable<String,String> env = new Hashtable <String,String>();
    
            env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
    
            env.put(Context.PROVIDER_URL, ldapURI);     
    
            env.put(Context.SECURITY_AUTHENTICATION, "simple");
    
            env.put(Context.SECURITY_PRINCIPAL, user);
    
            env.put(Context.SECURITY_CREDENTIALS, password);
    
            DirContext ctx = new InitialDirContext(env);
    
            String filter = "(sAMAccountName="+user+")";  // default for search filter username
    
            if(user.contains("@"))  // if user name is a email then
            {
                //String parts[] = user.split("\\@");
                //use different filter for email
                filter = "(userPrincipalName="+user+")";
            }
    
            SearchControls ctrl = new SearchControls();
            ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE);
            ctrl.setReturningAttributes(requiredAttributes);
    
            NamingEnumeration userInfo = null;
    
    
            Integer i = 0;
            do
            {
                userInfo = ctx.search(ADSearchPaths[i], filter, ctrl);
                i++;
    
            } while(!userInfo.hasMore() && i < ADSearchPaths.length );
    
            if (userInfo.hasMore()) {
    
                SearchResult UserDetails = (SearchResult) userInfo.next();
                Attributes userAttr = UserDetails.getAttributes();System.out.println("adEmail = "+userAttr.get("userPrincipalName").get(0).toString());
    
                System.out.println("adFirstName = "+userAttr.get("givenName").get(0).toString());
    
                System.out.println("adLastName = "+userAttr.get("sn").get(0).toString());
    
                System.out.println("name = "+userAttr.get("cn").get(0).toString());
    
                System.out.println("AdFullName = "+userAttr.get("cn").get(0).toString());
    
            }
    
            userInfo.close();
    
        }
        catch (javax.naming.AuthenticationException e) {
    
        }
    }   
    }
    
    0 讨论(0)
提交回复
热议问题