General documentation: Article directory Github: github.com/black-ant

The operation manual series mainly records the systematic operation notes accumulated in ordinary times. This article is mainly about THE LDAP (AD) related notes.

preface

LDAP is a Lightweight Directory Access Protocol. It is used to publish Directory information to many different resources. LDAP is similar to a centralized address book or a phone book

This article will cover OpenLDAP and Windows AD, both of which are implementations of the LDAP protocol.

1. LDAP Basics

Features:

  • LDAP supports TCP/IP
  • LDAP can be said to be a special database. LDAP implements the storage of data structures
  • LDAP uses a tree structure
  • LDAP is optimized for queries to provide better read performance
  • LDAP is an open Internet standard and a cross-platform protocol
  • Copy technology by push and pull, allowing the use of ACI (Control of access rights)
  • LDAP is a standard protocol for development
  • LDAP supports the strong authentication mode

The LDAP server

  • LDAP uses the Client/server model
  • The LDAP service is a system consisting of a directory database and a set of access protocols
  • The LDAP server is used to query and update the LDAP directory

2. LDAP attributes

The key of

  • Dc: A record of the owning region (which tree), domain component, at the top
  • dc -> Domain Component
  • Distinguished Name (DN): specifies the detailed position of a record
  • RDN: similar to relative road strength: CN= Zhang SAN
  • rdn -> Relative Distinguished Name
  • Base DN: indicates the top of the LDAP directory tree, that is, the root
  • GUID: globally unique identifier. The GUID is a 128-bit value
  • UPN: indicates the user principal name, which is shorter than the DN
  • UPN : [email protected]

Attribute Default Attribute:

  • Cn Common Name: indicates the Name
  • Sn sur name: last name
  • Ou Organizational Unit Name: Specifies the Name of the Unit (department)
  • It’s an organization
  • C countryName: country
  • Dc domainComponent: domain name
  • TelephoneNumber: telephoneNumber
  • ObjectClass: built-in attribute

structure

  • dc -> ou -> cn
  • Dc is a domain name and a number. There are many oU organizations under the tree and CN organizations under the tree
  • N is road strength, for example, CN= Zhang SAN,OU=Web front-end group,OU= Software Development Department,DC=moonxy,DC=com
  • N Relative path strength: CN= Zhang3, OU=Web front-end group

The basic concept

  • (dn + RDN + Base DN) (RDN + Base DN)
  • Attribute: Each entry has an Attribute (name-value) ()
  • ObjectClass: an ObjectClass is a collection of properties that come in three types: Structural, Abstract, and Auxiliary
  • Schema: A Schema, a collection of object classes
  • Backend & database: Backend is used for operations and database is used for storage

3. One of the LDAP implementations: Windows AD

Windows AD profile

The Directory Database in the Active Directory domain is used to store objects such as user accounts, computer accounts, printers, and shared folders. The component that provides Directory services is the Active Directory Domain Service (AD DS)

In the AD domain service, THE AD is a namespace. Using the AD, we can find all the information about an object by its name

AD Principal members:

AD Domain objects and properties: Resources in an AD Domain exist in the form of objects. An Object is a collection of properties using Attriburte. A domain can have multiple domain controllers. Each domain controller has equal status and stores the same Active Directory management tool: Ctive Directory Users and computers + Active Directory Management center

The difference between AD and LDAP is intuitive

  • AD: Active Directory: AD is a Windows service that stores user accounts, groups, and computers on the Windows network
  • Active Directory = LDAP server +LDAP application (Windows domain controller). AD is an application instance of LDPA and is accessed through LDAP
  • Active Directory implements an LDAP server and then uses the LDAP server to implement its own application (domain controller).
  • Simply put, data is written to the AD Server through THE LDAP protocol
  • It is reasonable to store accounts through the AD directory structure

4. Operation guide

The code is based on Windows AD 2012. LDAP needs to be compatible. Of course, the following code uses Javax.naming, which is a more low-level operation, or you can choose SpringLDAP, which is also comfortable to use.

!!!!!!!!!! More detailed operation can refer to.net. Tirasa. Connid. Bundles. Ldap package, a lot of operation started from the package

Node 1: Creates Connect

In the Naming package, the LDAP connection is implemented using the LdapContext object. The SSL connection uses LDAPS ://636, and the non-SSL connection uses LDAP ://389


private static final String LDAP_CTX_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
public static final String CONNECT_TIMEOUT_ENV_PROP = "com.sun.jndi.ldap.connect.timeout";
public static final String READ_TIMEOUT_ENV_PROP = "com.sun.jndi.ldap.read.timeout";

