首页 > 解决方案 > 线程“主”java.lang.NullPointerException 中的 LDAP 查询 Java 异常

问题描述

我的代码有问题:

import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

/**
 * Example code for retrieving a Users Primary Group
 * from Microsoft Active Directory via. its LDAP API
 * 

public class LDAPTest {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws NamingException {

        final String ldapAdServer = "/*Server*/";
        final String ldapSearchBase = "ou=users,ou=,dc=,dc=";

        final String ldapUsername = "/*Username*/";
        final String ldapPassword = "/*Passwort*/";

        final String ldapAccountToLookup = "/*lookupaccount*/";


        Hashtable<String, Object> env = new Hashtable<String, Object>();
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        if(ldapUsername != null) {
            env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
        }
        if(ldapPassword != null) {
            env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
        }
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, ldapAdServer);

        //ensures that objectSID attribute values
        //will be returned as a byte[] instead of a String
        env.put("java.naming.ldap.attributes.binary", "objectSID");

        //the following is helpful in debugging errors
        env.put("com.sun.jndi.ldap.trace.ber", System.err);

        LdapContext ctx = new InitialLdapContext(env,null);

        LDAPTest ldap = new LDAPTest();


        //1) lookup the ldap account
        SearchResult srLdapUser = ldap.findAccountByAccountName(ctx, ldapSearchBase, ldapAccountToLookup);



        //2) get the SID of the users primary group
        String primaryGroupSID = ldap.getPrimaryGroupSID(srLdapUser);

        //3) get the users Primary Group
        String primaryGroupName = ldap.findGroupBySID(ctx, ldapSearchBase,primaryGroupSID);


    }



    public SearchResult findAccountByAccountName(DirContext ctx, String ldapSearchBase, String accountName) throws NamingException {

        String searchFilter = "(&(objectClass=user)(sAMAccountName=" + accountName + "))";

        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        NamingEnumeration<SearchResult> results = ctx.search(ldapSearchBase, searchFilter, searchControls);

        SearchResult searchResult = null ;
        if(results.hasMoreElements()) {
             searchResult = (SearchResult) results.nextElement();

            //make sure there is not another item available, there should be only 1 match
            if(results.hasMoreElements()) {
                System.err.println("Matched multiple users for the accountName: " + accountName);
                return null;
            }
        }

        return searchResult;
    }

    public String findGroupBySID(DirContext ctx, String ldapSearchBase, String sid) throws NamingException {

        String searchFilter = "(&(objectClass=group)(objectSid=" + sid + "))";

        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        NamingEnumeration<SearchResult> results = ctx.search(ldapSearchBase, searchFilter, searchControls);

        if(results.hasMoreElements()) {
            SearchResult searchResult = (SearchResult) results.nextElement();

            //make sure there is not another item available, there should be only 1 match
            if(results.hasMoreElements()) {
                System.err.println("Matched multiple groups for the group with SID: " + sid);
                return null;
            } else {
                return (String)searchResult.getAttributes().get("sAMAccountName").get();
            }
        }
        return null;
    }

    public String getPrimaryGroupSID(SearchResult srLdapUser) throws NamingException {
        byte[] objectSID = (byte[])srLdapUser.getAttributes().get("objectSid").get();
        String strPrimaryGroupID = (String)srLdapUser.getAttributes().get("primaryGroupID").get();

        String strObjectSid = decodeSID(objectSID);

        return strObjectSid.substring(0, strObjectSid.lastIndexOf('-') + 1) + strPrimaryGroupID;
    }

    /**
     * The binary data is in the form:
     * byte[0] - revision level
     * byte[1] - count of sub-authorities
     * byte[2-7] - 48 bit authority (big-endian)
     * and then count x 32 bit sub authorities (little-endian)
     * 
     * The String value is: S-Revision-Authority-SubAuthority[n]...
     * 
     * Based on code from here - http://forums.oracle.com/forums/thread.jspa?threadID=1155740&tstart=0
     */
    public static String decodeSID(byte[] sid) {

        final StringBuilder strSid = new StringBuilder("S-");

        // get version
        final int revision = sid[0];
        strSid.append(Integer.toString(revision));

        //next byte is the count of sub-authorities
        final int countSubAuths = sid[1] & 0xFF;

        //get the authority
        long authority = 0;
        //String rid = "";
        for(int i = 2; i <= 7; i++) {
           authority |= ((long)sid[i]) << (8 * (5 - (i - 2)));
        }
        strSid.append("-");
        strSid.append(Long.toHexString(authority));

        //iterate all the sub-auths
        int offset = 8;
        int size = 4; //4 bytes for each sub auth
        for(int j = 0; j < countSubAuths; j++) {
            long subAuthority = 0;
            for(int k = 0; k < size; k++) {
                subAuthority |= (long)(sid[offset + k] & 0xFF) << (8 * k);
            }

            strSid.append("-");
            strSid.append(subAuthority);

            offset += size;
        }

        return strSid.toString();    
    }
}

首先,如果我运行此代码,我将成为错误消息:

Exception in thread "main" javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(Unknown Source)
at javax.naming.directory.InitialDirContext.getURLOrDefaultInitDirCtx(Unknown Source)
at javax.naming.directory.InitialDirContext.search(Unknown Source)
at LDAPTest.findAccountByAccountName(LDAPTest.java:74)
at LDAPTest.main(LDAPTest.java:58)

作为一项措施,我对 LdapContext ctx = new InitialLdapContext(env,null);

现在我收到错误消息

Exception in thread "main" java.lang.NullPointerException
at LDAPTest.getPrimaryGroupSID(LDAPTest.java:114)
at LDAPTest.main(LDAPTest.java:61)

我不知道如何继续。有谁能够帮我?有人熟悉吗?-------------------------------------------------- --------------

标签: javaldapldap-queryldapconnection

解决方案


你可以试试这个,当你的 ldap 身份验证可能没有以正确的方式完成时,会发生命名异常。

private boolean isLdapServerOnline() {
    try {
        Hashtable authEnv = new Hashtable();

        authEnv.put(Context.INITIAL_CONTEXT_FACTORY, LDAP_JNDI_FACTORY);
        authEnv.put(Context.PROVIDER_URL, ldapUrl);
        authEnv.put(Context.SECURITY_AUTHENTICATION, ldapSecurityAuthentication);
        authEnv.put(Context.SECURITY_PRINCIPAL, ldapDistinguishedName);
        authEnv.put(Context.SECURITY_CREDENTIALS, ldapPassword);
        DirContext authContext = new InitialDirContext(authEnv);
        return true;
    } catch (AuthenticationException authEx) {
        LOGGER.error("Active Directory Authentication failed", authEx);
        return false;
    } catch (NamingException namEx) {
        LOGGER.error("Unable to connect to Active Directory", namEx);
        return false;
    }
}

推荐阅读