[jboss-cvs] JBossAS SVN: r76135 - projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Wed Jul 23 10:33:04 EDT 2008
Author: darran.lofthouse at jboss.com
Date: 2008-07-23 10:33:04 -0400 (Wed, 23 Jul 2008)
New Revision: 76135
Removed:
projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/LdapExtLoginModule.java
Log:
[SECURITY-133] Remove branched login module as now using a new implementation.
Deleted: projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/LdapExtLoginModule.java
===================================================================
--- projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/LdapExtLoginModule.java 2008-07-23 14:24:11 UTC (rev 76134)
+++ projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/LdapExtLoginModule.java 2008-07-23 14:33:04 UTC (rev 76135)
@@ -1,574 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2006, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.security.negotiation.prototype;
-
-import java.security.Principal;
-import java.security.acl.Group;
-import java.util.Iterator;
-import java.util.Properties;
-import java.util.Map.Entry;
-
-import javax.management.ObjectName;
-import javax.naming.Context;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-import javax.naming.ldap.InitialLdapContext;
-import javax.security.auth.login.LoginException;
-
-import org.jboss.security.SimpleGroup;
-import org.jboss.security.auth.spi.UsernamePasswordLoginModule;
-
-/**
- The org.jboss.security.auth.spi.LdapExtLoginModule, added in jboss-4.0.3, is an
- alternate ldap login module implementation that uses searches for locating both
- the user to bind as for authentication as well as the associated roles. The
- roles query will recursively follow distinguished names (DNs) to navigate a
- hierarchical role structure.
-
- The LoginModule options include whatever options your LDAP JNDI provider
- supports. Examples of standard property names are:
-
- * Context.INITIAL_CONTEXT_FACTORY = "java.naming.factory.initial"
- * Context.SECURITY_PROTOCOL = "java.naming.security.protocol"
- * Context.PROVIDER_URL = "java.naming.provider.url"
- * Context.SECURITY_AUTHENTICATION = "java.naming.security.authentication"
-
- The authentication happens in 2 steps:
- # An initial bind to the ldap server is done using the __bindDN__ and
- __bindCredential__ options. The __bindDN__ is some user with the ability to
- search both the __baseDN__ and __rolesCtxDN__ trees for the user and roles. The
- user DN to authenticate against is queried using the filter specified by the
- __baseFilter__ attribute (see the __baseFilter__ option description for its
- syntax).
- # The resulting user DN is then authenticated by binding to ldap server using
- the user DN as the InitialLdapContext environment Context.SECURITY_PRINCIPAL.
-
- The Context.SECURITY_CREDENTIALS property is either set to the String password
- obtained by the callback handler.
-
- If this is successful, the associated user roles are queried using the
- __rolesCtxDN__, __roleAttributeID__, __roleAttributeIsDN__,
- __roleNameAttributeID__, and __roleFilter__ options.
-
- The full odule properties include:
- * __baseCtxDN__ : The fixed DN of the context to start the user search from.
- * __bindDN__ : The DN used to bind against the ldap server for the user and
- roles queries. This is some DN with read/search permissions on the baseCtxDN and
- rolesCtxDN values.
- * __bindCredential__ : The password for the bindDN. This can be encrypted if the
- jaasSecurityDomain is specified.
- * __jaasSecurityDomain__ : The JMX ObjectName of the JaasSecurityDomain to use
- to decrypt the java.naming.security.principal. The encrypted form of the
- password is that returned by the JaasSecurityDomain#encrypt64(byte[]) method.
- The org.jboss.security.plugins.PBEUtils can also be used to generate the
- encrypted form.
- * __baseFilter__ : A search filter used to locate the context of the user to
- authenticate. The input username/userDN as obtained from the login module
- callback will be substituted into the filter anywhere a "{0}" expression is
- seen. This substituion behavior comes from the standard
- __DirContext.search(Name, String, Object[], SearchControls cons)__ method. An
- common example search filter is "(uid={0})".
- * __rolesCtxDN__ : The fixed DN of the context to search for user roles.
- Consider that this is not the Distinguished Name of where the actual roles are;
- rather, this is the DN of where the objects containing the user roles are (e.g.
- for active directory, this is the DN where the user account is)
- * __roleFilter__ : A search filter used to locate the roles associated with the
- authenticated user. The input username/userDN as obtained from the login module
- callback will be substituted into the filter anywhere a "{0}" expression is
- seen. The authenticated userDN will be substituted into the filter anywhere a
- "{1}" is seen. An example search filter that matches on the input username is:
- "(member={0})". An alternative that matches on the authenticated userDN is:
- "(member={1})".
- * __roleAttributeIsDN__ : A flag indicating whether the user's role attribute
- contains the fully distinguished name of a role object, or the users's role
- attribute contains the role name. If false, the role name is taken from the
- value of the user's role attribute. If true, the role attribute represents the
- distinguished name of a role object. The role name is taken from the value of
- the roleNameAttributeId` attribute of the corresponding object. In certain
- directory schemas (e.g., Microsoft Active Directory), role (group)attributes in
- the user object are stored as DNs to role objects instead of as simple names, in
- which case, this property should be set to true. The default value of this
- property is false.
- * __roleNameAttributeID__ : The name of the attribute of the role object which
- corresponds to the name of the role. If the __roleAttributeIsDN__ property is
- set to true, this property is used to find the role object's name attribute. If
- the __roleAttributeIsDN__ property is set to false, this property is ignored.
- * __roleRecursion__ : How deep the role search will go below a given matching
- context. Disable with 0, which is the default.
- * __searchTimeLimit__ : The timeout in milliseconds for the user/role searches.
- Defaults to 10000 (10 seconds).
- * __searchScope__ : Sets the search scope to one of the strings. The default is
- SUBTREE_SCOPE.
- ** OBJECT_SCOPE : only search the named roles context.
- ** ONELEVEL_SCOPE : search directly under the named roles context.
- ** SUBTREE_SCOPE : If the roles context is not a DirContext, search only the
- object. If the roles context is a DirContext, search the subtree rooted at the
- named object, including the named object itself
- * __allowEmptyPasswords__ : A flag indicating if empty(length==0) passwords
- should be passed to the ldap server. An empty password is treated as an
- anonymous login by some ldap servers and this may not be a desirable feature.
- Set this to false to reject empty passwords, true to have the ldap server
- validate the empty password. The default is true.
-
- @author Andy Oliver
- @author Scott.Stark at jboss.org
- @version $Revision$ */
-public class LdapExtLoginModule extends UsernamePasswordLoginModule
-{
- private static final String ROLES_CTX_DN_OPT = "rolesCtxDN";
- private static final String ROLE_ATTRIBUTE_ID_OPT = "roleAttributeID";
- private static final String ROLE_ATTRIBUTE_IS_DN_OPT = "roleAttributeIsDN";
- private static final String ROLE_NAME_ATTRIBUTE_ID_OPT = "roleNameAttributeID";
-
- private static final String BIND_DN = "bindDN";
- private static final String BIND_CREDENTIAL = "bindCredential";
- private static final String BASE_CTX_DN = "baseCtxDN";
- private static final String BASE_FILTER_OPT = "baseFilter";
- private static final String ROLE_FILTER_OPT = "roleFilter";
- private static final String ROLE_RECURSION = "roleRecursion";
- private static final String DEFAULT_ROLE = "defaultRole";
- private static final String SEARCH_TIME_LIMIT_OPT = "searchTimeLimit";
- private static final String SEARCH_SCOPE_OPT = "searchScope";
- private static final String SECURITY_DOMAIN_OPT = "jaasSecurityDomain";
-
- protected String bindDN;
- protected String bindCredential;
- protected String baseDN;
- protected String baseFilter;
- protected String rolesCtxDN;
- protected String roleFilter;
- protected String roleAttributeID;
- protected String roleNameAttributeID;
- protected boolean roleAttributeIsDN;
- protected int recursion = 0;
- protected int searchTimeLimit = 10000;
- protected int searchScope = SearchControls.SUBTREE_SCOPE;
- protected boolean trace;
-
- public LdapExtLoginModule()
- {
- }
-
- private transient SimpleGroup userRoles = new SimpleGroup("Roles");
-
- /**
- Overriden to return an empty password string as typically one cannot obtain a
- user's password. We also override the validatePassword so this is ok.
- @return and empty password String
- */
- protected String getUsersPassword() throws LoginException
- {
- return "";
- }
-
- /**
- Overriden by subclasses to return the Groups that correspond to the to the
- role sets assigned to the user. Subclasses should create at least a Group
- named "Roles" that contains the roles assigned to the user. A second common
- group is "CallerPrincipal" that provides the application identity of the user
- rather than the security domain identity.
- @return Group[] containing the sets of roles
- */
- protected Group[] getRoleSets() throws LoginException
- {
- Group[] roleSets = {userRoles};
- return roleSets;
- }
-
- /**
- Validate the inputPassword by creating a ldap InitialContext with the
- SECURITY_CREDENTIALS set to the password.
- @param inputPassword the password to validate.
- @param expectedPassword ignored
- */
- protected boolean validatePassword(String inputPassword, String expectedPassword)
- {
- boolean isValid = false;
- if (inputPassword != null)
- {
- // See if this is an empty password that should be disallowed
- if (inputPassword.length() == 0)
- {
- // Check for an allowEmptyPasswords option
- boolean allowEmptyPasswords = true;
- String flag = (String) options.get("allowEmptyPasswords");
- if (flag != null)
- allowEmptyPasswords = Boolean.valueOf(flag).booleanValue();
- if (allowEmptyPasswords == false)
- {
- log.trace("Rejecting empty password due to allowEmptyPasswords");
- return false;
- }
- }
-
- try
- {
- // Validate the password by trying to create an initial context
- String username = getUsername();
- isValid = createLdapInitContext(username, inputPassword);
- defaultRole();
- isValid = true;
- }
- catch (Throwable e)
- {
- super.setValidateError(e);
- }
- }
- return isValid;
- }
-
- /**
- @todo move to a generic role mapping function at the base login module
- */
- private void defaultRole()
- {
- try
- {
- String defaultRole = (String) options.get(DEFAULT_ROLE);
- if (defaultRole == null || defaultRole.equals(""))
- {
- return;
- }
- Principal p = super.createIdentity(defaultRole);
- log.trace("Assign user to role " + defaultRole);
- userRoles.addMember(p);
- }
- catch (Exception e)
- {
- super.log.debug("could not add default role to user", e);
- }
- }
-
- /**
- Bind to the ldap server for authentication.
-
- @param username
- @param credential
- @return true if the bind for authentication succeeded
- @throws NamingException
- */
- private boolean createLdapInitContext(String username, Object credential)
- throws Exception
- {
- bindDN = (String) options.get(BIND_DN);
- bindCredential = (String) options.get(BIND_CREDENTIAL);
- String securityDomain = (String) options.get(SECURITY_DOMAIN_OPT);
- if (securityDomain != null)
- {
- ObjectName serviceName = new ObjectName(securityDomain);
- char[] tmp = DecodeAction.decode(bindCredential, serviceName);
- bindCredential = new String(tmp);
- }
-
- baseDN = (String) options.get(BASE_CTX_DN);
- baseFilter = (String) options.get(BASE_FILTER_OPT);
- roleFilter = (String) options.get(ROLE_FILTER_OPT);
- roleAttributeID = (String) options.get(ROLE_ATTRIBUTE_ID_OPT);
- if (roleAttributeID == null)
- roleAttributeID = "role";
- // Is user's role attribute a DN or the role name
- String roleAttributeIsDNOption = (String) options.get(ROLE_ATTRIBUTE_IS_DN_OPT);
- roleAttributeIsDN = Boolean.valueOf(roleAttributeIsDNOption).booleanValue();
- roleNameAttributeID = (String) options.get(ROLE_NAME_ATTRIBUTE_ID_OPT);
- if (roleNameAttributeID == null)
- roleNameAttributeID = "name";
- rolesCtxDN = (String) options.get(ROLES_CTX_DN_OPT);
- String strRecursion = (String) options.get(ROLE_RECURSION);
- try
- {
- recursion = Integer.parseInt(strRecursion);
- }
- catch (Exception e)
- {
- if (trace)
- log.trace("Failed to parse: " + strRecursion + ", disabling recursion");
- // its okay for this to be 0 as this just disables recursion
- recursion = 0;
- }
- String timeLimit = (String) options.get(SEARCH_TIME_LIMIT_OPT);
- if (timeLimit != null)
- {
- try
- {
- searchTimeLimit = Integer.parseInt(timeLimit);
- }
- catch (NumberFormatException e)
- {
- if (trace)
- log.trace("Failed to parse: " + timeLimit + ", using searchTimeLimit=" + searchTimeLimit);
- }
- }
- String scope = (String) options.get(SEARCH_SCOPE_OPT);
- if ("OBJECT_SCOPE".equalsIgnoreCase(scope))
- searchScope = SearchControls.OBJECT_SCOPE;
- else if ("ONELEVEL_SCOPE".equalsIgnoreCase(scope))
- searchScope = SearchControls.ONELEVEL_SCOPE;
- if ("SUBTREE_SCOPE".equalsIgnoreCase(scope))
- searchScope = SearchControls.SUBTREE_SCOPE;
-
- // Get the admin context for searching
- InitialLdapContext ctx = null;
- try
- {
- ctx = constructInitialLdapContext(bindDN, bindCredential);
- // Validate the user by binding against the userDN
- String userDN = bindDNAuthentication(ctx, username, credential, baseDN, baseFilter);
-
- // Query for roles matching the role filter
- SearchControls constraints = new SearchControls();
- constraints.setSearchScope(searchScope);
- constraints.setReturningAttributes(new String[0]);
- constraints.setTimeLimit(searchTimeLimit);
- rolesSearch(ctx, constraints, username, userDN, recursion, 0);
- }
- finally
- {
- if( ctx != null )
- ctx.close();
- }
- return true;
- }
-
- /**
- @param ctx - the context to search from
- @param user - the input username
- @param credential - the bind credential
- @param baseDN - base DN to search the ctx from
- @param filter - the search filter string
- @return the userDN string for the successful authentication
- @throws NamingException
- */
- protected String bindDNAuthentication(InitialLdapContext ctx,
- String user, Object credential, String baseDN, String filter)
- throws NamingException
- {
- SearchControls constraints = new SearchControls();
- constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
- constraints.setReturningAttributes(new String[0]);
- constraints.setTimeLimit(searchTimeLimit);
-
- NamingEnumeration results = null;
-
-
- Object[] filterArgs = {user};
- results = ctx.search(baseDN, filter, filterArgs, constraints);
- if (results.hasMore() == false)
- {
- results.close();
- throw new NamingException("Search of baseDN(" + baseDN + ") found no matches");
- }
-
- SearchResult sr = (SearchResult) results.next();
- String name = sr.getName();
- String userDN = null;
- if (sr.isRelative() == true)
- userDN = name + "," + baseDN;
- else
- throw new NamingException("Can't follow referal for authentication: " + name);
-
- results.close();
- results = null;
- // Bind as the user dn to authenticate the user
- InitialLdapContext userCtx = constructInitialLdapContext(userDN, credential);
- userCtx.close();
-
- return userDN;
- }
-
- /**
- @param ctx
- @param constraints
- @param user
- @param userDN
- @param recursionMax
- @param nesting
- @throws NamingException
- */
- protected void rolesSearch(InitialLdapContext ctx, SearchControls constraints,
- String user, String userDN, int recursionMax, int nesting)
- throws NamingException
- {
- Object[] filterArgs = {user, userDN};
- NamingEnumeration results = ctx.search(rolesCtxDN, roleFilter, filterArgs, constraints);
- try
- {
- while (results.hasMore())
- {
- SearchResult sr = (SearchResult) results.next();
- String dn = canonicalize(sr.getName());
- if( nesting == 0 && roleAttributeIsDN && roleNameAttributeID != null )
- {
- // Check the top context for role names
- String[] attrNames = {roleNameAttributeID};
- Attributes result2 = ctx.getAttributes(dn, attrNames);
- Attribute roles2 = result2.get(roleNameAttributeID);
- if( roles2 != null )
- {
- for(int m = 0; m < roles2.size(); m ++)
- {
- String roleName = (String) roles2.get(m);
- addRole(roleName);
- }
- }
- }
-
- // Query the context for the roleDN values
- String[] attrNames = {roleAttributeID};
- Attributes result = ctx.getAttributes(dn, attrNames);
- if( result != null && result.size() > 0 )
- {
- Attribute roles = result.get(roleAttributeID);
- for (int n = 0; n < roles.size(); n ++)
- {
- String roleName = (String) roles.get(n);
- if (roleAttributeIsDN)
- {
- // Query the roleDN location for the value of roleNameAttributeID
- String roleDN = roleName;
- String[] returnAttribute = {roleNameAttributeID};
- log.trace("Using roleDN: " + roleDN);
- try
- {
- Attributes result2 = ctx.getAttributes(roleDN, returnAttribute);
- Attribute roles2 = result2.get(roleNameAttributeID);
- if( roles2 != null )
- {
- for(int m = 0; m < roles2.size(); m ++)
- {
- roleName = (String) roles2.get(m);
- addRole(roleName);
- }
- }
- }
- catch (NamingException e)
- {
- log.trace("Failed to query roleNameAttrName", e);
- }
- }
- else
- {
- // The role attribute value is the role name
- addRole(roleName);
- }
- }
- }
-
- if (nesting < recursionMax)
- {
- rolesSearch(ctx, constraints, user, dn,
- recursionMax, nesting + 1);
- }
- }
- }
- finally
- {
- if( results != null )
- results.close();
- }
-
- }
-
- private InitialLdapContext constructInitialLdapContext(String dn, Object credential) throws NamingException
- {
- Properties env = new Properties();
- Iterator iter = options.entrySet().iterator();
- while (iter.hasNext())
- {
- Entry entry = (Entry) iter.next();
- env.put(entry.getKey(), entry.getValue());
- }
-
- // 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 = (String) options.get(Context.PROVIDER_URL);
- if (providerURL == null)
- providerURL = "ldap://localhost:" + ((protocol != null && protocol.equals("ssl")) ? "636" : "389");
-
- env.setProperty(Context.PROVIDER_URL, providerURL);
- // JBAS-3555, allow anonymous login with no bindDN and bindCredential
- if (dn != null)
- env.setProperty(Context.SECURITY_PRINCIPAL, dn);
- if (credential != null)
- env.put(Context.SECURITY_CREDENTIALS, credential);
- traceLdapEnv(env);
- return new InitialLdapContext(env, null);
- }
-
- private void traceLdapEnv(Properties env)
- {
- if(trace)
- {
- Properties tmp = new Properties();
- tmp.putAll(env);
- tmp.setProperty(Context.SECURITY_CREDENTIALS, "***");
- log.trace("Logging into LDAP server, env=" + tmp.toString());
- }
- }
-
- //JBAS-3438 : Handle "/" correctly
- private String canonicalize(String searchResult)
- {
- String result = searchResult;
- int len = searchResult.length();
-
- if (searchResult.endsWith("\""))
- {
- result = searchResult.substring(0,len - 1)
- + "," + rolesCtxDN + "\"";
- }
- else
- {
- result = searchResult + "," + rolesCtxDN;
- }
- return result;
- }
-
- private void addRole(String roleName)
- {
- if (roleName != null)
- {
- try
- {
- Principal p = super.createIdentity(roleName);
- log.trace("Assign user to role " + roleName);
- userRoles.addMember(p);
- }
- catch (Exception e)
- {
- log.debug("Failed to create principal: " + roleName, e);
- }
- }
- }
-}
More information about the jboss-cvs-commits
mailing list