public LdapContext createLdapContext(a) {
        final java.util.Hashtable<Object, Object> env = new java.util.Hashtable<Object, Object>();
         
        // Define the LDAP factory class
        env.put(Context.INITIAL_CONTEXT_FACTORY, LDAP_CTX_FACTORY);
         
        // Build the LDAP access address
        env.put(Context.PROVIDER_URL, getLdapUrls());
        env.put(Context.REFERRAL, "follow");
        
        // Define the timeout period
        env.put(CONNECT_TIMEOUT_ENV_PROP,Long.toString(config.getConnectTimeout()));
        env.put(READ_TIMEOUT_ENV_PROP, Long.toString(config.getReadTimeout()));
 
        // Enable SSL/trust key
        if (config.isSsl()) {
            env.put(Context.SECURITY_PROTOCOL, "ssl");
        }
        env.put(LDAP_CTX_SOCKET_FACTORY, TrustAllSocketFactory.class.getName());
 
        env.put(LDAP_BINARY_ATTRIBUTE,
                SDDL_ATTR + "" + OBJECTGUID + "" + OBJECTSID);
        // Access the current account
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, "administrator@antblack");
 
        / / password
        env.put(Context.SECURITY_CREDENTIALS, "123456");
        LdapContext context = null;
        try {
            context = new InitialLdapContext(env, null);
        } catch (NamingException e) {
            e.printStackTrace();
        }
 
        return context;
}

    private String getLdapUrls(a) {
        StringBuilder builder = new StringBuilder();
        builder.append("ldap://");
        builder.append(config.getHost());
        builder.append(':');
        builder.append(config.getPort());
        for (String failover : LdapUtil.nullAsEmpty(config.getFailover())) {
            builder.append(' ');
            builder.append(failover);
        }
        return builder.toString();
    }

Copy the code

Node 2: Property build operation


// Step 1: Build attributes. The Naming package manages attributes by Attribute
final BasicAttributes ldapAttrs = new BasicAttributes(true);
dapAttrs.put(ldapAttr);

 
// Step 3: Create an object
Context context = ctx.createSubcontext("Research and development of OU = 0219, DC antblack, DC = com, DC = cn", adAttrs);
 
 
// Build attributes
public BasicAttributes getAttriutes(a) {
    BasicAttributes adAttrs = new BasicAttributes(true);
    adAttrs.put(getAttribute("description"."test"));
 
    BasicAttribute objectClass = new BasicAttribute("objectClass");
    for (String ldapClass : orgClass) {
        objectClass.add(ldapClass);
    }
    adAttrs.put(objectClass);
    return adAttrs;
}
 
public BasicAttribute getAttribute(String key, String value) {
    return new BasicAttribute(key, value);
}
 
// ORG
private Set<String> orgClass = new TreeSet<>();
orgClass.add("organizationalUnit");
orgClass.add("top")
     
// GROUP
orgClass.add("group");
orgClass.add("top");   
 
// Person
orgClass.add("organizationalPerson");
orgClass.add("top");
orgClass.add("person");
orgClass.add("user");


Copy the code

Node 3: Builds the GUID

/** * convert to GUID */
public static String exchangeGUID(String guid) {
    return Hex.getEscaped(GUID.getGuidAsByteArray(guid));
}
 
/** * Convert entryDN to UID */
public String entryExchangeGUID(final String entryDN) throws NamingException {
    return GUID.getGuidAsString((byte[]) getEntryID(entryDN).get());
}


// This is usually the entryUUID, but can also be customized by type, as shown below
/**
* The LDAP attribute to map Uid to.
*/
private String uidAttribute = "entryUUID";

/**
* The LDAP attribute to map Gid to.
*/
private String gidAttribute = "entryUUID";

if (oclass.equals(ObjectClass.GROUP)) {
    clazz = oclass;
    idAttribute = conn.getConfiguration().getGidAttribute();
} else if (oclass.equals(ObjectClass.ACCOUNT)) {
    clazz = oclass;
    idAttribute = conn.getConfiguration().getUidAttribute();
} else {
    clazz = ObjectClass.ALL;
    idAttribute = null;
}

Copy the code

Node 4: AD query

LDAP has a complete set of query statements. The following example is @www.ietf.org/rfc/rfc2254…

// Query all
(objectClass=*)
     
/ / objectGUID queries
 (&(objectClass=*)(objectGUID=c92131cee-dd23-445-9967-c462123455667))
 (objectGUID=l\D7\ABTP\14\0CL\B5\A9\3E\E60\F0\90\29)
 // GUID to be converted to hexadecimal format
      
/ / cn queries(& (objectClass = *) (cn = O organization U125))// sAMAccountName(& (objectClass = *) (sAMAccountName = O organization U125))// syncSearch
(|(&(objectClass=user))(objectClass=group)(&(isDeleted=FALSE)(objectClass=user)))  
 
 
 
 
// Java query mode
public void search(String info, String baseOUName) throws NamingException {
 
    // Step 1: Search the root path --> baseDN
    baseOUName = "OU=" + baseOUName + ",DC=antblack,DC=com,DC=cn";
 
    // Step 2: Define the search scope
    SearchControls searchCtls = new SearchControls();
    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
 
    // Step 3: Prepare the search statement
    String searchFilter = ADSearchUtils.getNativeFilter(ADSearchType.EQUALS, "name",
                info, ObjectClass.ORGANIZATION);
 
    // Step 4: Search
    try {
        final NamingEnumeration<SearchResult> results =
                ctx.search(baseOUName, searchFilter, searchCtls);
 
        // Step 5: Processing results
        Set backMap = new HashSet();
        while (results.hasMoreElements()) {
            SearchResult sr = (SearchResult) results.next();
            logger.info("------> this is result :{} <-------", sr.getAttributes().get("name"));
            backMap.add(sr.getAttributes());
        }
 
        logger.info("------> this back is :{} <-------", backMap.size());
    } catch (NamingException e) {
        logger.error("E----> error :{} -- content :{}", e.getClass() + e.getMessage(), e);
        throwe; }}// Identifier type
