Index: lams_central/src/java/org/lamsfoundation/lams/web/ShibLearnerServlet.java =================================================================== RCS file: /usr/local/cvsroot/lams_central/src/java/org/lamsfoundation/lams/web/Attic/ShibLearnerServlet.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- lams_central/src/java/org/lamsfoundation/lams/web/ShibLearnerServlet.java 18 Jul 2007 02:49:19 -0000 1.1.2.3 +++ lams_central/src/java/org/lamsfoundation/lams/web/ShibLearnerServlet.java 20 Jul 2007 02:58:53 -0000 1.1.2.4 @@ -1,5 +1,22 @@ /** - * + * 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.web; @@ -36,49 +53,38 @@ private static ILessonService lessonService; private static IFederationService fedService; - private ILessonService getLessonService(){ - if(lessonService==null){ - WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); + if(lessonService==null){ lessonService = (ILessonService) ctx.getBean("lessonService"); } - return lessonService; - } - - private IUserManagementService getService(){ if(service==null){ - WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); service = (IUserManagementService) ctx.getBean("userManagementServiceTarget"); } - return service; - } - - private IFederationService getFedService(){ if(fedService==null){ - WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); fedService = (IFederationService) ctx.getBean("federationService"); } - return fedService; - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { String lessonIdStr = request.getParameter("lessonID"); Long lessonId = Long.parseLong(lessonIdStr); - // add this shib user to lesson if they have learner role and are not already a member String roles = request.getHeader(Configuration.get(ConfigurationKeys.SHIB_ATTR_ROLES)); String username = request.getHeader(Configuration.get(ConfigurationKeys.SHIB_ATTR_LOGIN)); - String identityProvider = request.getHeader("Shib-Identity-Provider"); + String originServerURL = request.getHeader(Configuration.get(ConfigurationKeys.SHIB_ATTR_SERVER_URL)); + + // add this shib user to lesson if they have learner role and are not already a member + // TODO check this shib user's fed server id and org id against this server's shared lessons in lams_fed_lesson User user = null; if (roles != null && roles.indexOf(Role.LEARNER)>0) { try { - String localUsername = getFedService().getLocalUsername(username, identityProvider); - user = getService().getUserByLogin(localUsername); + String localUsername = fedService.getLocalUsername(username, originServerURL); + user = service.getUserByLogin(localUsername); } catch (Exception e) { log.error("Couldn't get local user from shib username "+username); } - Lesson lesson = lessonId != null ? getLessonService().getLesson(lessonId) : null; + Lesson lesson = lessonId != null ? lessonService.getLesson(lessonId) : null; if (lesson != null) { LessonClass lessonClass = lesson.getLessonClass(); if (user != null && lessonClass != null && !lessonClass.getLearners().contains(user)) { Index: lams_central/src/java/org/lamsfoundation/lams/web/ShibLoginServlet.java =================================================================== RCS file: /usr/local/cvsroot/lams_central/src/java/org/lamsfoundation/lams/web/Attic/ShibLoginServlet.java,v diff -u -r1.1.2.9 -r1.1.2.10 --- lams_central/src/java/org/lamsfoundation/lams/web/ShibLoginServlet.java 17 Jul 2007 05:36:22 -0000 1.1.2.9 +++ lams_central/src/java/org/lamsfoundation/lams/web/ShibLoginServlet.java 20 Jul 2007 02:58:53 -0000 1.1.2.10 @@ -21,8 +21,10 @@ package org.lamsfoundation.lams.web; import java.io.IOException; +import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; +import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -31,13 +33,20 @@ import org.apache.log4j.Logger; import org.lamsfoundation.lams.federation.FederationException; -import org.lamsfoundation.lams.federation.FederationServer; import org.lamsfoundation.lams.federation.service.IFederationService; import org.lamsfoundation.lams.usermanagement.AuthenticationMethod; +import org.lamsfoundation.lams.usermanagement.Organisation; +import org.lamsfoundation.lams.usermanagement.OrganisationState; +import org.lamsfoundation.lams.usermanagement.OrganisationType; +import org.lamsfoundation.lams.usermanagement.Role; import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.service.UserManagementService; +import org.lamsfoundation.lams.util.CentralConstants; import org.lamsfoundation.lams.util.Configuration; import org.lamsfoundation.lams.util.ConfigurationKeys; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.audit.IAuditService; +import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; /** @@ -49,19 +58,19 @@ private static Logger log = Logger.getLogger(ShibLoginServlet.class); private static UserManagementService service = null; private static IFederationService fedService = null; + private static final String MAGIC_PASSWD = "dummy"; + private static final String SHIB_ORG_NAME = "Shibboleth Users"; + private static final String SHIB_ORG_DESC = "This group acts as a hidden container for shibboleth users."; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); if (service == null) { - service = (UserManagementService)WebApplicationContextUtils - .getRequiredWebApplicationContext(getServletContext()).getBean("userManagementServiceTarget"); + service = (UserManagementService)ctx.getBean("userManagementServiceTarget"); } - if (fedService == null) { - fedService = (IFederationService)WebApplicationContextUtils - .getRequiredWebApplicationContext(getServletContext()) - .getBean("federationService"); + fedService = (IFederationService)ctx.getBean("federationService"); } // debug request headers @@ -70,68 +79,54 @@ String header = (String)headers.nextElement(); log.debug("Request header: "+header+" has value: "+request.getHeader(header)); } - log.debug("request.getPathInfo: "+request.getPathInfo()); - log.debug("request.getContextPath: "+request.getContextPath()); // get shib attributes based on sysadmin's configuration of shib header names String username = request.getHeader(Configuration.get(ConfigurationKeys.SHIB_ATTR_LOGIN)); String firstname = request.getHeader(Configuration.get(ConfigurationKeys.SHIB_ATTR_FNAME)); String lastname = request.getHeader(Configuration.get(ConfigurationKeys.SHIB_ATTR_LNAME)); String roles = request.getHeader(Configuration.get(ConfigurationKeys.SHIB_ATTR_ROLES)); - // this attribute included by default on all protected resources; is the providerId of the IdP - String identityProvider = request.getHeader("Shib-Identity-Provider"); + String originServerURL = request.getHeader(Configuration.get(ConfigurationKeys.SHIB_ATTR_SERVER_URL)); if (username != null && username.trim().length()>0) { - // prefix new usernames with their origin server's fedId so as not to mix up with local usernames - String prefixedUsername = null; + // prefix new usernames with their origin server's fedId if necessary, + // so as not to mix up with local usernames + String localUsername = null; try { - prefixedUsername = fedService.getLocalUsername(username, identityProvider); + localUsername = fedService.getLocalUsername(username, originServerURL); } catch (FederationException e) { + log.error("Couldn't get local username for shib user "+username, e); flagError(request, response); } - if (prefixedUsername == null) { + if (localUsername == null) { + log.error("Couldn't get local username for shib user "+username); flagError(request, response); } - User user = service.getUserByLogin(prefixedUsername); + User user = service.getUserByLogin(localUsername); if (user != null) { - // user is already authenticated by Shibboleth IdP - log.info("Found account for shibboleth user "+username+", logging them in..."); - response.sendRedirect("j_security_check?j_username="+prefixedUsername+"&j_password="+user.getPassword()); + // TODO update user attributes if changed + log.info("Found account for shibboleth user "+localUsername+"..."); } else { - // create user account for new shib user; try { - log.info("Creating new user: "+prefixedUsername); - user = new User(); - user.setLogin(prefixedUsername); - user.setPassword("dummy"); - if (firstname != null && firstname.trim().length()>0) { - user.setFirstName(firstname); - } else { - user.setFirstName(username); - } - if (lastname != null && lastname.trim().length()>0) { - user.setLastName(lastname); - } else { - user.setLastName(username); - } - user.setEmail(username); - user.setAuthenticationMethod((AuthenticationMethod) - service.findById(AuthenticationMethod.class, AuthenticationMethod.DB)); - user.setChangePassword(false); - user.setDisabledFlag(false); - user.setLocale(service.getDefaultLocale()); - user.setFlashTheme(service.getDefaultFlashTheme()); - user.setHtmlTheme(service.getDefaultHtmlTheme()); - user.setCreateDate(new Date()); - service.save(user); - - response.sendRedirect("j_security_check?j_username="+username+"&j_password=dummy"); + log.info("Creating new user: "+localUsername); + user = saveNewUser(localUsername, firstname, lastname); } catch (Exception e) { - log.error("Couldn't save new user with username: "+prefixedUsername); + log.error("Couldn't save new user with username: "+localUsername, e); flagError(request, response); } } + int shibOrgId = Configuration.getAsInt(ConfigurationKeys.SHIB_ORG_ID); + Organisation org = getShibbolethOrganisation(shibOrgId); + + try { + log.info("Updating "+localUsername+"'s roles using current shibboleth attributes..."); + List roleIdList = getRoleIds(roles); + service.setRolesForUserOrganisation(user, org, roleIdList); + } catch (Exception e) { + log.error("Couldn't update "+localUsername+"'s roles.", e); + } + + response.sendRedirect("j_security_check?j_username="+localUsername+"&j_password="+MAGIC_PASSWD); } else { // somehow lost shib username attribute, send back to login page log.error("Couldn't get a username from shibboleth header: "+Configuration.get(ConfigurationKeys.SHIB_ATTR_LOGIN)); @@ -143,5 +138,95 @@ request.getSession().setAttribute("shibLoginError", "true"); response.sendRedirect("/lams/"); } + + // returns shibboleth group as specified by ShibOrgId configuration parameter + private Organisation getShibbolethOrganisation(int shibOrgId) { + Organisation org; + if (shibOrgId <= 0) { + log.info("Creating new organisation for shibboleth users..."); + org = saveNewShibOrg(); + } else { + org = (Organisation)service.findById(Organisation.class, new Integer(shibOrgId)); + } + return org; + } + + // create new User for shibboleth user; should be given a local username for this server + private User saveNewUser(String username, String fname, String lname) { + User user = new User(); + user.setLogin(username); + user.setPassword(MAGIC_PASSWD); + if (fname != null && fname.trim().length()>0) { + user.setFirstName(fname); + } else { + user.setFirstName(username); + } + if (lname != null && lname.trim().length()>0) { + user.setLastName(lname); + } else { + user.setLastName(username); + } + // TODO use other shib attributes + user.setEmail(username); + user.setAuthenticationMethod((AuthenticationMethod) + service.findById(AuthenticationMethod.class, AuthenticationMethod.DB)); + user.setChangePassword(false); + user.setDisabledFlag(false); + user.setLocale(service.getDefaultLocale()); + user.setFlashTheme(service.getDefaultFlashTheme()); + user.setHtmlTheme(service.getDefaultHtmlTheme()); + user.setCreateDate(new Date()); + service.save(user); + return user; + } + + // create new hidden group to contain shib user's roles + private Organisation saveNewShibOrg() { + Organisation org = new Organisation(); + try { + org = new Organisation(); + org.setName(SHIB_ORG_NAME); + org.setDescription(SHIB_ORG_DESC); + org.setParentOrganisation(service.getRootOrganisation()); + org.setOrganisationType((OrganisationType) + service.findById(OrganisationType.class, OrganisationType.COURSE_TYPE)); + org.setOrganisationState((OrganisationState) + service.findById(OrganisationState.class, OrganisationState.HIDDEN)); + org.setLocale(service.getDefaultLocale()); + org = service.saveOrganisation(org, new Integer(1)); + writeAuditLog(org); + Configuration.updateItem(ConfigurationKeys.SHIB_ORG_ID, org.getOrganisationId().toString()); + } catch (Exception e) { + log.error("Couldn't save new organisation: ", e); + } + return org; + } + + private void writeAuditLog(Organisation org) { + WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); + IAuditService auditService = (IAuditService) ctx.getBean("auditService"); + MessageService messageService = (MessageService)ctx.getBean("centralMessageService"); + String[] args = new String[2]; + args[0] = org.getName()+"("+org.getOrganisationId()+")"; + args[1] = org.getOrganisationType().getName(); + String message = messageService.getMessage("audit.organisation.create", args); + auditService.log(CentralConstants.MODULE_NAME, message); + } + + // given string like 'LEARNER;MONITOR;AUTHOR', returns role ids + private List getRoleIds(String roles) { + String[] roleNames = roles.split(";"); + ArrayList roleIds = new ArrayList(); + for (String roleName : roleNames) { + Role role = (Role)service.findByProperty(Role.class, "name", roleName); + if (role != null) { + roleIds.add(role.getRoleId().toString()); + } else { + log.warn("Encountered invalid role name: "+roleName); + continue; + } + } + return roleIds; + } } \ No newline at end of file Index: lams_central/web/includes/javascript/openUrls.js =================================================================== RCS file: /usr/local/cvsroot/lams_central/web/includes/javascript/openUrls.js,v diff -u -r1.20.2.4 -r1.20.2.5 --- lams_central/web/includes/javascript/openUrls.js 17 Jul 2007 03:02:03 -0000 1.20.2.4 +++ lams_central/web/includes/javascript/openUrls.js 20 Jul 2007 02:58:53 -0000 1.20.2.5 @@ -163,14 +163,11 @@ } } - function openFedLearner( lessonId, fedServer, handler, entityId ) + function openFedLearner( lessonId, fedServerHost, localIdPHandler, providerId ) { - var target = fedServer+'/lams/shiblearner?lessonID='+lessonId; - var shire = fedServer+'/Shibboleth.sso/SAML/POST'; - // direct to IdP - var url = handler+'?target='+target+'&shire='+shire+'&providerId='+entityId; - // SP first - //var url = fedServer+'/Shibboleth.sso/Lazy?target='+target+'&providerId='+entityId; + var target = fedServerHost+'/lams/shiblearner?lessonID='+lessonId; + var shire = fedServerHost+'/Shibboleth.sso/SAML/POST'; + var url = localIdPHandler+'?target='+target+'&shire='+shire+'&providerId='+providerId; if(isMac) { Index: lams_common/db/sql/insert_lams_unix_config_data.sql =================================================================== RCS file: /usr/local/cvsroot/lams_common/db/sql/insert_lams_unix_config_data.sql,v diff -u -r1.6.2.3 -r1.6.2.4 --- lams_common/db/sql/insert_lams_unix_config_data.sql 12 Jul 2007 02:53:12 -0000 1.6.2.3 +++ lams_common/db/sql/insert_lams_unix_config_data.sql 20 Jul 2007 02:58:53 -0000 1.6.2.4 @@ -36,8 +36,10 @@ insert into lams_configuration (config_key, config_value) values ('ShibAttrFname','LAMS-Login'); insert into lams_configuration (config_key, config_value) values ('ShibAttrLname','LAMS-Login'); insert into lams_configuration (config_key, config_value) values ('ShibAttrRoles','LAMS-Roles'); +insert into lams_configuration (config_key, config_value) values ('ShibAttrServerURL','LAMS-ServerURL'); insert into lams_configuration (config_key, config_value) values ('FedRegistryURL','http://192.168.111.55:8081'); insert into lams_configuration (config_key, config_value) values ('FedKey','blah'); insert into lams_configuration (config_key, config_value) values ('ShibIdPSSOHandler','https://olive.lamsfoundation.org/shibboleth-idp/SSO'); insert into lams_configuration (config_key, config_value) values ('ShibIdPEntityId','https://olive.lamsfoundation.org/shibboleth'); -insert into lams_configuration (config_key, config_value) values ('ShibEnabled','true'); \ No newline at end of file +insert into lams_configuration (config_key, config_value) values ('ShibEnabled','true'); +insert into lams_configuration (config_key, config_value) values ('ShibOrgId',''); \ No newline at end of file Index: lams_common/db/sql/insert_lams_windows_config_data.sql =================================================================== RCS file: /usr/local/cvsroot/lams_common/db/sql/insert_lams_windows_config_data.sql,v diff -u -r1.3.2.3 -r1.3.2.4 --- lams_common/db/sql/insert_lams_windows_config_data.sql 12 Jul 2007 02:53:12 -0000 1.3.2.3 +++ lams_common/db/sql/insert_lams_windows_config_data.sql 20 Jul 2007 02:58:53 -0000 1.3.2.4 @@ -36,8 +36,10 @@ insert into lams_configuration (config_key, config_value) values ('ShibAttrFname','LAMS-Login'); insert into lams_configuration (config_key, config_value) values ('ShibAttrLname','LAMS-Login'); insert into lams_configuration (config_key, config_value) values ('ShibAttrRoles','LAMS-Roles'); +insert into lams_configuration (config_key, config_value) values ('ShibAttrServerURL','LAMS-ServerURL'); insert into lams_configuration (config_key, config_value) values ('FedRegistryURL','http://192.168.111.55:8081'); insert into lams_configuration (config_key, config_value) values ('FedKey','blah'); insert into lams_configuration (config_key, config_value) values ('ShibIdPSSOHandler','https://olive.lamsfoundation.org/shibboleth-idp/SSO'); insert into lams_configuration (config_key, config_value) values ('ShibIdPEntityId','https://olive.lamsfoundation.org/shibboleth'); insert into lams_configuration (config_key, config_value) values ('ShibEnabled','true'); +insert into lams_configuration (config_key, config_value) values ('ShibOrgId',''); Index: lams_common/src/java/org/lamsfoundation/lams/federation/service/FederationService.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/federation/service/Attic/FederationService.java,v diff -u -r1.1.2.10 -r1.1.2.11 --- lams_common/src/java/org/lamsfoundation/lams/federation/service/FederationService.java 17 Jul 2007 05:36:22 -0000 1.1.2.10 +++ lams_common/src/java/org/lamsfoundation/lams/federation/service/FederationService.java 20 Jul 2007 02:58:53 -0000 1.1.2.11 @@ -376,8 +376,8 @@ } // produces a local version of shibboleth user's username; it is prefixed by the fedId of their origin server - public String getLocalUsername(String username, String providerId) throws FederationException { - String host = getHost(providerId); + public String getLocalUsername(String username, String originServerURL) throws FederationException { + String host = getHost(originServerURL); // check if user is from local server if (host.equals(getHost(Configuration.get(ConfigurationKeys.SERVER_URL)))) { log.info("Shibboleth user "+username+" appears to be a local user."); Index: lams_common/src/java/org/lamsfoundation/lams/util/ConfigurationKeys.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/util/ConfigurationKeys.java,v diff -u -r1.23.2.5 -r1.23.2.6 --- lams_common/src/java/org/lamsfoundation/lams/util/ConfigurationKeys.java 12 Jul 2007 02:53:11 -0000 1.23.2.5 +++ lams_common/src/java/org/lamsfoundation/lams/util/ConfigurationKeys.java 20 Jul 2007 02:58:53 -0000 1.23.2.6 @@ -141,6 +141,8 @@ public static String SHIB_ATTR_LNAME = "ShibAttrLname"; + public static String SHIB_ATTR_SERVER_URL = "ShibAttrServerURL"; + public static String FED_REGISTRY_URL = "FedRegistryURL"; public static String FED_KEY = "FedKey"; @@ -152,4 +154,6 @@ public static String SHIB_IDP_ENTITY_ID = "ShibIdPEntityId"; public static String SHIB_ENABLED = "ShibEnabled"; + + public static String SHIB_ORG_ID = "ShibOrgId"; } \ No newline at end of file