User: starksm Date: 01/08/03 13:31:18 Modified: src/main/org/jboss/security/auth/spi Tag: Branch_2_4 LdapLoginModule.java Log: Fix bug in validatePassword, #447596 Revision Changes Path No revision No revision 1.1.4.2 +221 -220 jbosssx/src/main/org/jboss/security/auth/spi/LdapLoginModule.java Index: LdapLoginModule.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/auth/spi/LdapLoginModule.java,v retrieving revision 1.1.4.1 retrieving revision 1.1.4.2 diff -u -r1.1.4.1 -r1.1.4.2 --- LdapLoginModule.java 2001/07/09 08:49:37 1.1.4.1 +++ LdapLoginModule.java 2001/08/03 20:31:18 1.1.4.2 @@ -1,220 +1,221 @@ -/* - * JBoss, the OpenSource EJB server - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package org.jboss.security.auth.spi; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -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.BasicAttributes; -import javax.naming.directory.SearchResult; -import javax.naming.ldap.InitialLdapContext; -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.FailedLoginException; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; - -import org.jboss.security.SimpleGroup; -import org.jboss.security.SimplePrincipal; -import org.jboss.security.auth.callback.ObjectCallback; -import org.jboss.security.auth.spi.UsernamePasswordLoginModule; - -/** An implementation of LoginModule that authenticates against an LDAP server - using JNDI based on the configuration properties. - - The LoginModule options include whatever options your LDAP JNDI provider - support. 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 Context.SECURITY_PRINCIPAL is set to the distinguished name of the user - as obtained by the callback handler and the Context.SECURITY_CREDENTIALS - property is either set to the String password or Object credential depending - on the useObjectCredential option. - - Additional module properties include: - principalDNPrefix, principalDNSuffix : A prefix and suffix to add to the - username when forming the user distiguished name. This is useful if you - prompt a user for a username and you don't want them to have to enter the - fully distinguished name. Using this property and principalDNSuffix the - userDN will be formed as: - <code>String userDN = principalDNPrefix + username + principalDNSuffix;</code> - - useObjectCredential : indicates that the credential should be obtained as - an opaque Object using the org.jboss.security.plugins.ObjectCallback type - of Callback rather than as a char[] password using a JAAS PasswordCallback. - - rolesCtxDN : The distinguished name to the context to search for user roles. - roleAttributeName : The name of the attribute that contains the user roles - uidAttributeName : The name of the attribute that in the object containing - the user roles that corresponds to the userid. This is used to locate the - user roles. - - A sample login config: - testLdap { - org.jboss.security.plugins.samples.LdapLoginModule required - java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory - principalDNPrefix=uid= - uidAttributeID=userid - roleAttributeID=rolenames - principalDNSuffix=,ou=People,o=displayscape.com - rolesCtxDN=ou=Users,cn=Project1,ou=Projects,o=displayscape.com - java.naming.provider.url=ldap://siren-int/ - java.naming.security.authentication=simple - }; - - @author [EMAIL PROTECTED] - @version $Revision: 1.1.4.1 $ - */ -public class LdapLoginModule extends UsernamePasswordLoginModule -{ - private static final String USE_OBJECT_CREDENTIAL_OPT = "useObjectCredential"; - private static final String PRINCIPAL_DN_PREFIX_OPT = "principalDNPrefix"; - private static final String PRINCIPAL_DN_SUFFIX_OPT = "principalDNSuffix"; - private static final String ROLES_CTX_DN_OPT = "rolesCtxDN"; - private static final String UID_ATTRIBUTE_ID_OPT = "uidAttributeID"; - private static final String ROLE_ATTRIBUTE_ID_OPT = "roleAttributeID"; - - public LdapLoginModule() - { - } - - 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; - } - - protected boolean validatePassword(String inputPassword, String expectedPassword) - { - boolean isValid = false; - if( inputPassword != null ) - { - try - { - // Validate the password by trying to create an initial context - String username = getUsername(); - createLdapInitContext(username, inputPassword); - } - catch(NamingException e) - { - e.printStackTrace(); - } - } - return isValid; - } - - private void createLdapInitContext(String username, Object credential) throws NamingException - { - Properties env = new Properties(); - // Map all option into the JNDI InitialLdapContext env - 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")) ? "389" : "636"); - - String principalDNPrefix = (String) options.get(PRINCIPAL_DN_PREFIX_OPT); - if( principalDNPrefix == null ) - principalDNPrefix=""; - String principalDNSuffix = (String) options.get(PRINCIPAL_DN_SUFFIX_OPT); - if( principalDNSuffix == null ) - principalDNSuffix=""; - String userDN = principalDNPrefix + username + principalDNSuffix; - env.setProperty(Context.PROVIDER_URL, providerURL); - env.setProperty(Context.SECURITY_PRINCIPAL, userDN); - env.put(Context.SECURITY_CREDENTIALS, credential); - System.out.println("Logging into LDAP server, env="+env); - InitialLdapContext ctx = new InitialLdapContext(env, null); - System.out.println("Logged into LDAP server, "+ctx); - // Query the user's roles... - String rolesCtxDN = (String) options.get(ROLES_CTX_DN_OPT); - if( rolesCtxDN != null ) - { - String uidAttrName = (String) options.get(UID_ATTRIBUTE_ID_OPT); - if( uidAttrName == null ) - uidAttrName = "uid"; - String roleAttrName = (String) options.get(ROLE_ATTRIBUTE_ID_OPT); - if( roleAttrName == null ) - roleAttrName = "roles"; - BasicAttributes matchAttrs = new BasicAttributes(true); - matchAttrs.put(uidAttrName, username); - String[] roleAttr = - {roleAttrName}; - try - { - NamingEnumeration answer = ctx.search(rolesCtxDN, matchAttrs, roleAttr); - 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 = value.toString(); - userRoles.addMember(new SimplePrincipal(roleName)); - } - } - } - catch(NamingException e) - { - } - } - // Close the context to release the connection - ctx.close(); - } -} +/* + * JBoss, the OpenSource EJB server + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package org.jboss.security.auth.spi; + +import java.security.Principal; +import java.security.acl.Group; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +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.BasicAttributes; +import javax.naming.directory.SearchResult; +import javax.naming.ldap.InitialLdapContext; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.FailedLoginException; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; + +import org.jboss.security.SimpleGroup; +import org.jboss.security.SimplePrincipal; +import org.jboss.security.auth.callback.ObjectCallback; +import org.jboss.security.auth.spi.UsernamePasswordLoginModule; + +/** An implementation of LoginModule that authenticates against an LDAP server + using JNDI based on the configuration properties. + + The LoginModule options include whatever options your LDAP JNDI provider + support. 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 Context.SECURITY_PRINCIPAL is set to the distinguished name of the user + as obtained by the callback handler and the Context.SECURITY_CREDENTIALS + property is either set to the String password or Object credential depending + on the useObjectCredential option. + + Additional module properties include: + principalDNPrefix, principalDNSuffix : A prefix and suffix to add to the + username when forming the user distiguished name. This is useful if you + prompt a user for a username and you don't want them to have to enter the + fully distinguished name. Using this property and principalDNSuffix the + userDN will be formed as: + <code>String userDN = principalDNPrefix + username + principalDNSuffix;</code> + + useObjectCredential : indicates that the credential should be obtained as + an opaque Object using the org.jboss.security.plugins.ObjectCallback type + of Callback rather than as a char[] password using a JAAS PasswordCallback. + + rolesCtxDN : The distinguished name to the context to search for user roles. + roleAttributeName : The name of the attribute that contains the user roles + uidAttributeName : The name of the attribute that in the object containing + the user roles that corresponds to the userid. This is used to locate the + user roles. + + A sample login config: + testLdap { + org.jboss.security.plugins.samples.LdapLoginModule required + java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory + principalDNPrefix=uid= + uidAttributeID=userid + roleAttributeID=rolenames + principalDNSuffix=,ou=People,o=displayscape.com + rolesCtxDN=ou=Users,cn=Project1,ou=Projects,o=displayscape.com + java.naming.provider.url=ldap://siren-int/ + java.naming.security.authentication=simple + }; + + @author [EMAIL PROTECTED] + @version $Revision: 1.1.4.2 $ + */ +public class LdapLoginModule extends UsernamePasswordLoginModule +{ + private static final String USE_OBJECT_CREDENTIAL_OPT = "useObjectCredential"; + private static final String PRINCIPAL_DN_PREFIX_OPT = "principalDNPrefix"; + private static final String PRINCIPAL_DN_SUFFIX_OPT = "principalDNSuffix"; + private static final String ROLES_CTX_DN_OPT = "rolesCtxDN"; + private static final String UID_ATTRIBUTE_ID_OPT = "uidAttributeID"; + private static final String ROLE_ATTRIBUTE_ID_OPT = "roleAttributeID"; + + public LdapLoginModule() + { + } + + 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; + } + + protected boolean validatePassword(String inputPassword, String expectedPassword) + { + boolean isValid = false; + if( inputPassword != null ) + { + try + { + // Validate the password by trying to create an initial context + String username = getUsername(); + createLdapInitContext(username, inputPassword); + isValid = true; + } + catch(NamingException e) + { + e.printStackTrace(); + } + } + return isValid; + } + + private void createLdapInitContext(String username, Object credential) throws NamingException + { + Properties env = new Properties(); + // Map all option into the JNDI InitialLdapContext env + 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")) ? "389" : "636"); + + String principalDNPrefix = (String) options.get(PRINCIPAL_DN_PREFIX_OPT); + if( principalDNPrefix == null ) + principalDNPrefix=""; + String principalDNSuffix = (String) options.get(PRINCIPAL_DN_SUFFIX_OPT); + if( principalDNSuffix == null ) + principalDNSuffix=""; + String userDN = principalDNPrefix + username + principalDNSuffix; + env.setProperty(Context.PROVIDER_URL, providerURL); + env.setProperty(Context.SECURITY_PRINCIPAL, userDN); + env.put(Context.SECURITY_CREDENTIALS, credential); + System.out.println("Logging into LDAP server, env="+env); + InitialLdapContext ctx = new InitialLdapContext(env, null); + System.out.println("Logged into LDAP server, "+ctx); + // Query the user's roles... + String rolesCtxDN = (String) options.get(ROLES_CTX_DN_OPT); + if( rolesCtxDN != null ) + { + String uidAttrName = (String) options.get(UID_ATTRIBUTE_ID_OPT); + if( uidAttrName == null ) + uidAttrName = "uid"; + String roleAttrName = (String) options.get(ROLE_ATTRIBUTE_ID_OPT); + if( roleAttrName == null ) + roleAttrName = "roles"; + BasicAttributes matchAttrs = new BasicAttributes(true); + matchAttrs.put(uidAttrName, username); + String[] roleAttr = + {roleAttrName}; + try + { + NamingEnumeration answer = ctx.search(rolesCtxDN, matchAttrs, roleAttr); + 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 = value.toString(); + userRoles.addMember(new SimplePrincipal(roleName)); + } + } + } + catch(NamingException e) + { + } + } + // Close the context to release the connection + ctx.close(); + } +} _______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] http://lists.sourceforge.net/lists/listinfo/jboss-development