filter     = "(" filtercomp ")"
filtercomp = and / or / not / item
and        = "&" filterlist
or         = "|" filterlist
not        = "!" filter
filterlist = 1*filter
item       = simple / present / substring / extensible
simple     = attr filtertype value
filtertype = equal / approx / greater / less
equal      = "="
approx     = "~ ="
greater    = "> ="
less       = "< ="
extensible = attr [":dn"] [":" matchingrule] ": =" value
                     / [":dn"] ":" matchingrule ": =" value
present    = attr "=" *"
substring  = attr "=" [initial] any [final]
initial    = value
any        = "*" *(value "*")
final      = value
attr       = AttributeDescription from Section 4.1. 5 of [1]
matchingrule = MatchingRuleId from Section 4.19. of [1]
value      = AttributeValue from Section 4.16. of [1]
 
 
// For details about query operations, see the documentation

 
 
// 注意点 :
1Special characters should also be considered in search. ASCII codes can be used to replace them, for example (cn=*\2a*) (o=Parens R Us \28for all your parenthetical needs\29)
(cn=*\2A*)
(filename=C:\5cMyFile)
(bin=\00\00\00\04)
(sn=Lu\c4\8di\c4\87)



Copy the code

Node 5: Other operations

// Modify the properties
public final static int ADD_ATTRIBUTE = 1;
public final static int REPLACE_ATTRIBUTE = 2;
public final static int REMOVE_ATTRIBUTE = 3;

modifyAttributes(entryDN, attrToModify, DirContext.REPLACE_ATTRIBUTE);
private void modifyAttributes(final String entryDN, final List<ModificationItem> modItems) {
    try {
    conn.getInitialContext().modifyAttributes(entryDN, modItems.toArray(new ModificationItem[modItems.size()]));
    } catch (NamingException e) {
        throw newConnectorException(e); }}// Rename/modify the path
LdapContext ctx = conn.getInitialContext().newInstance(null);
ctx.addToEnvironment("java.naming.ldap.deleteRDN", deleteOldRdn);
ctx.rename(oldName, newName);

/ / set of operationsGroup operations are performed through the member/memberOf attributeCopy the code

5. Special operation

5.1 User Permission Operations

// Add the userAccountControl attribute to the BasicAttributes to set the user's permissions
public static final String UACCONTROL_ATTR = "userAccountControl";

Copy the code

Permissions are not arbitrary. Some permissions can only be added by specific sub-permissions. The AD provides the following permissions:

Note that the transfer of AD permissions is not arbitrary. The first four permissions in the following figure can only be transferred to the specified permissions, and other permissions can be transferred!!

5.2 Group Permission Operations

// Set group permissions by adding the groupType attribute to the BasicAttributes
public static final String LDAP_GROUP_TYPE = "groupType";
Copy the code

5.3 Nationality Operation

// AD has multiple attributes to control international
public static final String COUNTRY = "c";
public static final String COUNTRY_NAME = "co";
public static final String COUNTRY_CODE = "countryCode";

BasicAttribute c = new BasicAttribute(COUNTRY,countryCode.getCountrySign());
BasicAttribute co = new BasicAttribute(COUNTRY_NAME,countryCode.getCountryName());
BasicAttribute code = new BasicAttribute(COUNTRY_CODE,countryCode.getCode());
Copy the code

5.4 Connection Pool Problems

Reference documentation @ docs.oracle.com/javase/jndi…

Connection pooling is described in great detail in this document

// The common way to configure connection pooling is:
env.put("com.sun.jndi.ldap.connect.pool"."true");
env.put("com.sun.jndi.ldap.connect.pool.authentication"."simple");
env.put("com.sun.jndi.ldap.connect.pool.maxsize"."3");
env.put("com.sun.jndi.ldap.connect.pool.prefsize"."1");
env.put("com.sun.jndi.ldap.connect.pool.timeout"."300000");
Copy the code

The default rule is that plain (non-SSL) connections that use simple or no authentication are allowed to be pooled

That is, the connection pool may not take effect. In this case, modify the configuration

Com. Sun. Jndi. Ldap. Connect. Pool. Protocol: at the same time allows the use of common connection and SSL connection com., sun. Jndi. Ldap. Connect. Pool. The authentication: (None/Simple/digest-MD5) The anonymous (None), simple, and digest-MD5 authentication types are allowed. You need to configure them

5.5 AD Special Characters

AD can use ASCII to pass in special characters, such as names, but it is important to note that = or similar symbols exist in AD itself. When it is generated, AD automatically adds/escapes, so when we use it, we need to add!!

conclusion

Probably a little fur, because do not want to run virtual machine, a lot of temporarily not recorded, the follow-up if the opportunity will consider to put up (too small, I do not know whether people see)