Index: lams_build/build_base.xml =================================================================== diff -u -ra0b759c0e2c1f081e1d2d10e5e8e6565b4e74505 -r9da35349a62686e5112d5be703c9047c48d88467 --- lams_build/build_base.xml (.../build_base.xml) (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505) +++ lams_build/build_base.xml (.../build_base.xml) (revision 9da35349a62686e5112d5be703c9047c48d88467) @@ -272,7 +272,15 @@ + + + ${ant.project.name}: Preparing SSO config file + + + + ${ant.project.name}: Building JAR @@ -284,7 +292,7 @@ + depends="_build-webdoclet, _build-manifest, _copy-language, _jsp-plaincopy, _jsp-precompile, _add-sso"> ${ant.project.name}: Building WAR Index: lams_build/common.properties =================================================================== diff -u -rf00a75141cbe08108d5b59396b88f6c995322979 -r9da35349a62686e5112d5be703c9047c48d88467 --- lams_build/common.properties (.../common.properties) (revision f00a75141cbe08108d5b59396b88f6c995322979) +++ lams_build/common.properties (.../common.properties) (revision 9da35349a62686e5112d5be703c9047c48d88467) @@ -23,6 +23,9 @@ # which o/s related property file do you want? valid values "windows" or "unix" osPropertiesName=windows +# a servlet extension that pulls credentials from shared session and allows access +ssoClass=org.lamsfoundation.lams.integration.security.SsoConsumer + # To precompile JSP pages uncomment the property below # jsp.precompile=anyvalue Index: lams_build/conf/standalone.xml =================================================================== diff -u -r9bfa89e11ba6cdcbf87f128f142a24047abb139d -r9da35349a62686e5112d5be703c9047c48d88467 --- lams_build/conf/standalone.xml (.../standalone.xml) (revision 9bfa89e11ba6cdcbf87f128f142a24047abb139d) +++ lams_build/conf/standalone.xml (.../standalone.xml) (revision 9da35349a62686e5112d5be703c9047c48d88467) @@ -366,7 +366,7 @@ - + Index: lams_build/lib/lams/lams-gradebook.jar =================================================================== diff -u -r5a5f3640c4d5fdf0c302347e7d6b502a972fd9cc -r9da35349a62686e5112d5be703c9047c48d88467 Binary files differ Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r567018f37ff59abaa5c6acf8a50209543857542f -r9da35349a62686e5112d5be703c9047c48d88467 Binary files differ Index: lams_central/build.properties =================================================================== diff -u -rd56929f06ad90a63082d514e6521adc175f3de27 -r9da35349a62686e5112d5be703c9047c48d88467 --- lams_central/build.properties (.../build.properties) (revision d56929f06ad90a63082d514e6521adc175f3de27) +++ lams_central/build.properties (.../build.properties) (revision 9da35349a62686e5112d5be703c9047c48d88467) @@ -6,4 +6,8 @@ product.path.filesystem=org/lamsfoundation/lams/central # Project is a core one, not a Tool -product.core=true \ No newline at end of file +product.core=true + +# a servlet extension that puts credentials into shared session to allows access for other modules +# overrides default setting in lams_build/common.properties +ssoClass=org.lamsfoundation.lams.integration.security.SsoProducer \ No newline at end of file Index: lams_central/build.xml =================================================================== diff -u -re1fa88a315d71d92edd258e0a2347804ed70feb8 -r9da35349a62686e5112d5be703c9047c48d88467 --- lams_central/build.xml (.../build.xml) (revision e1fa88a315d71d92edd258e0a2347804ed70feb8) +++ lams_central/build.xml (.../build.xml) (revision 9da35349a62686e5112d5be703c9047c48d88467) @@ -34,7 +34,7 @@ + depends="_build-webdoclet, _build-manifest, _copy-war-resources, _copy-planner, _jsp-plaincopy, _jsp-precompile, _add-sso"> ${ant.project.name}: Building exploded WAR Index: lams_central/src/java/org/lamsfoundation/lams/security/UniversalLoginModule.java =================================================================== diff -u -rab19db088359a46353cc92e806c40ff5cff818b9 -r9da35349a62686e5112d5be703c9047c48d88467 --- lams_central/src/java/org/lamsfoundation/lams/security/UniversalLoginModule.java (.../UniversalLoginModule.java) (revision ab19db088359a46353cc92e806c40ff5cff818b9) +++ lams_central/src/java/org/lamsfoundation/lams/security/UniversalLoginModule.java (.../UniversalLoginModule.java) (revision 9da35349a62686e5112d5be703c9047c48d88467) @@ -75,340 +75,319 @@ public class UniversalLoginModule extends UsernamePasswordLoginModule { - private static Logger log = Logger.getLogger(UniversalLoginModule.class); + private static Logger log = Logger.getLogger(UniversalLoginModule.class); - public UniversalLoginModule() { - } + public UniversalLoginModule() { + } - protected String dsJndiName; + protected String dsJndiName; - protected String rolesQuery; + protected String rolesQuery; - protected String principalsQuery; + protected String principalsQuery; - private IThemeService themeService; - private UserManagementService service; + private IThemeService themeService; + private UserManagementService service; - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, Map options) { - super.initialize(subject, callbackHandler, sharedState, options); - dsJndiName = (String) options.get("dsJndiName"); - principalsQuery = (String) options.get("principalsQuery"); - rolesQuery = (String) options.get("rolesQuery"); - } + @Override + public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { + super.initialize(subject, callbackHandler, sharedState, options); + dsJndiName = (String) options.get("dsJndiName"); + principalsQuery = (String) options.get("principalsQuery"); + rolesQuery = (String) options.get("rolesQuery"); + } - protected boolean validatePassword(String inputPassword, - String expectedPassword) { - boolean isValid = false; - if (inputPassword != null) { - // empty password not allowed - if (inputPassword.length() == 0) - return false; + @Override + protected boolean validatePassword(String inputPassword, String expectedPassword) { + boolean isValid = false; + if (inputPassword != null) { + // empty password not allowed + if (inputPassword.length() == 0) { + return false; + } - try { - String username = getUsername(); - log.debug("===> authenticating user: " + username); + try { + String username = getUsername(); + UniversalLoginModule.log.debug("===> authenticating user: " + username); - WebApplicationContext ctx = WebApplicationContextUtils - .getWebApplicationContext(HttpSessionManager - .getInstance().getServletContext()); + WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(HttpSessionManager + .getInstance().getServletContext()); - if (service == null) { - service = (UserManagementService) ctx - .getBean("userManagementService"); - } - User user = service.getUserByLogin(username); + if (service == null) { + service = (UserManagementService) ctx.getBean("userManagementService"); + } + User user = service.getUserByLogin(username); - if (themeService == null) { - themeService = (IThemeService) ctx.getBean("themeService"); - } + if (themeService == null) { + themeService = (IThemeService) ctx.getBean("themeService"); + } - // LDAP user provisioning - if (user == null) { - // provision a new user by checking ldap server - if (Configuration - .getAsBoolean(ConfigurationKeys.LDAP_PROVISIONING_ENABLED)) { - LdapService ldapService; - try { - ldapService = (LdapService) ctx - .getBean("ldapService"); - } catch (NoSuchBeanDefinitionException e) { - // LDEV-1937 - log - .error( - "NoSuchBeanDefinitionException while getting ldapService bean, will try another method...", - e); - ApplicationContext context = new ClassPathXmlApplicationContext( - "org/lamsfoundation/lams/usermanagement/ldapContext.xml"); - ldapService = (LdapService) context - .getBean("ldapService"); - } - log - .debug("===> LDAP provisioning is enabled, checking username against LDAP server..."); - LDAPAuthenticator ldap = new LDAPAuthenticator(); - isValid = ldap.authenticate(username, inputPassword); - if (isValid) { // create a new user - log - .info("===> Creating new user for LDAP username: " - + username); - if (ldapService.createLDAPUser(ldap.getAttrs())) { - user = service.getUserByLogin(username); - if (!ldapService.addLDAPUser(ldap.getAttrs(), - user.getUserId())) { - log.error("===> Couldn't add LDAP user: " - + username + " to organisation."); - } - } else { - log - .error("===> Couldn't create new user for LDAP username: " - + username); - return false; - } - } else { // didn't authenticate successfully with - // ldap - return false; - } - } else { - return false; - } + // LDAP user provisioning + if (user == null) { + // provision a new user by checking ldap server + if (Configuration.getAsBoolean(ConfigurationKeys.LDAP_PROVISIONING_ENABLED)) { + LdapService ldapService; + try { + ldapService = (LdapService) ctx.getBean("ldapService"); + } catch (NoSuchBeanDefinitionException e) { + // LDEV-1937 + UniversalLoginModule.log + .error("NoSuchBeanDefinitionException while getting ldapService bean, will try another method...", + e); + ApplicationContext context = new ClassPathXmlApplicationContext( + "org/lamsfoundation/lams/usermanagement/ldapContext.xml"); + ldapService = (LdapService) context.getBean("ldapService"); + } + UniversalLoginModule.log + .debug("===> LDAP provisioning is enabled, checking username against LDAP server..."); + LDAPAuthenticator ldap = new LDAPAuthenticator(); + isValid = ldap.authenticate(username, inputPassword); + if (isValid) { // create a new user + UniversalLoginModule.log.info("===> Creating new user for LDAP username: " + username); + if (ldapService.createLDAPUser(ldap.getAttrs())) { + user = service.getUserByLogin(username); + if (!ldapService.addLDAPUser(ldap.getAttrs(), user.getUserId())) { + UniversalLoginModule.log.error("===> Couldn't add LDAP user: " + username + + " to organisation."); } + } else { + UniversalLoginModule.log.error("===> Couldn't create new user for LDAP username: " + + username); + return false; + } + } else { // didn't authenticate successfully with + // ldap + return false; + } + } else { + return false; + } + } - // allow sysadmin to login as another user; in this case, the - // LAMS shared session - // will be present, allowing the following check to work - if (service.isUserSysAdmin()) { - isValid = true; - } + // allow sysadmin to login as another user; in this case, the + // LAMS shared session + // will be present, allowing the following check to work +// if (service.isUserSysAdmin()) { +// isValid = true; +// } - // perform password checking according to user's authentication - // method - if (!isValid) { - String type = user.getAuthenticationMethod() - .getAuthenticationMethodType().getDescription(); - log.debug("===> authentication type: " + type); - if (AuthenticationMethodType.LDAP.equals(type)) { - LDAPAuthenticator authenticator = new LDAPAuthenticator(); - isValid = authenticator.authenticate(username, - inputPassword); - // if ldap user profile has updated, udpate user object - // for dto below - user = service.getUserByLogin(username); - } else if (AuthenticationMethodType.LAMS.equals(type)) { - DatabaseAuthenticator authenticator = new DatabaseAuthenticator( - dsJndiName, principalsQuery); - // if the password is not encrypted when sent from the - // jsp (e.g. when it is passed - // unencrypted to say, ldap) then encrypt it here when - // authenticating against local db - if (!Configuration - .getAsBoolean(ConfigurationKeys.LDAP_ENCRYPT_PASSWORD_FROM_BROWSER)) { - // try the passed in password first, - // LoginRequestServlet always passes in encrypted - // passwords - isValid = authenticator.authenticate(username, - inputPassword); - if (!isValid) { - inputPassword = HashUtil.sha1(inputPassword); - } - isValid = authenticator.authenticate(username, - inputPassword); - } else { - isValid = authenticator.authenticate(username, - inputPassword); - } - } else if (AuthenticationMethodType.WEB_AUTH.equals(type)) { - WebAuthAuthenticator authenticator = new WebAuthAuthenticator(); - isValid = authenticator.authenticate(username, - inputPassword); - } else { - log.error("===> Unexpected authentication type: " - + type); - return false; - } - } + // perform password checking according to user's authentication + // method + if (!isValid) { + String type = user.getAuthenticationMethod().getAuthenticationMethodType().getDescription(); + UniversalLoginModule.log.debug("===> authentication type: " + type); + if (AuthenticationMethodType.LDAP.equals(type)) { + LDAPAuthenticator authenticator = new LDAPAuthenticator(); + isValid = authenticator.authenticate(username, inputPassword); + // if ldap user profile has updated, udpate user object + // for dto below + user = service.getUserByLogin(username); + } else if (AuthenticationMethodType.LAMS.equals(type)) { + DatabaseAuthenticator authenticator = new DatabaseAuthenticator(dsJndiName, principalsQuery); + // if the password is not encrypted when sent from the + // jsp (e.g. when it is passed + // unencrypted to say, ldap) then encrypt it here when + // authenticating against local db + if (!Configuration.getAsBoolean(ConfigurationKeys.LDAP_ENCRYPT_PASSWORD_FROM_BROWSER)) { + // try the passed in password first, + // LoginRequestServlet always passes in encrypted + // passwords + isValid = authenticator.authenticate(username, inputPassword); + if (!isValid) { + inputPassword = HashUtil.sha1(inputPassword); + } + isValid = authenticator.authenticate(username, inputPassword); + } else { + isValid = authenticator.authenticate(username, inputPassword); + } + } else if (AuthenticationMethodType.WEB_AUTH.equals(type)) { + WebAuthAuthenticator authenticator = new WebAuthAuthenticator(); + isValid = authenticator.authenticate(username, inputPassword); + } else { + UniversalLoginModule.log.error("===> Unexpected authentication type: " + type); + return false; + } + } - // disabled users can't login; - // check after authentication to give non-db authentication - // methods - // a chance to update disabled flag - if (user.getDisabledFlag()) { - log.debug("===> user is disabled."); - return false; - } + // disabled users can't login; + // check after authentication to give non-db authentication + // methods + // a chance to update disabled flag + if (user.getDisabledFlag()) { + UniversalLoginModule.log.debug("===> user is disabled."); + return false; + } - // if login is valid, register userDTO into session. - if (isValid) { - UserDTO userDTO = user.getUserDTO(); + // if login is valid, register userDTO into session. + if (isValid) { + UserDTO userDTO = user.getUserDTO(); - // If the user's css theme has been deleted, use the default - // as fallback - CSSThemeBriefDTO userCSSTheme = userDTO.getHtmlTheme(); - if (userCSSTheme != null) { - boolean themeExists = false; - for (Theme theme : themeService.getAllCSSThemes()) { - if (userCSSTheme.getId().equals(theme.getThemeId())) { - themeExists = true; - break; - } - } + // If the user's css theme has been deleted, use the default + // as fallback + CSSThemeBriefDTO userCSSTheme = userDTO.getHtmlTheme(); + if (userCSSTheme != null) { + boolean themeExists = false; + for (Theme theme : themeService.getAllCSSThemes()) { + if (userCSSTheme.getId().equals(theme.getThemeId())) { + themeExists = true; + break; + } + } - if (!themeExists) { - userDTO.setHtmlTheme(new CSSThemeBriefDTO( - themeService.getDefaultCSSTheme())); - } - } + if (!themeExists) { + userDTO.setHtmlTheme(new CSSThemeBriefDTO(themeService.getDefaultCSSTheme())); + } + } - // If the user's flash theme has been deleted, use the - // default as fallback - CSSThemeBriefDTO userFlashTheme = userDTO.getFlashTheme(); - if (userFlashTheme != null) { - boolean themeExists = false; - for (Theme theme : themeService.getAllFlashThemes()) { - if (userFlashTheme.getId().equals( - theme.getThemeId())) { - themeExists = true; - break; - } - } + // If the user's flash theme has been deleted, use the + // default as fallback + CSSThemeBriefDTO userFlashTheme = userDTO.getFlashTheme(); + if (userFlashTheme != null) { + boolean themeExists = false; + for (Theme theme : themeService.getAllFlashThemes()) { + if (userFlashTheme.getId().equals(theme.getThemeId())) { + themeExists = true; + break; + } + } - if (!themeExists) { - userDTO.setFlashTheme(new CSSThemeBriefDTO( - themeService.getDefaultFlashTheme())); - } - } - - HttpSession sharedsession = SessionManager.getSession(); - sharedsession.setAttribute(AttributeNames.USER, userDTO); - } - } catch (Exception e) { - e.printStackTrace(); - log.error("===> exception: " + e, e); + if (!themeExists) { + userDTO.setFlashTheme(new CSSThemeBriefDTO(themeService.getDefaultFlashTheme())); } + } + + HttpSession sharedsession = SessionManager.getSession(); + sharedsession.setAttribute(AttributeNames.USER, userDTO); } - return isValid; + } catch (Exception e) { + e.printStackTrace(); + UniversalLoginModule.log.error("===> exception: " + e, e); + } } + return isValid; + } - /** - * According to Lams's security policy, all the authorization must be done - * locally, in other word, through Lams database or other "local"(logically) - * data resource. - * - * @return Group[] containing the sets of roles - */ - protected Group[] getRoleSets() throws LoginException { - String username = getUsername(); - Connection conn = null; - HashMap setsMap = new HashMap(); - PreparedStatement ps = null; - ResultSet rs = null; + /** + * According to Lams's security policy, all the authorization must be done locally, in other word, through Lams + * database or other "local"(logically) data resource. + * + * @return Group[] containing the sets of roles + */ + @Override + protected Group[] getRoleSets() throws LoginException { + String username = getUsername(); + Connection conn = null; + HashMap setsMap = new HashMap(); + PreparedStatement ps = null; + ResultSet rs = null; - try { + try { - InitialContext ctx = new InitialContext(); - DataSource ds = (DataSource) ctx.lookup(this.dsJndiName); + InitialContext ctx = new InitialContext(); + DataSource ds = (DataSource) ctx.lookup(this.dsJndiName); - // log.debug("===> getRoleSets() called: " + dsJndiName + ": " + - // rolesQuery); - conn = ds.getConnection(); - // Get the user role names - ps = conn.prepareStatement(this.rolesQuery); - try { - ps.setString(1, username); - } catch (ArrayIndexOutOfBoundsException ignore) { - // The query may not have any parameters so just try it - } - rs = ps.executeQuery(); - if (rs.next() == false) { - if (getUnauthenticatedIdentity() == null) - throw new FailedLoginException( - "No matching username found in Roles"); - /* - * We are running with an unauthenticatedIdentity so create an - * empty Roles set and return. - */ - Group[] roleSets = { new SimpleGroup("Roles") }; - return roleSets; - } + // log.debug("===> getRoleSets() called: " + dsJndiName + ": " + + // rolesQuery); + conn = ds.getConnection(); + // Get the user role names + ps = conn.prepareStatement(this.rolesQuery); + try { + ps.setString(1, username); + } catch (ArrayIndexOutOfBoundsException ignore) { + // The query may not have any parameters so just try it + } + rs = ps.executeQuery(); + if (rs.next() == false) { + if (getUnauthenticatedIdentity() == null) { + throw new FailedLoginException("No matching username found in Roles"); + } + /* + * We are running with an unauthenticatedIdentity so create an + * empty Roles set and return. + */ + Group[] roleSets = { new SimpleGroup("Roles") }; + return roleSets; + } - ArrayList groupMembers = new ArrayList(); - do { - String name = rs.getString(1); - String groupName = rs.getString(2); - if (groupName == null || groupName.length() == 0) - groupName = "Roles"; - Group group = (Group) setsMap.get(groupName); - if (group == null) { - group = new SimpleGroup(groupName); - setsMap.put(groupName, group); - } + ArrayList groupMembers = new ArrayList(); + do { + String name = rs.getString(1); + String groupName = rs.getString(2); + if ((groupName == null) || (groupName.length() == 0)) { + groupName = "Roles"; + } + Group group = (Group) setsMap.get(groupName); + if (group == null) { + group = new SimpleGroup(groupName); + setsMap.put(groupName, group); + } - try { - Principal p; - // Assign minimal role if user has none - if (name == null) { - name = Role.LEARNER; - log.info("===> Found no roles"); - } - p = super.createIdentity(name); - if (!groupMembers.contains(name)) { - log.info("===> Assign user to role " + p.getName()); - group.addMember(p); - groupMembers.add(name); - } - if (name.equals(Role.SYSADMIN) - || name.equals(Role.AUTHOR_ADMIN)) { - p = super.createIdentity(Role.AUTHOR); - log.info("===> Found " + name); - if (!groupMembers.contains(Role.AUTHOR)) { - log.info("===> Assign user to role " + Role.AUTHOR); - group.addMember(p); - groupMembers.add(Role.AUTHOR); - } - } - } catch (Exception e) { - log.debug("===> Failed to create principal: " + name, e); - } - } while (rs.next()); - } catch (NamingException ex) { - throw new LoginException(ex.toString(true)); - } catch (SQLException ex) { - super.log.error("SQL failure", ex); - throw new LoginException(ex.toString()); - } finally { - if (rs != null) { - try { - rs.close(); - } catch (SQLException e) { - } + try { + Principal p; + // Assign minimal role if user has none + if (name == null) { + name = Role.LEARNER; + UniversalLoginModule.log.info("===> Found no roles"); + } + p = super.createIdentity(name); + if (!groupMembers.contains(name)) { + UniversalLoginModule.log.info("===> Assign user to role " + p.getName()); + group.addMember(p); + groupMembers.add(name); + } + if (name.equals(Role.SYSADMIN) || name.equals(Role.AUTHOR_ADMIN)) { + p = super.createIdentity(Role.AUTHOR); + UniversalLoginModule.log.info("===> Found " + name); + if (!groupMembers.contains(Role.AUTHOR)) { + UniversalLoginModule.log.info("===> Assign user to role " + Role.AUTHOR); + group.addMember(p); + groupMembers.add(Role.AUTHOR); } - if (ps != null) { - try { - ps.close(); - } catch (SQLException e) { - } - } - if (conn != null) { - try { - conn.close(); - } catch (Exception ex) { - } - } + } + } catch (Exception e) { + UniversalLoginModule.log.debug("===> Failed to create principal: " + name, e); } - - Group[] roleSets = new Group[setsMap.size()]; - setsMap.values().toArray(roleSets); - return roleSets; + } while (rs.next()); + } catch (NamingException ex) { + throw new LoginException(ex.toString(true)); + } catch (SQLException ex) { + super.log.error("SQL failure", ex); + throw new LoginException(ex.toString()); + } finally { + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + } + } + if (ps != null) { + try { + ps.close(); + } catch (SQLException e) { + } + } + if (conn != null) { + try { + conn.close(); + } catch (Exception ex) { + } + } } - /** - * 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 ""; - } + Group[] roleSets = new Group[setsMap.size()]; + setsMap.values().toArray(roleSets); + return roleSets; + } + /** + * 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 + */ + @Override + protected String getUsersPassword() throws LoginException { + return ""; + } + } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/commonContext.xml =================================================================== diff -u -rce9453335b5baf70c2ab13a11f0f3bb08cca7bb9 -r9da35349a62686e5112d5be703c9047c48d88467 --- lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision ce9453335b5baf70c2ab13a11f0f3bb08cca7bb9) +++ lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision 9da35349a62686e5112d5be703c9047c48d88467) @@ -55,6 +55,7 @@ PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED + PROPAGATION_REQUIRED PROPAGATION_REQUIRED Fisheye: Tag 9da35349a62686e5112d5be703c9047c48d88467 refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/integration/security/SingleSignOn.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoConsumer.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoConsumer.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoConsumer.java (revision 9da35349a62686e5112d5be703c9047c48d88467) @@ -0,0 +1,97 @@ +/** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + */ +package org.lamsfoundation.lams.integration.security; + +import io.undertow.security.api.AuthenticationMechanism; +import io.undertow.security.api.SecurityContext; +import io.undertow.security.idm.Account; +import io.undertow.security.impl.SecurityContextImpl; +import io.undertow.server.HttpServerExchange; +import io.undertow.servlet.ServletExtension; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.handlers.ServletRequestContext; + +import javax.servlet.ServletContext; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.lamsfoundation.lams.web.session.SessionManager; + +/** + * Allows access to LAMS WARs if an user logged in. It pulls out user Account from shared session and notifies security + * context that the user is already logged in. + * + * TODO: Always allow access for static content like images or JS files. It can be done by putting an URI check here or + * by adding an another auth mechanism in front of it. + * + * @author Marcin Cieslak + * + */ +public class SsoConsumer implements ServletExtension { + private final static String MECHANISM_NAME = "LAMS SSO"; + private final static String SSO_ATTRIBUTE_NAME = "ssoAccount"; + + @Override + public void handleDeployment(final DeploymentInfo deploymentInfo, final ServletContext servletContext) { + + // SSO goes first + deploymentInfo.addFirstAuthenticationMechanism(SsoConsumer.MECHANISM_NAME, new AuthenticationMechanism() { + + @Override + public AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange, SecurityContext sc) { + ServletRequestContext requestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + if (requestContext == null) { + return AuthenticationMechanismOutcome.NOT_ATTEMPTED; + } + + // get the account information + HttpServletRequest request = (HttpServletRequest) requestContext.getServletRequest(); + ServletResponse response = requestContext.getServletResponse(); + SessionManager.startSession(request, response); + HttpSession session = SessionManager.getSession(); + Account ssoAccount = session == null ? null : (Account) session + .getAttribute(SsoConsumer.SSO_ATTRIBUTE_NAME); + SessionManager.endSession(); + + if (ssoAccount != null) { + SecurityContextImpl securityContext = (SecurityContextImpl) sc; + Account account = securityContext.getAuthenticatedAccount(); + if (account == null) { + // Notify security context that the user is logged in. + // Do not cache it as the user would still be logged in the given WAR, + // even if he was logged out Central. + securityContext.authenticationComplete(ssoAccount, SsoConsumer.MECHANISM_NAME, false); + } + return AuthenticationMechanismOutcome.AUTHENTICATED; + } + + // Let other auth mechanisms do their checking + return AuthenticationMechanismOutcome.NOT_ATTEMPTED; + } + + @Override + public ChallengeResult sendChallenge(HttpServerExchange exchange, SecurityContext securityContext) { + return new ChallengeResult(false); + } + }); + } +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoProducer.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoProducer.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoProducer.java (revision 9da35349a62686e5112d5be703c9047c48d88467) @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + */ +package org.lamsfoundation.lams.integration.security; + +import io.undertow.Handlers; +import io.undertow.security.idm.Account; +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.servlet.ServletExtension; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.handlers.ServletRequestContext; + +import javax.servlet.ServletContext; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.lamsfoundation.lams.web.session.SessionManager; + +/** + * Allows access to LAMS WARs if an user logged in. It puts user Account into shared session so SsoConsumer in other + * WARs can use it. + * + * @author Marcin Cieslak + * + */ +public class SsoProducer implements ServletExtension { + private final static String SSO_ATTRIBUTE_NAME = "ssoAccount"; + + @Override + public void handleDeployment(final DeploymentInfo deploymentInfo, final ServletContext servletContext) { + + // run when request and response were already parsed, but before security handlers + deploymentInfo.addOuterHandlerChainWrapper(new HandlerWrapper() { + @Override + public HttpHandler wrap(final HttpHandler handler) { + // just forward all requests except one for logging in + return Handlers.path().addPrefixPath("/", handler).addExactPath("/j_security_check", new HttpHandler() { + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + ServletRequestContext context = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + HttpServletRequest request = (HttpServletRequest) context.getServletRequest(); + ServletResponse response = context.getServletResponse(); + + // create session so UniversalLoginModule can access it + SessionManager.startSession(request, response); + // do the logging in UniversalLoginModule + handler.handleRequest(exchange); + + HttpSession session = SessionManager.getSession(); + // get the just-logged-in user account and put it in the shared session + Account account = exchange.getSecurityContext().getAuthenticatedAccount(); + session.setAttribute(SsoProducer.SSO_ATTRIBUTE_NAME, account); + + SessionManager.endSession(); + } + }); + } + }); + } +} \ No newline at end of file Index: lams_www/build.xml =================================================================== diff -u -r088dbcf441a1443c55042ca298850077bdee7028 -r9da35349a62686e5112d5be703c9047c48d88467 --- lams_www/build.xml (.../build.xml) (revision 088dbcf441a1443c55042ca298850077bdee7028) +++ lams_www/build.xml (.../build.xml) (revision 9da35349a62686e5112d5be703c9047c48d88467) @@ -29,8 +29,7 @@ + depends="_clean-dirs, _build-manifest, _copy-war-resources, _jsp-plaincopy, _jsp-precompile, _add-sso"> ${ant.project.name}: Building WAR