Return-Path: Delivered-To: apmail-geronimo-scm-archive@www.apache.org Received: (qmail 55018 invoked from network); 28 Jun 2010 08:50:13 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 28 Jun 2010 08:50:13 -0000 Received: (qmail 59752 invoked by uid 500); 28 Jun 2010 08:50:13 -0000 Delivered-To: apmail-geronimo-scm-archive@geronimo.apache.org Received: (qmail 59624 invoked by uid 500); 28 Jun 2010 08:50:11 -0000 Mailing-List: contact scm-help@geronimo.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@geronimo.apache.org List-Id: Delivered-To: mailing list scm@geronimo.apache.org Received: (qmail 59617 invoked by uid 99); 28 Jun 2010 08:50:10 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 28 Jun 2010 08:50:10 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 28 Jun 2010 08:50:04 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id D7C2523889D2; Mon, 28 Jun 2010 08:49:00 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r958505 - /geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/ Date: Mon, 28 Jun 2010 08:49:00 -0000 To: scm@geronimo.apache.org From: ashishjain@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100628084900.D7C2523889D2@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: ashishjain Date: Mon Jun 28 08:49:00 2010 New Revision: 958505 URL: http://svn.apache.org/viewvc?rev=958505&view=rev Log: GERONIMO-5197 Add generic header authentication modules for properties, ldap and sql. Added: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLdapLoginModule.java (with props) geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLoginmodule.java (with props) geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderPropertiesFileLoginModule.java (with props) geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderSqlLoginmodule.java (with props) Added: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLdapLoginModule.java URL: http://svn.apache.org/viewvc/geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLdapLoginModule.java?rev=958505&view=auto ============================================================================== --- geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLdapLoginModule.java (added) +++ geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLdapLoginModule.java Mon Jun 28 08:49:00 2010 @@ -0,0 +1,440 @@ +package org.apache.geronimo.security.realm.providers; + +import java.io.IOException; +import java.security.Principal; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.naming.AuthenticationException; +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +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.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.geronimo.security.jaas.JaasLoginModuleUse; +import org.apache.geronimo.security.jaas.WrappingLoginModule; + +public class GenericHttpHeaderLdapLoginModule extends GenericHttpHeaderLoginmodule implements LoginModule { + + private static Log log = LogFactory.getLog(GenericHttpHeaderLdapLoginModule.class); + + private final static String HEADER_NAMES="headerNames"; + private final static String AUTHENTICATION_AUTHORITY="authenticationAuthority"; + private static final String INITIAL_CONTEXT_FACTORY = "initialContextFactory"; + private static final String CONNECTION_URL = "connectionURL"; + private static final String CONNECTION_USERNAME = "connectionUsername"; + private static final String CONNECTION_PASSWORD = "connectionPassword"; + private static final String CONNECTION_PROTOCOL = "connectionProtocol"; + private static final String AUTHENTICATION = "authentication"; + private static final String USER_BASE = "userBase"; + private static final String USER_SEARCH_MATCHING = "userSearchMatching"; + private static final String USER_SEARCH_SUBTREE = "userSearchSubtree"; + private static final String ROLE_BASE = "roleBase"; + private static final String ROLE_NAME = "roleName"; + private static final String ROLE_SEARCH_MATCHING = "roleSearchMatching"; + private static final String ROLE_SEARCH_SUBTREE = "roleSearchSubtree"; + private static final String USER_ROLE_NAME = "userRoleName"; + public final static List supportedOptions = Collections.unmodifiableList(Arrays.asList(INITIAL_CONTEXT_FACTORY, CONNECTION_URL, + CONNECTION_USERNAME,CONNECTION_PASSWORD, HEADER_NAMES, AUTHENTICATION_AUTHORITY, CONNECTION_PROTOCOL, AUTHENTICATION, USER_BASE, + USER_SEARCH_MATCHING, USER_SEARCH_SUBTREE, ROLE_BASE, ROLE_NAME, ROLE_SEARCH_MATCHING, ROLE_SEARCH_SUBTREE, + USER_ROLE_NAME)); + + private String initialContextFactory; + private String connectionURL; + private String connectionProtocol; + private String connectionUsername; + private String connectionPassword; + private String authentication; + private String userBase; + private String roleBase; + private String roleName; + private String userRoleName; + + protected DirContext context = null; + + private MessageFormat userSearchMatchingFormat; + private MessageFormat roleSearchMatchingFormat; + + private boolean userSearchSubtreeBool = false; + private boolean roleSearchSubtreeBool = false; + + private boolean loginSucceeded; + private final Set groups = new HashSet(); + private final Set allPrincipals = new HashSet(); + + public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { + this.subject = subject; + this.callbackHandler = callbackHandler; + for(Object option: options.keySet()) { + if(!supportedOptions.contains(option) && !JaasLoginModuleUse.supportedOptions.contains(option) + && !WrappingLoginModule.supportedOptions.contains(option)) { + log.warn("Ignoring option: "+option+". Not supported."); + } + } + headerNames= (String)options.get(HEADER_NAMES); + authenticationAuthority=(String)options.get(AUTHENTICATION_AUTHORITY); + initialContextFactory = (String) options.get(INITIAL_CONTEXT_FACTORY); + connectionURL = (String) options.get(CONNECTION_URL); + connectionUsername = (String) options.get(CONNECTION_USERNAME); + connectionPassword = (String) options.get(CONNECTION_PASSWORD); + connectionProtocol = (String) options.get(CONNECTION_PROTOCOL); + authentication = (String) options.get(AUTHENTICATION); + userBase = (String) options.get(USER_BASE); + String userSearchMatching = (String) options.get(USER_SEARCH_MATCHING); + String userSearchSubtree = (String) options.get(USER_SEARCH_SUBTREE); + roleBase = (String) options.get(ROLE_BASE); + roleName = (String) options.get(ROLE_NAME); + String roleSearchMatching = (String) options.get(ROLE_SEARCH_MATCHING); + String roleSearchSubtree = (String) options.get(ROLE_SEARCH_SUBTREE); + userRoleName = (String) options.get(USER_ROLE_NAME); + userSearchMatchingFormat = new MessageFormat(userSearchMatching); + roleSearchMatchingFormat = new MessageFormat(roleSearchMatching); + userSearchSubtreeBool = Boolean.valueOf(userSearchSubtree); + roleSearchSubtreeBool = Boolean.valueOf(roleSearchSubtree); + } + + /** + * This LoginModule is not to be ignored. So, this method should never return false. + * @return true if authentication succeeds, or throw a LoginException such as FailedLoginException + * if authentication fails + */ + public boolean login() throws LoginException { + Map headerMap=null; + loginSucceeded = false; + Callback[] callbacks = new Callback[1]; + callbacks[0]= new RequestCallback(); + try { + callbackHandler.handle(callbacks); + } catch (IOException ioe) { + throw (LoginException) new LoginException().initCause(ioe); + } catch (UnsupportedCallbackException uce) { + throw (LoginException) new LoginException().initCause(uce); + } + httpRequest = ((RequestCallback) callbacks[0]).getRequest(); + String []headers=headerNames.split(","); + try{ + headerMap=matchHeaders(httpRequest, headers); + } + catch(HeaderMismatchException e){ + throw (LoginException) new LoginException("Header Mistmatch error").initCause(e); + } + + if(headerMap.isEmpty()){ + throw new FailedLoginException(); + } + + if(authenticationAuthority.equalsIgnoreCase("Siteminder")){ + HeaderHandler headerHandler= new SiteminderHeaderHandler(); + username=headerHandler.getUser(headerMap); + } + else + if(authenticationAuthority.equalsIgnoreCase("Datapower")) + { + /*To be Done*/ + } + if (username == null || username.equals("")) { + username = null; + throw new FailedLoginException(); + } + + try { + boolean result = authenticate(username); + if (!result) { + throw new FailedLoginException(); + } + } catch (LoginException e) { + // Clear out the private state + username = null; + groups.clear(); + throw e; + } catch (Exception e) { + // Clear out the private state + username = null; + groups.clear(); + throw (LoginException) new LoginException("LDAP Error").initCause(e); + } + + loginSucceeded = true; + return loginSucceeded; + } + + /* + * @exception LoginException if login succeeded but commit failed. + * + * @return true if login succeeded and commit succeeded, or false if login failed but commit succeeded. + */ + public boolean commit() throws LoginException { + if(loginSucceeded) { + for(String group: groups) { + allPrincipals.add(new GeronimoGroupPrincipal(group)); + } + subject.getPrincipals().addAll(allPrincipals); + } + + // Clear out the private state + username = null; + groups.clear(); + + return loginSucceeded; + } + + public boolean abort() throws LoginException { + if(loginSucceeded) { + // Clear out the private state + username = null; + groups.clear(); + allPrincipals.clear(); + } + return loginSucceeded; + } + + public boolean logout() throws LoginException { + // Clear out the private state + loginSucceeded = false; + username = null; + groups.clear(); + if(!subject.isReadOnly()) { + // Remove principals added by this LoginModule + subject.getPrincipals().removeAll(allPrincipals); + } + allPrincipals.clear(); + return true; + } + + protected void close(DirContext context) { + try { + context.close(); + } catch (Exception e) { + log.error(e); + } + } + + protected boolean authenticate(String username) throws Exception { + DirContext context = open(); + try { + + String filter = userSearchMatchingFormat.format(new String[]{username}); + SearchControls constraints = new SearchControls(); + if (userSearchSubtreeBool) { + constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); + } else { + constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE); + } + + //setup attributes + String[] attribs; + if (userRoleName == null) { + attribs = new String[]{}; + } else { + attribs = new String[]{userRoleName}; + } + constraints.setReturningAttributes(attribs); + + + NamingEnumeration results = context.search(userBase, filter, constraints); + + if (results == null || !results.hasMore()) { + log.error("No roles associated with user "+username); + loginSucceeded=false; + throw new FailedLoginException(); + } + + SearchResult result = (SearchResult) results.next(); + + if (results.hasMore()) { + //ignore for now + } + NameParser parser = context.getNameParser(""); + Name contextName = parser.parse(context.getNameInNamespace()); + Name baseName = parser.parse(userBase); + Name entryName = parser.parse(result.getName()); + Name name = contextName.addAll(baseName); + name = name.addAll(entryName); + String dn = name.toString(); + + Attributes attrs = result.getAttributes(); + if (attrs == null) { + return false; + } + ArrayList roles = null; + if (userRoleName != null) { + roles = addAttributeValues(userRoleName, attrs, roles); + } + //check the credentials by binding to server + // bindUser(context, dn); + //if authenticated add more roles + roles = getRoles(context, dn, username, roles); + for (String role : roles) { + groups.add(role); + } + if(groups.isEmpty()){ + log.error("No roles associated with user "+username); + loginSucceeded=false; + throw new FailedLoginException(); + } + else + loginSucceeded=true; + + } catch (CommunicationException e) { + close(context); + throw (LoginException) new FailedLoginException().initCause(e); + } catch (NamingException e) { + close(context); + throw (LoginException) new FailedLoginException().initCause(e); + } + return true; + } + + protected ArrayList getRoles(DirContext context, String dn, String username, ArrayList list) throws NamingException { + if (list == null) { + list = new ArrayList(); + } + if (roleName == null || "".equals(roleName)) { + return list; + } + String filter = roleSearchMatchingFormat.format(new String[]{doRFC2254Encoding(dn), username}); + + SearchControls constraints = new SearchControls(); + if (roleSearchSubtreeBool) { + constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); + } else { + constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE); + } + NamingEnumeration results = + context.search(roleBase, filter, constraints); + while (results.hasMore()) { + SearchResult result = (SearchResult) results.next(); + Attributes attrs = result.getAttributes(); + if (attrs == null) { + continue; + } + list = addAttributeValues(roleName, attrs, list); + } + return list; + } + + + protected String doRFC2254Encoding(String inputString) { + StringBuffer buf = new StringBuffer(inputString.length()); + for (int i = 0; i < inputString.length(); i++) { + char c = inputString.charAt(i); + switch (c) { + case'\\': + buf.append("\\5c"); + break; + case'*': + buf.append("\\2a"); + break; + case'(': + buf.append("\\28"); + break; + case')': + buf.append("\\29"); + break; + case'\0': + buf.append("\\00"); + break; + default: + buf.append(c); + break; + } + } + return buf.toString(); + } + + protected void bindUser(DirContext context, String dn) throws NamingException, FailedLoginException { + + context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn); + try { + context.getAttributes("", null); + } catch (AuthenticationException e) { + log.debug("Authentication failed for dn=" + dn); + throw new FailedLoginException(); + } finally { + + if (connectionUsername != null) { + context.addToEnvironment(Context.SECURITY_PRINCIPAL, + connectionUsername); + } else { + context.removeFromEnvironment(Context.SECURITY_PRINCIPAL); + } + + if (connectionPassword != null) { + context.addToEnvironment(Context.SECURITY_CREDENTIALS, + connectionPassword); + } else { + context.removeFromEnvironment(Context.SECURITY_CREDENTIALS); + } + } + } + + private ArrayList addAttributeValues(String attrId, Attributes attrs, ArrayList values) + throws NamingException { + + if (attrId == null || attrs == null) { + return values; + } + if (values == null) { + values = new ArrayList(); + } + Attribute attr = attrs.get(attrId); + if (attr == null) { + return (values); + } + NamingEnumeration e = attr.getAll(); + while (e.hasMore()) { + String value = (String) e.next(); + values.add(value); + } + return values; + } + + protected DirContext open() throws NamingException { + if (context != null) { + return context; + } + try { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory); + if (connectionUsername != null || !"".equals(connectionUsername)) { + env.put(Context.SECURITY_PRINCIPAL, connectionUsername); + } + if (connectionPassword != null || !"".equals(connectionPassword)) { + env.put(Context.SECURITY_CREDENTIALS, connectionPassword); + } + env.put(Context.SECURITY_PROTOCOL, connectionProtocol == null ? "" : connectionProtocol); + env.put(Context.PROVIDER_URL, connectionURL == null ? "" : connectionURL); + env.put(Context.SECURITY_AUTHENTICATION, authentication == null ? "" : authentication); + context = new InitialDirContext(env); + + } catch (NamingException e) { + log.error(e); + throw e; + } + return context; + } +} Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLdapLoginModule.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLdapLoginModule.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLdapLoginModule.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLoginmodule.java URL: http://svn.apache.org/viewvc/geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLoginmodule.java?rev=958505&view=auto ============================================================================== --- geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLoginmodule.java (added) +++ geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLoginmodule.java Mon Jun 28 08:49:00 2010 @@ -0,0 +1,73 @@ +package org.apache.geronimo.security.realm.providers; + +import java.security.Principal; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.geronimo.management.geronimo.JCAManagedConnectionFactory; +/* + * Parent class for all the generic header login modules. + */ +public abstract class GenericHttpHeaderLoginmodule { + + private static Log log = LogFactory.getLog(GenericHttpHeaderLoginmodule.class); + + protected Subject subject; + protected String username; + protected String headerNames; + protected String authenticationAuthority; + protected JCAManagedConnectionFactory factory; + protected CallbackHandler callbackHandler; + protected boolean loginSucceeded; + protected HttpServletRequest httpRequest; + protected Set allPrincipals = new HashSet(); + protected Set groups = new HashSet(); + + public GenericHttpHeaderLoginmodule(){ + + } + + protected void commitHelper(){ + for(String group:groups){ + allPrincipals.add(new GeronimoGroupPrincipal(group)); + } + subject.getPrincipals().addAll(allPrincipals); + subject.getPublicCredentials().add(username); + } + + public void abortHelper(){ + allPrincipals.clear(); + groups.clear(); + } + + public void logoutHelper(){ + groups.clear(); + if(!subject.isReadOnly()) { + // Remove principals added by this LoginModule + subject.getPrincipals().removeAll(allPrincipals); + } + allPrincipals.clear(); + } + + public Map matchHeaders(HttpServletRequest request, String[] headers) throws HeaderMismatchException{ + Map headerMap= new HashMap(); + for(String header:headers){ + String headerValue=request.getHeader(header); + if(headerValue!=null){ + headerMap.put(header, headerValue); + } + else + log.warn("An Unauthorized attempt has been made to access the protected resource from host "+request.getRemoteHost()); + } + return headerMap; + } + +} Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLoginmodule.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLoginmodule.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderLoginmodule.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderPropertiesFileLoginModule.java URL: http://svn.apache.org/viewvc/geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderPropertiesFileLoginModule.java?rev=958505&view=auto ============================================================================== --- geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderPropertiesFileLoginModule.java (added) +++ geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderPropertiesFileLoginModule.java Mon Jun 28 08:49:00 2010 @@ -0,0 +1,200 @@ +package org.apache.geronimo.security.realm.providers; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +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.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.geronimo.common.GeronimoSecurityException; +import org.apache.geronimo.security.jaas.JaasLoginModuleUse; +import org.apache.geronimo.security.jaas.WrappingLoginModule; +import org.apache.geronimo.system.serverinfo.ServerInfo; + +public class GenericHttpHeaderPropertiesFileLoginModule extends GenericHttpHeaderLoginmodule implements LoginModule { + private final static String GROUPS_URI = "groupsURI"; + private final static String HEADER_NAMES="headerNames"; + private final static String AUTHENTICATION_AUTHORITY="authenticationAuthority"; + + public final static List supportedOptions = Collections.unmodifiableList(Arrays.asList(GROUPS_URI, HEADER_NAMES, AUTHENTICATION_AUTHORITY)); + private static Log log = LogFactory.getLog(PropertiesFileLoginModule.class); + final Map> roleUsersMap = new HashMap>(); + + + public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { + this.subject = subject; + this.callbackHandler = callbackHandler; + headerNames= (String)options.get(HEADER_NAMES); + authenticationAuthority=(String)options.get(AUTHENTICATION_AUTHORITY); + + for(Object option: options.keySet()) { + if(!supportedOptions.contains(option) && !JaasLoginModuleUse.supportedOptions.contains(option) + && !WrappingLoginModule.supportedOptions.contains(option)) { + log.warn("Ignoring option: "+option+". Not supported."); + } + } + try { + ServerInfo serverInfo = (ServerInfo) options.get(JaasLoginModuleUse.SERVERINFO_LM_OPTION); + final String groups = (String) options.get(GROUPS_URI); + + if (groups == null) { + throw new IllegalArgumentException(GROUPS_URI + " must be provided!"); + } + URI groupsURI = new URI(groups); + loadProperties(serverInfo, groupsURI); + } catch (Exception e) { + log.error("Initialization failed", e); + throw new IllegalArgumentException("Unable to configure properties file login module: " + e.getMessage(), + e); + } + } + + public void loadProperties(ServerInfo serverInfo, URI groupURI) throws GeronimoSecurityException { + try { + URI groupFile = serverInfo.resolveServer(groupURI); + Properties temp = new Properties(); + InputStream stream = groupFile.toURL().openStream(); + temp.load(stream); + stream.close(); + + Enumeration e = temp.keys(); + while (e.hasMoreElements()) { + String groupName = (String) e.nextElement(); + String[] userList = ((String) temp.get(groupName)).split(","); + + Set userset = roleUsersMap.get(groupName); + if (userset == null) { + userset = new HashSet(); + roleUsersMap.put(groupName, userset); + } + for (String user : userList) { + userset.add(user); + } + } + + } catch (Exception e) { + log.error("Generic HTTP Header Properties File Login Module - data load failed", e); + throw new GeronimoSecurityException(e); + } + } + + public boolean login() throws LoginException { + Map headerMap=null; + loginSucceeded = false; + Callback[] callbacks = new Callback[1]; + callbacks[0]= new RequestCallback(); + try { + callbackHandler.handle(callbacks); + } catch (IOException ioe) { + throw (LoginException) new LoginException().initCause(ioe); + } catch (UnsupportedCallbackException uce) { + throw (LoginException) new LoginException().initCause(uce); + } + httpRequest = ((RequestCallback) callbacks[0]).getRequest(); + String []headers=headerNames.split(","); + try{ + headerMap=matchHeaders(httpRequest, headers); + } + catch(HeaderMismatchException e){ + throw (LoginException) new LoginException("Header Mistmatch error").initCause(e); + } + + if(headerMap.isEmpty()){ + throw new FailedLoginException(); + } + + if(authenticationAuthority.equalsIgnoreCase("Siteminder")){ + HeaderHandler headerHandler= new SiteminderHeaderHandler(); + username=headerHandler.getUser(headerMap); + } + else + if(authenticationAuthority.equalsIgnoreCase("Datapower")) + { + /*To be Done*/ + } + if (username == null || username.equals("")) { + username = null; + throw new FailedLoginException(); + } + + if(username!= null) { + for (Map.Entry> entry : roleUsersMap.entrySet()) { + String groupName = entry.getKey(); + Set users = entry.getValue(); + for (String user : users) { + if (username.equals(user)) { + groups.add(groupName); + break; + } + } + } + } + + if(groups.isEmpty()){ + log.error("No roles associated with user "+username); + loginSucceeded=false; + throw new FailedLoginException(); + } + else + loginSucceeded=true; + return loginSucceeded; + } + + /* + * @exception LoginException if login succeeded but commit failed. + * + * @return true if login succeeded and commit succeeded, or false if login failed but commit succeeded. + */ + public boolean commit() throws LoginException { + if(loginSucceeded) { + if(username != null) { + super.commitHelper(); + } + } + + // Clear out the private state + username = null; + roleUsersMap.clear(); + groups.clear(); + + return loginSucceeded; + } + + public boolean abort() throws LoginException { + if(loginSucceeded) { + // Clear out the private state + username = null; + allPrincipals.clear(); + } + return loginSucceeded; + } + + public boolean logout() throws LoginException { + // Clear out the private state + loginSucceeded = false; + username = null; + if(!subject.isReadOnly()) { + // Remove principals added by this LoginModule + subject.getPrincipals().removeAll(allPrincipals); + } + allPrincipals.clear(); + return true; + } +} Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderPropertiesFileLoginModule.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderPropertiesFileLoginModule.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderPropertiesFileLoginModule.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderSqlLoginmodule.java URL: http://svn.apache.org/viewvc/geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderSqlLoginmodule.java?rev=958505&view=auto ============================================================================== --- geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderSqlLoginmodule.java (added) +++ geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderSqlLoginmodule.java Mon Jun 28 08:49:00 2010 @@ -0,0 +1,234 @@ +package org.apache.geronimo.security.realm.providers; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +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 javax.sql.DataSource; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.geronimo.gbean.AbstractName; +import org.apache.geronimo.gbean.AbstractNameQuery; +import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; +import org.apache.geronimo.kernel.GBeanNotFoundException; +import org.apache.geronimo.kernel.Kernel; +import org.apache.geronimo.kernel.KernelRegistry; +import org.apache.geronimo.management.geronimo.JCAManagedConnectionFactory; +import org.apache.geronimo.security.jaas.JaasLoginModuleUse; +import org.apache.geronimo.security.jaas.WrappingLoginModule; + + +public class GenericHttpHeaderSqlLoginmodule extends GenericHttpHeaderLoginmodule implements LoginModule { + private static Log log = LogFactory.getLog(GenericHttpHeaderSqlLoginmodule.class); + + private final static String GROUP_SELECT = "groupSelect"; + private final static String USER = "jdbcUser"; + private final static String DATABASE_POOL_NAME = "dataSourceName"; + private final static String DATABASE_POOL_APP_NAME = "dataSourceApplication"; + private final static String HEADER_NAMES="headerNames"; + private final static String AUTHENTICATION_AUTHORITY="authenticationAuthority"; + private final static List supportedOptions = Collections.unmodifiableList(Arrays.asList(GROUP_SELECT, USER, + DATABASE_POOL_NAME, DATABASE_POOL_APP_NAME,HEADER_NAMES,AUTHENTICATION_AUTHORITY)); + private String groupSelect; + + public boolean abort() throws LoginException { + if(loginSucceeded) { + // Clear out the private state + username = null; + groups.clear(); + allPrincipals.clear(); + } + return loginSucceeded; + } + + public boolean commit() throws LoginException { + if(loginSucceeded) { + if(username != null) { + super.commitHelper(); + } + } + + // Clear out the private state + username = null; + groups.clear(); + + return loginSucceeded; + } + + public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, + Map options) { + this.subject = subject; + this.callbackHandler = callbackHandler; + for (Object option : options.keySet()) { + if (!supportedOptions.contains(option) && !JaasLoginModuleUse.supportedOptions.contains(option) + && !WrappingLoginModule.supportedOptions.contains(option)) { + log.warn("Ignoring option: " + option + ". Not supported."); + } + } + headerNames= (String)options.get(HEADER_NAMES); + authenticationAuthority=(String)options.get(AUTHENTICATION_AUTHORITY); + groupSelect = (String) options.get(GROUP_SELECT); + String dataSourceName = (String) options.get(DATABASE_POOL_NAME); + if (dataSourceName != null) { + dataSourceName = dataSourceName.trim(); + String dataSourceAppName = (String) options.get(DATABASE_POOL_APP_NAME); + if (dataSourceAppName == null || dataSourceAppName.trim().equals("")) { + dataSourceAppName = "null"; + } else { + dataSourceAppName = dataSourceAppName.trim(); + } + String kernelName = (String) options.get(JaasLoginModuleUse.KERNEL_NAME_LM_OPTION); + Kernel kernel = KernelRegistry.getKernel(kernelName); + Set set = kernel.listGBeans(new AbstractNameQuery(JCAManagedConnectionFactory.class.getName())); + JCAManagedConnectionFactory factory; + for (AbstractName name : set) { + if (name.getName().get(NameFactory.J2EE_APPLICATION).equals(dataSourceAppName) + && name.getName().get(NameFactory.J2EE_NAME).equals(dataSourceName)) { + try { + factory = (JCAManagedConnectionFactory) kernel.getGBean(name); + String type = factory.getConnectionFactoryInterface(); + if (type.equals(DataSource.class.getName())) { + this.factory = factory; + break; + } + } catch (GBeanNotFoundException e) { + // ignore... GBean was unregistered + } + } + } + } + } + + public boolean login() throws LoginException { + Map headerMap=null; + loginSucceeded = false; + Connection conn=null; + ResultSet result=null; + PreparedStatement statement=null; + Callback[] callbacks = new Callback[1]; + callbacks[0]= new RequestCallback(); + try { + callbackHandler.handle(callbacks); + } catch (IOException ioe) { + throw (LoginException) new LoginException().initCause(ioe); + } catch (UnsupportedCallbackException uce) { + throw (LoginException) new LoginException().initCause(uce); + } + httpRequest = ((RequestCallback) callbacks[0]).getRequest(); + String []headers=headerNames.split(","); + try{ + headerMap=matchHeaders(httpRequest, headers); + } + catch(HeaderMismatchException e){ + throw (LoginException) new LoginException("Header Mistmatch error").initCause(e); + } + + if(headerMap.isEmpty()){ + throw new FailedLoginException(); + } + + if(authenticationAuthority.equalsIgnoreCase("Siteminder")){ + HeaderHandler headerHandler= new SiteminderHeaderHandler(); + username=headerHandler.getUser(headerMap); + } + else + if(authenticationAuthority.equalsIgnoreCase("Datapower")) + { + /*To be Done*/ + } + if (username == null || username.equals("")) { + username = null; + throw new FailedLoginException(); + } + + if (factory != null) { + DataSource ds; + try { + ds = (DataSource) factory.getConnectionFactory(); + conn = ds.getConnection(); + + try { + statement = conn.prepareStatement(groupSelect); + int count = countParameters(groupSelect); + for (int i = 0; i < count; i++) { + statement.setObject(i + 1, username); + } + result = statement.executeQuery(); + while (result.next()) { + String userName = result.getString(1); + String groupName = result.getString(2); + if(userName.equals(username)) + groups.add(groupName); + } + if(groups.isEmpty()){ + log.error("No roles associated with user "+username); + loginSucceeded=false; + throw new FailedLoginException(); + } + else + loginSucceeded=true; + } + finally{ + result.close(); + statement.close(); + conn.close(); + } + } + catch (LoginException e) { + // Clear out the private state + username = null; + groups.clear(); + throw e; + } catch (SQLException sqle) { + // Clear out the private state + username = null; + groups.clear(); + throw (LoginException) new LoginException("SQL error").initCause(sqle); + } catch (Exception e) { + // Clear out the private state + username = null; + groups.clear(); + throw (LoginException) new LoginException("Could not access datasource").initCause(e); + } + } + + return loginSucceeded; + } + + public boolean logout() throws LoginException { + loginSucceeded = false; + username = null; + groups.clear(); + if(!subject.isReadOnly()) { + // Remove principals added by this LoginModule + subject.getPrincipals().removeAll(allPrincipals); + } + allPrincipals.clear(); + return true; + } + + private static int countParameters(String sql) { + int count = 0; + int pos = -1; + while ((pos = sql.indexOf('?', pos + 1)) != -1) { + ++count; + } + return count; + } + +} Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderSqlLoginmodule.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderSqlLoginmodule.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: geronimo/server/branches/2.1/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/GenericHttpHeaderSqlLoginmodule.java ------------------------------------------------------------------------------ svn:mime-type = text/plain