/*
* Atricore IDBus
*
* Copyright (c) 2009, Atricore Inc.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.atricore.idbus.idojos.ldapidentitystore;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.atricore.idbus.kernel.main.authn.*;
import org.atricore.idbus.kernel.main.store.AbstractStore;
import org.atricore.idbus.kernel.main.store.SimpleUserKey;
import org.atricore.idbus.kernel.main.store.UserKey;
import org.atricore.idbus.kernel.main.store.exceptions.NoSuchUserException;
import org.atricore.idbus.kernel.main.store.exceptions.SSOIdentityException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.*;
/**
* An implementation of an Identity and Credential Store which obtains credential, user and
* role information from an LDAP server using JNDI, based on the configuration properties.
* <p/>
* It allows to set whatever options your LDAP JNDI provider supports your Gateway
* configuration file.
* Examples of standard property names are:
* <ul>
* <li><code>initialContextFactory = "java.naming.factory.initial"</code>
* <li><code>securityProtocol = "java.naming.security.protocol"</code>
* <li><code>providerUrl = "java.naming.provider.url"</code>
* <li><code>securityAuthentication = "java.naming.security.authentication"</code>
* </ul>
* <p/>
* This store implementation is both an Identity Store and Credential Store.
* Since in JOSSO the authentication of the user is left to the configured Authentication Scheme,
* this store implementation cannot delegate user identity assertion by binding to the
* LDAP server. For that reason it retrieves the required credentials from the directory
* leaving the authentication procedure to the configured Authentication Scheme.
* The store must be supplied with the configuratoin parameters so that it can retrieve user
* identity information.
* <p/>
* <p/>
* Additional component properties include:
* <ul>
* <li>securityPrincipal: the DN of the user to be used to bind to the LDAP Server
* <li>securityCredential: the securityPrincipal password to be used for binding to the
* LDAP Server.
* <li>securityAuthentication: the security level to be used with the LDAP Server session.
* Its value is one of the following strings:
* "none", "simple", "strong".
* If not set, "simple" will be used.
* <li>ldapSearchScope : alows control over LDAP search scope : valid values are ONELEVEL, SUBTREE</li>
* <li>usersCtxDN : the fixed distinguished name to the context to search for user accounts.
* <li>principalUidAttributeID: the name of the attribute that contains the user login name.
* This is used to locate the user.
* <li>rolesCtxDN : The fixed distinguished name to the context to search for user roles.
* <li>uidAttributeID: the name of the attribute that, in the object containing the user roles,
* references role members. The attribute value should be the DN of the user associated with the
* role. This is used to locate the user roles.
* <li>roleAttributeID : The name of the attribute that contains the role name
* <li>roleMatchingMOde : The way JOSSO gets users roles, values UDN (default) and UID.
* <li>credentialQueryString : The query string to obtain user credentials. It should have the
* following format : user_attribute_name=credential_attribute_name,...
* For example :
* uid=username,userPassword=password
* <li>userPropertiesQueryString : The query string to obtain user properties. It should have
* the following format : ldap_attribute_name=user_attribute_name,...
* For example :
* mail=mail,cn=description
* </ul>
* A sample LDAP Identity Store configuration :
* <p/>
* <pre>
* <sso-identity-store>
* <class>org.josso.gateway.identity.service.store.ldap.LDAPIdentityStore</class>
* <initialContextFactory>com.sun.jndi.ldap.LdapCtxFactory</initialContextFactory>
* <providerUrl>ldap://localhost</providerUrl>
* <securityPrincipal>cn=Manager\,dc=my-domain\,dc=com</securityPrincipal>
* <securityCredential>secret</securityCredential>
* <securityAuthentication>simple</securityAuthentication>
* <usersCtxDN>ou=People\,dc=my-domain\,dc=com</usersCtxDN>
* <principalUidAttributeID>uid</principalUidAttributeID>
* <rolesCtxDN>ou=Roles\,dc=my-domain\,dc=com</rolesCtxDN>
* <uidAttributeID>uniquemember</uidAttributeID>
* <roleMatchingMode>UDN</roleMatchingMode>
* <roleAttributeID>cn</roleAttributeID>
* <credentialQueryString>uid=username\,userPassword=password</credentialQueryString>
* <userPropertiesQueryString>mail=mail\,cn=description</userPropertiesQueryString>
* <ldapSearchScope>SUBTREE</ldapSearchScope>
* </sso-identity-store>
* </pre>
* <p/>
* A sample LDAP Credential Store configuration :
* <p/>
* <pre>
* <credential-store>
* <class>org.josso.gateway.identity.service.store.ldap.LDAPIdentityStore</class>
* <initialContextFactory>com.sun.jndi.ldap.LdapCtxFactory</initialContextFactory>
* <providerUrl>ldap://localhost</providerUrl>
* <securityPrincipal>cn=Manager\,dc=my-domain\,dc=com</securityPrincipal>
* <securityCredential>secret</securityCredential>
* <securityAuthentication>simple</securityAuthentication>
* <usersCtxDN>ou=People\,dc=my-domain\,dc=com</usersCtxDN>
* <principalUidAttributeID>uid</principalUidAttributeID>
* <rolesCtxDN>ou=Roles\,dc=my-domain\,dc=com</rolesCtxDN>
* <uidAttributeID>uniquemember</uidAttributeID>
* <roleAttributeID>cn</roleAttributeID>
* <credentialQueryString>uid=username\,userPassword=password</credentialQueryString>
* <userPropertiesQueryString>mail=mail\,cn=description</userPropertiesQueryString>
* </credential-store>
* </pre>
*
* @author <a href="mailto:gbrigand@josso.org">Gianluca Brigandi</a>
* @version CVS $Id: LDAPIdentityStore.java 1040 2009-03-05 00:56:52Z gbrigand $
*
* @org.apache.xbean.XBean element="ldap-store"
*/
public class LDAPIdentityStore extends AbstractStore {
private static final Log logger = LogFactory.getLog(LDAPIdentityStore.class);
/**
* Valid userPassword schemes according to RFC 2307
*/
private static final String USERPASSWORD_SCHEME_MD5 = "{md5}";
private static final String USERPASSWORD_SCHEME_CRYPT = "{crypt}";
private static final String USERPASSWORD_SCHEME_SHA = "{sha}";
// ----------------------------------------------------- Instance Variables
private String _initialContextFactory;
private String _providerUrl;
private String _securityAuthentication;
private String _rolesCtxDN;
private String _uidAttributeID;
private String _roleAttributeID;
private String _roleMatchingMode;
private String _securityProtocol;
private String _securityPrincipal;
private String _securityCredential;
private String _principalUidAttributeID;
private String _usersCtxDN;
private String _credentialQueryString;
private String _userPropertiesQueryString;
private String _ldapSearchScope;
private String _updateableCredentialAttribute;
// ----------------------------------------------------- Constructors
public LDAPIdentityStore(){}
// ----------------------------------------------------- IdentityStore Methods
@Override
public boolean userExists(UserKey key) throws SSOIdentityException {
try {
String dn = selectUserDN(((SimpleUserKey) key).getId());
return dn != null;
} catch (NamingException e) {
throw new SSOIdentityException(e);
}
}
/**
* Loads user information and its user attributes from the LDAP server.
*
* @param key the userid value to fetch the user in the LDAP server.
* @return the user instance with the provided userid
* @throws NoSuchUserException if the user does not exist
* @throws SSOIdentityException a fatal exception loading the requested user
*/
public BaseUser loadUser(UserKey key) throws NoSuchUserException, SSOIdentityException {
try {
if (!(key instanceof SimpleUserKey)) {
throw new SSOIdentityException("Unsupported key type : " + key.getClass().getName());
}
String uid = selectUser(((SimpleUserKey) key).getId());
if (uid == null)
throw new NoSuchUserException(key);
BaseUser bu = new BaseUserImpl();
bu.setName(uid);
List userProperties = new ArrayList();
// Optionally find user properties.
if (getUserPropertiesQueryString() != null) {
HashMap userPropertiesResultSet = selectUserProperties(((SimpleUserKey) key).getId());
Iterator i = userPropertiesResultSet.keySet().iterator();
while (i.hasNext()) {
String pName = (String) i.next();
String pValue = (String) userPropertiesResultSet.get(pName);
SSONameValuePair vp = new SSONameValuePair(pName, pValue);
userProperties.add(vp);
}
}
// Store User DN as a SSOUser property.
String dn = selectUserDN(((SimpleUserKey) key).getId());
userProperties.add(new SSONameValuePair("josso.user.dn", dn));
SSONameValuePair[] props = (SSONameValuePair[])
userProperties.toArray(new SSONameValuePair[userProperties.size()]);
bu.setProperties(props);
return bu;
} catch (NamingException e) {
logger.error("NamingException while obtaining user", e);
throw new SSOIdentityException("Error obtaining user : " + key);
}
}
/**
* Retrieves the roles for the supplied user.
*
* @param key the user id of the user for whom role information is to be retrieved.
* @return the roles associated with the supplied user.
* @throws SSOIdentityException fatal exception obtaining user roles.
*/
public BaseRole[] findRolesByUserKey(UserKey key)
throws SSOIdentityException {
try {
if (!(key instanceof SimpleUserKey)) {
throw new SSOIdentityException("Unsupported key type : " + key.getClass().getName());
}
String[] roleNames = selectRolesByUsername(((SimpleUserKey) key).getId());
List roles = new ArrayList();
for (int i = 0; i < roleNames.length; i++) {
String roleName = roleNames[i];
BaseRole role = new BaseRoleImpl();
role.setName(roleName);
roles.add(role);
}
return (BaseRole[]) roles.toArray(new BaseRole[roles.size()]);
} catch (NamingException e) {
logger.error("NamingException while obtaining roles", e);
throw new SSOIdentityException("Error obtaining roles for user : " + key);
}
}
// ----------------------------------------------------- CredentialStore Methods
/**
* Loads user credential information for the supplied user from the LDAP server.
*
* @param key the user id of the user for whom credential information is to be retrieved.
* @return the credentials associated with the supplied user.
* @throws SSOIdentityException fatal exception obtaining user credentials
*/
public Credential[] loadCredentials(CredentialKey key, CredentialProvider cp) throws SSOIdentityException {
try {
if (!(key instanceof CredentialKey)) {
throw new SSOIdentityException("Unsupported key type : " + key.getClass().getName());
}
List credentials = new ArrayList();
HashMap credentialResultSet = selectCredentials(((SimpleUserKey) key).getId());
Iterator i = credentialResultSet.keySet().iterator();
while (i.hasNext()) {
String cName = (String) i.next();
Object cValue = (Object) credentialResultSet.get(cName);
Credential c = cp.newCredential(cName, cValue);
credentials.add(c);
}
return (Credential[]) credentials.toArray(new Credential[credentialResultSet.size()]);
} catch (NamingException e) {
throw new SSOIdentityException("Error obtaining credentials for user : " + key + " ("+e.getMessage()+")", e);
}
}
// ----------------------------------------------------- LDAP Primitives
/**
* Obtains the roles for the given user.
*
* @param username the user name to fetch user data.
* @return the list of roles to which the user is associated to.
* @throws NamingException LDAP error obtaining roles fro the given user
*/
protected String[] selectRolesByUsername(String username) throws NamingException, NoSuchUserException {
List userRoles = new ArrayList();
InitialLdapContext ctx = createLdapInitialContext();
String rolesCtxDN = getRolesCtxDN();
// Search for any roles associated with the user
if (rolesCtxDN != null) {
// The attribute where user DN is stored in roles :
String uidAttributeID = getUidAttributeID();
if (uidAttributeID == null)
uidAttributeID = "uniquemember";
// The attribute that identifies the role name
String roleAttrName = getRoleAttributeID();
if (roleAttrName == null)
roleAttrName = "roles";
String userDN;
if ("UID".equals(getRoleMatchingMode())) {
// Use User ID to match the role
userDN = username;
} else if ("PRINCIPAL".equals(getRoleMatchingMode())) {
// Use User ID to match the role
userDN = _principalUidAttributeID + "=" + username;
} else {
// Default behaviour: Match the role using the User DN, not just the username :
userDN = selectUserDN(username);
}
if (logger.isDebugEnabled())
logger.debug("Searching Roles for user '" + userDN + "' in Uid attribute name '" + uidAttributeID + "'");
if (userDN ==null)
throw new NoSuchUserException(username);
try {
if (userDN.contains("\\")) {
logger.debug("Escaping '\\' character");
userDN = userDN.replace("\\", "\\\\\\");
}
NamingEnumeration answer = ctx.search(rolesCtxDN, "(&(" + uidAttributeID + "=" + userDN + "))", getSearchControls());
if (logger.isDebugEnabled())
logger.debug("Search Name: " + rolesCtxDN);
if (logger.isDebugEnabled())
logger.debug("Search Filter: (&(" + uidAttributeID + "=" + userDN + "))");
if (!answer.hasMore())
logger.info("No roles found for user " + username);
while (answer.hasMore()) {
SearchResult sr = (SearchResult) answer.next();
Attributes attrs = sr.getAttributes();
Attribute roles = attrs.get(roleAttrName);
for (int r = 0; r < roles.size(); r++) {
Object value = roles.get(r);
String roleName = null;
// The role attribute value is the role name
roleName = value.toString();
if (roleName != null) {
if (logger.isDebugEnabled())
logger.debug("Saving role '" + roleName + "' for user '" + username + "'");
userRoles.add(roleName);
}
}
}
} catch (NamingException e) {
if (logger.isDebugEnabled())
logger.debug("Failed to locate roles", e);
}
}
// Close the context to release the connection
ctx.close();
return (String[]) userRoles.toArray(new String[userRoles.size()]);
}
/**
* Fetches the supplied user DN.
*
* @param uid the user id
* @return the user DN for the supplied uid
* @throws NamingException LDAP error obtaining user information.
*/
protected String selectUserDN(String uid) throws NamingException {
String dn = null;
InitialLdapContext ctx = createLdapInitialContext();
try {
dn = selectUserDN(ctx, uid);
} finally {
// Close the context to release the connection
ctx.close();
}
return dn;
}
/**
* Fetches the supplied user DN.
*
* @param uid the user id
* @return the user DN for the supplied uid
* @throws NamingException LDAP error obtaining user information.
*/
protected String selectUserDN(InitialLdapContext ctx, String uid) throws NamingException {
String dn = null;
String principalUidAttrName = this.getPrincipalUidAttributeID();
String usersCtxDN = this.getUsersCtxDN();
try {
// NamingEnumeration answer = ctx.search(usersCtxDN, matchAttrs, principalAttr);
// This gives more control over search behavior :
NamingEnumeration answer = ctx.search(usersCtxDN, "(&(" + principalUidAttrName + "=" + uid + "))", getSearchControls());
while (answer.hasMore()) {
SearchResult sr = (SearchResult) answer.next();
Attributes attrs = sr.getAttributes();
Attribute uidAttr = attrs.get(principalUidAttrName);
if (uidAttr == null) {
logger.warn("Invalid user uid attribute '" + principalUidAttrName + "'");
continue;
}
String uidValue = uidAttr.get().toString();
if (uidValue != null) {
dn = sr.getName() + "," + usersCtxDN;
if (logger.isDebugEnabled())
logger.debug("Found user '" + principalUidAttrName + "=" + uidValue + "' for user '" + uid + "' DN=" + dn);
} else {
if (logger.isDebugEnabled())
logger.debug("User not found for user '" + uid + "'");
}
}
} catch (NamingException e) {
if (logger.isDebugEnabled())
logger.debug("Failed to locate user", e);
}
return dn;
}
protected String selectUser(String uid) throws NamingException {
return selectUser( this.getPrincipalUidAttributeID(), uid );
}
/**
* Fetches the supplied user.
*
* @param attrValue the user id
* @return the user id for the supplied uid
* @throws NamingException LDAP error obtaining user information.
*/
protected String selectUser(String attrId, String attrValue ) throws NamingException {
String uidValue = null;
InitialLdapContext ctx = createLdapInitialContext();
String uidAttrName = this.getPrincipalUidAttributeID();
String usersCtxDN = this.getUsersCtxDN();
try {
// NamingEnumeration answer = ctx.search(usersCtxDN, matchAttrs, principalAttr);
// This gives more control over search behavior :
NamingEnumeration answer = ctx.search(usersCtxDN, "(&(" + attrId + "=" + attrValue + "))", getSearchControls());
while (answer.hasMore()) {
SearchResult sr = (SearchResult) answer.next();
Attributes attrs = sr.getAttributes();
Attribute uidAttr = attrs.get( uidAttrName );
if (uidAttr == null) {
logger.warn("Invalid user attrValue attribute '" + uidAttrName + "'");
continue;
}
uidValue = uidAttr.get().toString();
if (uidValue != null) {
if (logger.isDebugEnabled())
logger.debug("Found user '" + uidAttrName + "=" + uidValue + "' for user '" + attrValue + "'");
} else {
if (logger.isDebugEnabled())
logger.debug("User not found for user '" + attrValue + "'");
}
}
} catch (NamingException e) {
if (logger.isDebugEnabled())
logger.debug("Failed to locate user", e);
} finally {
// Close the context to release the connection
ctx.close();
}
return uidValue;
}
/**
* Fetch the Ldap user attributes to be used as credentials.
*
* @param uid the user id for whom credentials are required
* @return the hash map containing user credentials as name/value pairs
* @throws NamingException LDAP error obtaining user credentials.
*/
protected HashMap selectCredentials(String uid) throws NamingException {
HashMap credentialResultSet = new HashMap();
InitialLdapContext ctx = createLdapInitialContext();
String principalUidAttrName = this.getPrincipalUidAttributeID();
String usersCtxDN = this.getUsersCtxDN();
// BasicAttributes matchAttrs = new BasicAttributes(true);
// matchAttrs.put(principalUidAttrName, uid);
String credentialQueryString = getCredentialQueryString();
HashMap credentialQueryMap = parseQueryString(credentialQueryString);
Iterator i = credentialQueryMap.keySet().iterator();
List credentialAttrList = new ArrayList();
while (i.hasNext()) {
String o = (String) i.next();
credentialAttrList.add(o);
}
String[] credentialAttr = (String[]) credentialAttrList.toArray(new String[credentialAttrList.size()]);
try {
// NamingEnumeration answer = ctx.search(usersCtxDN, matchAttrs, credentialAttr);
// This gives more control over search behavior :
NamingEnumeration answer = ctx.search(usersCtxDN, "(&(" + principalUidAttrName + "=" + uid + "))", getSearchControls());
while (answer.hasMore()) {
SearchResult sr = (SearchResult) answer.next();
Attributes attrs = sr.getAttributes();
for (int j = 0; j < credentialAttr.length; j++) {
Object credentialObject = attrs.get(credentialAttr[j]).get();
String credentialName = (String) credentialQueryMap.get(credentialAttr[j]);
String credentialValue = null;
if (logger.isDebugEnabled())
logger.debug("Found user credential '" + credentialName + "' of type '" + credentialObject.getClass().getName() + "" +
(credentialObject.getClass().isArray() ? "[" + Array.getLength(credentialObject) + "]" : "") + "'");
// if the attribute value is an array, cast it to byte[] and then convert to
// String using proper encoding
if (credentialObject.getClass().isArray()) {
try {
// Try to create a UTF-8 String, we use java.nio to handle errors in a better way.
// If the byte[] cannot be converted to UTF-8, we're using the credentialObject as is.
byte[] credentialData = (byte[]) credentialObject;
ByteBuffer in = ByteBuffer.allocate(credentialData.length);
in.put(credentialData);
in.flip();
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode(in);
credentialValue = charBuffer.toString();
} catch (CharacterCodingException e) {
if (logger.isDebugEnabled())
logger.debug("Can't convert credential value to String using UTF-8");
}
} else if (credentialObject instanceof String) {
// The credential value must be a String ...
credentialValue = (String) credentialObject;
}
// Check what do we have ...
if (credentialValue != null) {
// Remove any schema information from the credential value, like the {md5} prefix for passwords.
credentialValue = getSchemeFreeValue(credentialValue);
credentialResultSet.put(credentialName, credentialValue);
} else {
// We have a binary credential, leave it as it is ... probably binary value.
credentialResultSet.put(credentialName, credentialObject);
}
if (logger.isDebugEnabled())
logger.debug("Found user credential '" + credentialName + "' with value '" + (credentialValue != null ?
credentialValue : credentialObject) + "'");
}
}
} catch (NamingException e) {
if (logger.isDebugEnabled())
logger.debug("Failed to locate user", e);
} finally {
// Close the context to release the connection
ctx.close();
}
return credentialResultSet;
}
/**
* Obtain the properties for the user associated with the given uid using the
* configured user properties query string.
*
* @param uid the user id of the user for whom its user properties are required.
* @return the hash map containing user properties as name/value pairs.
* @throws NamingException LDAP error obtaining user properties.
*/
protected HashMap selectUserProperties(String uid) throws NamingException {
HashMap userPropertiesResultSet = new HashMap();
InitialLdapContext ctx = createLdapInitialContext();
BasicAttributes matchAttrs = new BasicAttributes(true);
String principalUidAttrName = this.getPrincipalUidAttributeID();
String usersCtxDN = this.getUsersCtxDN();
matchAttrs.put(principalUidAttrName, uid);
String userPropertiesQueryString = getUserPropertiesQueryString();
HashMap userPropertiesQueryMap = parseQueryString(userPropertiesQueryString);
Iterator i = userPropertiesQueryMap.keySet().iterator();
List propertiesAttrList = new ArrayList();
while (i.hasNext()) {
String o = (String) i.next();
propertiesAttrList.add(o);
}
String[] propertiesAttr = (String[]) propertiesAttrList.toArray(
new String[propertiesAttrList.size()]
);
try {
// This gives more control over search behavior :
NamingEnumeration answer = ctx.search(usersCtxDN, "(&(" + principalUidAttrName + "=" + uid + "))", getSearchControls());
while (answer.hasMore()) {
SearchResult sr = (SearchResult) answer.next();
Attributes attrs = sr.getAttributes();
for (int j = 0; j < propertiesAttr.length; j++) {
Attribute attribute = attrs.get(propertiesAttr[j]);
if (attribute == null) {
logger.warn("Invalid user property attribute '" + propertiesAttr[j] + "'");
continue;
}
Object propertyObject = attrs.get(propertiesAttr[j]).get();
if (propertyObject == null) {
logger.warn("Found a 'null' value for user property '" + propertiesAttr[j] + "'");
continue;
}
String propertyValue = propertyObject.toString();
String propertyName = (String) userPropertiesQueryMap.get(propertiesAttr[j]);
userPropertiesResultSet.put(propertyName, propertyValue);
if (logger.isDebugEnabled())
logger.debug("Found user property '" + propertyName + "' with value '" + propertyValue + "'");
}
}
} catch (NamingException e) {
if (logger.isDebugEnabled())
logger.debug("Failed to locate user", e);
} finally {
// Close the context to release the connection
ctx.close();
}
return userPropertiesResultSet;
}
protected void replaceAttributes(String bane, Attributes atts) throws NamingException {
InitialLdapContext ctx = this.createLdapInitialContext( );
ctx.modifyAttributes( bane, InitialLdapContext.REPLACE_ATTRIBUTE, atts );
}
/**
* Creates an InitialLdapContext by logging into the configured Ldap Server using the configured
* username and credential.
*
* @return the Initial Ldap Context to be used to perform searches, etc.
* @throws NamingException LDAP binding error.
*/
protected InitialLdapContext createLdapInitialContext() throws NamingException {
String securityPrincipal = getSecurityPrincipal();
if (securityPrincipal == null)
securityPrincipal = "";
String securityCredential = getSecurityCredential();
if (securityCredential == null)
securityCredential = "";
return createLdapInitialContext(securityPrincipal, securityCredential);
}
/**
* Creates an InitialLdapContext by logging into the configured Ldap Server using the provided
* username and credential.
*
* @return the Initial Ldap Context to be used to perform searches, etc.
* @throws NamingException LDAP binding error.
*/
protected InitialLdapContext createLdapInitialContext(String securityPrincipal, String securityCredential) throws NamingException {
Properties env = new Properties();
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, getInitialContextFactory());
env.setProperty(Context.SECURITY_AUTHENTICATION, getSecurityAuthentication());
env.setProperty(Context.PROVIDER_URL, getProviderUrl());
env.setProperty(Context.SECURITY_PROTOCOL, (getSecurityProtocol() == null ? "" : getSecurityProtocol()));
// Set defaults for key values if they are missing
String factoryName = env.getProperty(Context.INITIAL_CONTEXT_FACTORY);
if (factoryName == null) {
factoryName = "com.sun.jndi.ldap.LdapCtxFactory";
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryName);
}
String authType = env.getProperty(Context.SECURITY_AUTHENTICATION);
if (authType == null)
env.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
String protocol = env.getProperty(Context.SECURITY_PROTOCOL);
String providerURL = getProviderUrl();
// Use localhost if providerUrl not set
if (providerURL == null) {
providerURL = "ldap://localhost:" + ((protocol != null && protocol.equals("ssl")) ? "636" : "389");
} else {
// In case user configured provided URL
if (providerURL.startsWith("ldaps")) {
protocol = "ssl";
env.setProperty(Context.SECURITY_PROTOCOL, "ssl");
}
}
env.setProperty(Context.PROVIDER_URL, providerURL);
if (securityPrincipal != null && !"".equals(securityPrincipal))
env.setProperty(Context.SECURITY_PRINCIPAL, securityPrincipal);
if (securityCredential != null && !"".equals(securityCredential))
env.put(Context.SECURITY_CREDENTIALS, securityCredential);
// always follow referrals transparently
env.put(Context.REFERRAL, "follow");
// Logon into LDAP server
if (logger.isDebugEnabled())
logger.debug("Logging into LDAP server, env=" + env);
InitialLdapContext ctx = new InitialLdapContext(env, null);
if (logger.isDebugEnabled())
logger.debug("Logged into LDAP server, " + ctx);
return ctx;
}
/**
* Returns the supplied attribute value without the scheme prefix.
* This method should be invoked for 'userPassword' type attributes.
*
* @param attributeValue the attribute value
* @return the scheme
*/
protected String getSchemeFreeValue(String attributeValue) {
String targetValue = attributeValue;
if (attributeValue.toLowerCase().startsWith(LDAPIdentityStore.USERPASSWORD_SCHEME_CRYPT)) {
targetValue = attributeValue.substring(USERPASSWORD_SCHEME_CRYPT.length());
} else if (attributeValue.toLowerCase().startsWith(LDAPIdentityStore.USERPASSWORD_SCHEME_MD5)) {
targetValue = attributeValue.substring(USERPASSWORD_SCHEME_MD5.length());
} else if (attributeValue.toLowerCase().startsWith(LDAPIdentityStore.USERPASSWORD_SCHEME_SHA)) {
targetValue = attributeValue.substring(USERPASSWORD_SCHEME_SHA.length());
}
return targetValue;
}
// ----------------------------------------------------- Utils
/**
* Parses a credential query string and builds a HashMap object
* with key-value pairs.
* The query string should be in the form of a string
* and should have key-value pairs in the form <i>key=value</i>,
* with each pair separated from the next by a ',' character.
*
* @param s a string containing the query to be parsed
* @return a HashMap object built from the parsed key-value pairs
* @throws IllegalArgumentException if the query string
* is invalid
*/
protected HashMap parseQueryString(String s) {
if (s == null) {
throw new IllegalArgumentException();
}
HashMap hm = new HashMap();
StringTokenizer st = new StringTokenizer(s, ",");
while (st.hasMoreTokens()) {
String pair = (String) st.nextToken();
int pos = pair.indexOf('=');
if (pos == -1) {
// XXX
// should give more detail about the illegal argument
throw new IllegalArgumentException();
}
String key = pair.substring(0, pos);
String val = pair.substring(pos + 1, pair.length());
hm.put(key, val);
}
return hm;
}
/**
* This method returns the proper search controls to be used when querying the LDAP..
*/
protected SearchControls getSearchControls() {
SearchControls sc = new SearchControls();
sc.setSearchScope(_ldapSearchScope == null || _ldapSearchScope.equalsIgnoreCase("ONELEVEL") ?
SearchControls.ONELEVEL_SCOPE : SearchControls.SUBTREE_SCOPE);
return sc;
}
/**
* Configuration Properties
*/
// ----------------------------------------------------- Configuration Properties
public void setInitialContextFactory(String initialContextFactory) {
_initialContextFactory = initialContextFactory;
}
public String getInitialContextFactory() {
return _initialContextFactory;
}
public void setProviderUrl(String providerUrl) {
_providerUrl = providerUrl;
}
public String getProviderUrl() {
return _providerUrl;
}
public void setSecurityAuthentication(String securityAuthentication) {
_securityAuthentication = securityAuthentication;
}
public String getSecurityAuthentication() {
return _securityAuthentication;
}
public void setSecurityProtocol(String securityProtocol) {
_securityProtocol = securityProtocol;
}
public String getSecurityProtocol() {
return _securityProtocol;
}
public void setSecurityPrincipal(String securityPrincipal) {
_securityPrincipal = securityPrincipal;
}
public String getSecurityPrincipal() {
return _securityPrincipal;
}
public void setSecurityCredential(String securityCredential) {
_securityCredential = securityCredential;
}
protected String getSecurityCredential() {
return _securityCredential;
}
public String getLdapSearchScope() {
return _ldapSearchScope;
}
public void setLdapSearchScope(String ldapSearchScope) {
_ldapSearchScope = ldapSearchScope;
}
public void setUsersCtxDN(String usersCtxDN) {
_usersCtxDN = usersCtxDN;
}
public String getUsersCtxDN() {
return _usersCtxDN;
}
public void setRolesCtxDN(String rolesCtxDN) {
_rolesCtxDN = rolesCtxDN;
}
public String getRolesCtxDN() {
return _rolesCtxDN;
}
public void setPrincipalUidAttributeID(String principalUidAttributeID) {
_principalUidAttributeID = principalUidAttributeID;
}
public String getPrincipalUidAttributeID() {
return _principalUidAttributeID;
}
public void setUidAttributeID(String uidAttributeID) {
_uidAttributeID = uidAttributeID;
}
public String getRoleMatchingMode() {
return _roleMatchingMode;
}
public void setRoleMatchingMode(String roleMatchingMode) {
this._roleMatchingMode = roleMatchingMode;
}
public String getUidAttributeID() {
return _uidAttributeID;
}
public void setRoleAttributeID(String roleAttributeID) {
_roleAttributeID = roleAttributeID;
}
public String getRoleAttributeID() {
return _roleAttributeID;
}
public void setCredentialQueryString(String credentialQueryString) {
_credentialQueryString = credentialQueryString;
}
public String getCredentialQueryString() {
return _credentialQueryString;
}
public void setUserPropertiesQueryString(String userPropertiesQueryString) {
_userPropertiesQueryString = userPropertiesQueryString;
}
public String getUserPropertiesQueryString() {
return _userPropertiesQueryString;
}
public String getUpdateableCredentialAttribute () {
return _updateableCredentialAttribute;
}
public void setUpdateableCredentialAttribute ( String updateableCredentialAttribute ) {
this._updateableCredentialAttribute = updateableCredentialAttribute;
}
}