diff --git a/src/main/java/org/olat/course/condition/AttributeEasyRowAdderController.java b/src/main/java/org/olat/course/condition/AttributeEasyRowAdderController.java index e7ec04dd46b6734dbee4aaea24a1a0b8d980f4b2..900e383aecd807b827e9ec8fbd04f6394bb18444 100644 --- a/src/main/java/org/olat/course/condition/AttributeEasyRowAdderController.java +++ b/src/main/java/org/olat/course/condition/AttributeEasyRowAdderController.java @@ -64,7 +64,7 @@ import org.springframework.beans.factory.annotation.Autowired; * A subform that implement the shibboleth easy mode config rows. * <P> * Initial Date: 23.10.2006 <br> - * + * * @author Lars Eberle (<a href="http://www.bps-system.de/">BPS Bildungsportal Sachsen GmbH</a>) * @author Florian Gnägi (<a href="http://www.frentix.com/">frentix GmbH</a>) */ @@ -96,13 +96,13 @@ public class AttributeEasyRowAdderController extends FormBasicController { private int rowCreationCounter = 0; // private boolean isinit = false; - + @Autowired private ShibbolethModule shibbolethModule; /** * Constructor for a shibboleth attribute rule creator form. - * + * * @param ureq * @param wControl * @param parentForm @@ -113,7 +113,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { setTranslator(Util.createPackageTranslator(ShibbolethModule.class, ureq.getLocale(), getTranslator())); attributeTranslator = shibbolethModule.getAttributeTranslator(); attrKeys = getShibAttributes(); - preselectedAttribute = shibbolethModule.getPreselectedAttributeKey(ShibbolethModule.CONF_OLATUSERMAPPING_INSTITUTIONALNAME); + preselectedAttribute = shibbolethModule.getPreselectedAttributeKey(shibbolethModule.getShibbolethAttributeName(UserConstants.INSTITUTIONALNAME)); preselectedAttributeValue = ureq.getIdentity().getUser().getProperty(UserConstants.INSTITUTIONALNAME, getLocale()); operatorKeys = OperatorManager.getRegisteredOperatorKeys(shibbolethModule.getOperatorKeys()); this.init(); @@ -121,7 +121,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Constructor for a log attribute rule creator form. - * + * * @param ureq * @param wControl * @param parentForm @@ -262,7 +262,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Internal helper to get the current row count - * + * * @return */ private int getRowCount() { @@ -275,7 +275,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Method to get a list of extended conditions represented in this form - * + * * @return */ public List<ExtendedCondition> getAttributeConditions() { @@ -307,7 +307,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Method to initialize this form with the given extended conditions - * + * * @param cond */ public void setAttributeConditions(final List<ExtendedCondition> cond) { @@ -339,7 +339,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Internal method to add a new row at the given position - * + * * @param i */ private void addRowAt(final int rowPos) { @@ -437,7 +437,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Internal method to remove the row at the given position. - * + * * @param clickPos The row to be removed */ private void removeRowAt(final int clickPos) { @@ -475,7 +475,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Internal method to update a row's value element. This can be a text input box or a selection drop down depending on the shibboleth module configuration and the selected attribute. The method * will set the given value as the users selected / inputed value - * + * * @param attribute The attribute key. Must not be NULL * @param row the row ID * @param value The value that should be selected / used in the text input field. Can be NULL. @@ -558,7 +558,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Internal helper to create a sting array that contains all shibboleth attributes that can be selected in the drop down - * + * * @return String[] - will never returh null */ private String[] getShibAttributes() { @@ -578,7 +578,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Checks if this form produces an error - * + * * @return true: has an error; false: is valid */ public boolean hasError() { @@ -592,7 +592,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Get the form item that forms this subform - * + * * @return */ public FormItem getFormItem() { diff --git a/src/main/java/org/olat/shibboleth/ShibbolethDispatcher.java b/src/main/java/org/olat/shibboleth/ShibbolethDispatcher.java index 4f07968e8cdea31cba85ba7850696b28aa2e23d7..cbb6c66860da2ddf7bd23d8f692416c1ba9a2195 100644 --- a/src/main/java/org/olat/shibboleth/ShibbolethDispatcher.java +++ b/src/main/java/org/olat/shibboleth/ShibbolethDispatcher.java @@ -51,7 +51,6 @@ import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.media.RedirectMediaResource; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; -import org.olat.core.id.User; import org.olat.core.id.UserConstants; import org.olat.core.logging.AssertException; import org.olat.core.logging.OLATRuntimeException; @@ -65,8 +64,7 @@ import org.olat.core.util.WebappHelper; import org.olat.core.util.i18n.I18nModule; import org.olat.restapi.security.RestSecurityBean; import org.olat.shibboleth.util.ShibbolethAttribute; -import org.olat.shibboleth.util.ShibbolethHelper; -import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; /** * Initial Date: 17.07.2004 @@ -74,22 +72,24 @@ import org.olat.user.UserManager; * @author Mike Stock */ public class ShibbolethDispatcher implements Dispatcher{ - + private static final OLog log = Tracing.createLoggerFor(ShibbolethDispatcher.class); /** Provider identifier */ public static final String PROVIDER_SHIB = "Shib"; /** Identifies requests for the ShibbolethDispatcher */ public static final String PATH_SHIBBOLETH = "/shib/"; - + private Translator translator; private boolean mobile = false; private BaseSecurity securityManager; private ShibbolethModule shibbolethModule; private RestSecurityBean restSecurityBean; private UserDeletionManager userDeletionManager; - - + + @Autowired + private ShibbolethManager shibbolethManager; + /** * [used by Spring] * @param mobile @@ -97,7 +97,7 @@ public class ShibbolethDispatcher implements Dispatcher{ public void setMobile(boolean mobile) { this.mobile = mobile; } - + /** * [used by Spring] * @param shibbolethModule @@ -105,7 +105,7 @@ public class ShibbolethDispatcher implements Dispatcher{ public void setShibbolethModule(ShibbolethModule shibbolethModule) { this.shibbolethModule = shibbolethModule; } - + /** * [used by Spring] * @param restSecurityBean @@ -113,7 +113,7 @@ public class ShibbolethDispatcher implements Dispatcher{ public void setRestSecurityBean(RestSecurityBean restSecurityBean) { this.restSecurityBean = restSecurityBean; } - + /** * [used by Spring] * @param securityManager @@ -133,7 +133,7 @@ public class ShibbolethDispatcher implements Dispatcher{ /** * Main method called by OpenOLATServlet. * This processess all shibboleth requests. - * + * * @param req * @param resp * @param uriPrefix @@ -152,21 +152,21 @@ public class ShibbolethDispatcher implements Dispatcher{ throw new AssertException("UTF-8 encoding not supported!!!!"); } String uriPrefix = DispatcherModule.getLegacyUriPrefix(req); - uri = uri.substring(uriPrefix.length()); // guaranteed to exist by DispatcherAction - + uri = uri.substring(uriPrefix.length()); // guaranteed to exist by DispatcherAction + Map<String, String> attributesMap = getShibbolethAttributesFromRequest(req); String uniqueID = getUniqueIdentifierFromRequest(req, resp, attributesMap); if(uniqueID == null) { return; } - + if(!authorization(req, resp, attributesMap)) { return; } UserRequest ureq = null; try{ - //upon creation URL is checked for + //upon creation URL is checked for ureq = new UserRequestImpl(uriPrefix, req, resp); } catch(NumberFormatException nfe) { //MODE could not be decoded @@ -181,7 +181,7 @@ public class ShibbolethDispatcher implements Dispatcher{ DispatcherModule.sendBadRequest(req.getPathInfo(), resp); return; } - + Authentication auth = securityManager.findAuthenticationByAuthusername(uniqueID, PROVIDER_SHIB); if (auth == null) { // no matching authentication... ShibbolethRegistrationController.putShibAttributes(req, attributesMap); @@ -202,37 +202,17 @@ public class ShibbolethDispatcher implements Dispatcher{ } return; } - - // successfull login - userDeletionManager.setIdentityAsActiv(ureq.getIdentity()); - ureq.getUserSession().getIdentityEnvironment().addAttributes( - shibbolethModule.getAttributeTranslator().translateAttributesMap(attributesMap)); - // update user attributes + // Successful login Identity authenticationedIdentity = ureq.getIdentity(); - User user = authenticationedIdentity.getUser(); - String s = attributesMap.get(shibbolethModule.getFirstName()); - if (s != null) user.setProperty(UserConstants.FIRSTNAME, s); - s = attributesMap.get(shibbolethModule.getLastName()); - if (s != null) user.setProperty(UserConstants.LASTNAME, s); - s = attributesMap.get(shibbolethModule.getInstitutionalName()); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALNAME, s); - s = ShibbolethHelper.getFirstValueOf(shibbolethModule.getInstitutionalEMail(), attributesMap); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALEMAIL, s); - s = attributesMap.get(shibbolethModule.getInstitutionalUserIdentifier()); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALUSERIDENTIFIER, s); - // Optional organization unit property - String orgUnitIdent = shibbolethModule.getOrgUnit(); - if(orgUnitIdent != null) { - s = ShibbolethHelper.getFirstValueOf(orgUnitIdent, attributesMap); - if (s != null) user.setProperty(UserConstants.ORGUNIT, s); - } - UserManager.getInstance().updateUser(user); + userDeletionManager.setIdentityAsActiv(authenticationedIdentity); + shibbolethManager.syncUser(authenticationedIdentity, attributesMap); + ureq.getUserSession().getIdentityEnvironment().addAttributes( + shibbolethModule.getAttributeTranslator().translateAttributesMap(attributesMap)); - if(mobile) { String token = restSecurityBean.generateToken(ureq.getIdentity(), ureq.getHttpReq().getSession(true)); - + try { resp.sendRedirect(WebappHelper.getServletContextPath() + "/mobile?x-olat-token=" + token + "&username=" + ureq.getIdentity().getName()); } catch (IOException e) { @@ -251,13 +231,13 @@ public class ShibbolethDispatcher implements Dispatcher{ private String getUniqueIdentifierFromRequest(HttpServletRequest req, HttpServletResponse resp, Map<String, String> attributesMap) { - String uniqueID = attributesMap.get(shibbolethModule.getDefaultUIDAttribute()); - if (uniqueID == null) { - handleException(new ShibbolethException(ShibbolethException.UNIQUE_ID_NOT_FOUND,"Unable to get unique identifier for subject. Make sure you are listed in the metadata.xml file and your resources your are trying to access are available and your are allowed to see them. (Resourceregistry). "), + String uniqueID = attributesMap.get(shibbolethModule.getDefaultUIDAttribute()); + if (uniqueID == null) { + handleException(new ShibbolethException(ShibbolethException.UNIQUE_ID_NOT_FOUND,"Unable to get unique identifier for subject. Make sure you are listed in the metadata.xml file and your resources your are trying to access are available and your are allowed to see them. (Resourceregistry). "), req, resp, translator); return null; } else if (!checkAttributes(attributesMap)) { - handleException(new ShibbolethException(ShibbolethException.INSUFFICIENT_ATTRIBUTES,"Insufficient shibboleth attributes!"), + handleException(new ShibbolethException(ShibbolethException.INSUFFICIENT_ATTRIBUTES,"Insufficient shibboleth attributes!"), req, resp, translator); return null; } @@ -266,27 +246,27 @@ public class ShibbolethDispatcher implements Dispatcher{ private Map<String, String> getShibbolethAttributesFromRequest(HttpServletRequest req) { Set<String> translateableAttributes = shibbolethModule.getAttributeTranslator().getTranslateableAttributes(); - Map<String, String> attributesMap = new HashMap<String, String>(); + Map<String, String> attributesMap = new HashMap<>(); Enumeration<String> headerEnum = req.getHeaderNames(); while(headerEnum.hasMoreElements()) { String attribute = headerEnum.nextElement(); String attributeValue = req.getHeader(attribute); - + ShibbolethAttribute shibbolethAttribute = ShibbolethAttribute.createFromUserRequestValue(attribute, attributeValue); - - boolean validAndTranslateableAttribute = shibbolethAttribute.isValid() && translateableAttributes.contains(shibbolethAttribute.getName()); + + boolean validAndTranslateableAttribute = shibbolethAttribute.isValid() && translateableAttributes.contains(shibbolethAttribute.getName()); if(validAndTranslateableAttribute){ attributesMap.put(shibbolethAttribute.getName(),shibbolethAttribute.getValueString()); } } - + if(log.isDebug()){ log.debug("Shib attribute Map: \n\n"+attributesMap.toString()+"\n\n"); } - + return attributesMap; } - + /** * Check if all required attributes are here. * @param attributesMap @@ -297,14 +277,12 @@ public class ShibbolethDispatcher implements Dispatcher{ return false; } try { - String lastname = attributesMap.get(shibbolethModule.getLastName()); - String firstname = attributesMap.get(shibbolethModule.getFirstName()); - String email = ShibbolethHelper.getFirstValueOf(shibbolethModule.getEMail(), attributesMap); - String institutionalEMail = ShibbolethHelper.getFirstValueOf(shibbolethModule.getInstitutionalEMail(), attributesMap); - String institutionalName = attributesMap.get(shibbolethModule.getInstitutionalName()); - //String institutionalUserIdentifier = userMapping.getInstitutionalUserIdentifier(); - if(lastname!=null && !lastname.equals("") && firstname!=null && !firstname.equals("") && email!=null && !email.equals("") && - institutionalEMail!=null && !institutionalEMail.equals("") && institutionalName!=null && !institutionalName.equals("")) { + String lastname = attributesMap.get(shibbolethModule.getShibbolethAttributeName(UserConstants.LASTNAME)); + String firstname = attributesMap.get(shibbolethModule.getShibbolethAttributeName(UserConstants.FIRSTNAME)); + String email = attributesMap.get(shibbolethModule.getShibbolethAttributeName(UserConstants.EMAIL)); + if (StringHelper.containsNonWhitespace(lastname) + && StringHelper.containsNonWhitespace(firstname) + && StringHelper.containsNonWhitespace(email)) { return true; } } catch (IllegalArgumentException e) { @@ -320,7 +298,7 @@ public class ShibbolethDispatcher implements Dispatcher{ log.error("Redirect failed: url=" + WebappHelper.getServletContextPath() + DispatcherModule.getPathDefault(),e); } } - + private boolean authorization(HttpServletRequest req, HttpServletResponse resp, Map<String,String> attributesMap) { boolean authorized = false; if(shibbolethModule.isAccessControlByAttributes()) { @@ -333,16 +311,16 @@ public class ShibbolethDispatcher implements Dispatcher{ } else { authorized = true; } - + if(!authorized) { UserRequest ureq = new UserRequestImpl(ShibbolethDispatcher.PATH_SHIBBOLETH, req, resp); - String userMsg = translator.translate("error.shibboleth.not.authorized"); + String userMsg = translator.translate("error.shibboleth.not.authorized"); ChiefController msgcc = MessageWindowController.createMessageChiefController(ureq, null, userMsg, null); msgcc.getWindow().dispatchRequest(ureq, true); } return authorized; } - + private boolean authorization(String attribute, String allowedValues, Map<String,String> attributesMap) { String val = attributesMap.get(attribute); if(StringHelper.containsNonWhitespace(val)) { @@ -351,23 +329,23 @@ public class ShibbolethDispatcher implements Dispatcher{ String allowedValue = tokenizer.nextToken().trim(); if(val.equalsIgnoreCase(allowedValue)) { return true; - } + } // Could be multi-field attribute. Check for semi-colon delimited encodings String[] multiValues = val.split(";"); for (String singleValue : multiValues) { singleValue = singleValue.trim(); if(singleValue.equalsIgnoreCase(allowedValue)) { return true; - } + } } - } + } } return false; } /** * It first tries to catch the frequent SAMLExceptions and to ask the user to login again. - * It basically lets the user to login again without getting a RedScreen if one of the most + * It basically lets the user to login again without getting a RedScreen if one of the most * frequent shibboleth error occurs. Else a RedScreen is the last option. * @param e * @param req @@ -375,19 +353,19 @@ public class ShibbolethDispatcher implements Dispatcher{ */ private void handleException(Throwable e, HttpServletRequest req, HttpServletResponse resp, Translator translator) { UserRequest ureq = new UserRequestImpl(ShibbolethDispatcher.PATH_SHIBBOLETH, req, resp); - if(e instanceof ShibbolethException) { + if(e instanceof ShibbolethException) { String userMsg = ""; int errorCode = ((ShibbolethException)e).getErrorCode(); switch (errorCode) { - case ShibbolethException.GENERAL_SAML_ERROR: userMsg = translator.translate("error.shibboleth.generic"); break; + case ShibbolethException.GENERAL_SAML_ERROR: userMsg = translator.translate("error.shibboleth.generic"); break; case ShibbolethException.UNIQUE_ID_NOT_FOUND: userMsg = translator.translate("error.unqueid.notfound"); break; case ShibbolethException.INSUFFICIENT_ATTRIBUTES: userMsg = translator.translate("error.insufficieant.attributes"); break; default: userMsg = translator.translate("error.shibboleth.generic"); break; - } + } showMessage(ureq,"org.opensaml.SAMLException: " + e.getMessage(), e, userMsg, ((ShibbolethException)e).getContactPersonEmail()); - return; + return; } else { - try { + try { ChiefController msgcc = MsgFactory.createMessageChiefController(ureq, new OLATRuntimeException("Error processing Shibboleth request: " + e.getMessage(), e), false); msgcc.getWindow().dispatchRequest(ureq, true); @@ -396,13 +374,13 @@ public class ShibbolethDispatcher implements Dispatcher{ } } } - + /** - * + * * @param ureq * @param exceptionLogMessage will be recorded into the log file * @param cause - * @param userMessage gets shown to the user + * @param userMessage gets shown to the user * @param supportEmail if any available, else null */ private void showMessage(UserRequest ureq, String exceptionLogMessage, Throwable cause, String userMessage, String supportEmail) { diff --git a/src/main/java/org/olat/shibboleth/ShibbolethManager.java b/src/main/java/org/olat/shibboleth/ShibbolethManager.java new file mode 100644 index 0000000000000000000000000000000000000000..5c14ec28048704aaf241627a8469473a55ca7a65 --- /dev/null +++ b/src/main/java/org/olat/shibboleth/ShibbolethManager.java @@ -0,0 +1,80 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth; + +import java.util.Map; + +import org.olat.core.id.Identity; +import org.olat.core.id.User; + +/** + * This manager handles the interaction between Shibboleth and OpenOLAT. + * + * Initial date: 19.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface ShibbolethManager { + + /** + * Create and persist an OpenOLAT user and synchronize the Shibboleth user + * attribute with the OpenOLAT user properties. The new user is added with + * the role user. Required Attributes have to be checked before this method. + * + * @param username + * @param shibbolethUniqueID + * @param language + * @param shibbolethAttributes + * @return + */ + public Identity createAndPersistUser(String username, String shibbolethUniqueID, String language, Map<String, String> shibbolethAttributes); + + /** + * Synchronize the Shibboleth user attributes to the OpenOLAT user + * properties and persist the user in the database. + * + * @param identity + * @param shibbolethAttributes + */ + public void syncUser(Identity identity, Map<String, String> shibbolethAttributes); + + /** + * Synchronize the Shibboleth attributes to the user properties. The + * attribute mapping is defined in the ShibboletModule. Attributes are added + * and overwritten, if Shibboleth delivers data. If Shibboleth delivers no + * value for an attribute the appropriate user property will be deleted. + * + * @param user + * @param shibboletAttributes + * @return + */ + public User syncAttributes(User user, Map<String, String> shibboiethAttributes); + + /** + * This methods gets the ShibbolethAttributeHandler for the attribute with + * the given attributeName and parses the attributeValue. + * + * @param attributeName + * @param attributeValue + * @return + */ + public String parseShibbolethAttribute(String attributeName, String attributeValue); + +} diff --git a/src/main/java/org/olat/shibboleth/ShibbolethModule.java b/src/main/java/org/olat/shibboleth/ShibbolethModule.java index bce4593435b188be5b6010cac0cf556afc5452a6..732ab7d9cce4568d13d56dfb1bc86775d8c77e37 100644 --- a/src/main/java/org/olat/shibboleth/ShibbolethModule.java +++ b/src/main/java/org/olat/shibboleth/ShibbolethModule.java @@ -28,9 +28,12 @@ package org.olat.shibboleth; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import org.olat.core.configuration.AbstractSpringModule; import org.olat.core.configuration.ConfigOnOff; +import org.olat.core.id.UserConstants; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; @@ -45,40 +48,24 @@ import org.springframework.stereotype.Service; * Initial Date: 16.07.2004 * * @author Mike Stock - * - * Comment: - * */ @Service("shibbolethModule") public class ShibbolethModule extends AbstractSpringModule implements ConfigOnOff { - + private static final OLog log = Tracing.createLoggerFor(ShibbolethModule.class); - + /** * Path identifier for shibboleth registration workflows. */ - static final String PATH_REGISTER_SHIBBOLETH = "shibregister"; - - private static final String CONF_OLATUSERMAPPING_FIRSTNAME = "FirstName"; - private static final String CONF_OLATUSERMAPPING_LASTNAME = "LastName"; - private static final String CONF_OLATUSERMAPPING_EMAIL = "EMail"; - public static final String CONF_OLATUSERMAPPING_INSTITUTIONALNAME = "InstitutionalName"; - private static final String CONF_OLATUSERMAPPING_INSTITUTIONALEMAIL = "InstitutionalEMail"; - private static final String CONF_OLATUSERMAPPING_INSTITUTIONALUSERIDENTIFIER = "InstitutionalUserIdentifier"; - private static final String CONF_OLATUSERMAPPING_PREFERED_LANGUAGE = "PreferedLanguage"; - private static final String CONF_OLATUSERMAPPING_ORGUNIT = "OrgUnit"; - + static final String PATH_REGISTER_SHIBBOLETH = "shibregister"; + private static final String DEFAULT_ATTRIBUTE_HANDLER = "DoNothingHandler"; + @Value("${shibboleth.enable}") private boolean enableShibbolethLogins = false; - + @Autowired private AttributeTranslator attributeTranslator; - @Value("${language.enable}") - private boolean useLanguageInReq = false; - @Value("${language.param:en}") - private String languageParamName; - @Autowired @Qualifier("shibbolethOperators") private ArrayList<String> operators; @@ -87,12 +74,16 @@ public class ShibbolethModule extends AbstractSpringModule implements ConfigOnOf @Value("${shibboleth.template.login.default:default_shibbolethlogin}") private String loginTemplateDefault; - public final String MULTIVALUE_SEPARATOR = ";"; - + public static final String MULTIVALUE_SEPARATOR = ";"; + + @Value("${shibboleth.preferred.language}") + private String preferredLanguageAttribute; @Value("${shibboleth.defaultUID:Shib-SwissEP-UniqueID}") private String defaultUIDAttribute; @Autowired @Qualifier("shibbolethUserMapping") private HashMap<String, String> userMapping; + @Autowired @Qualifier("shibbolethAttributeHandler") + private HashMap<String, String> attributeHandler; @Value("${shibboleth.ac.byAttributes:false}") private boolean accessControlByAttributes; @@ -104,160 +95,101 @@ public class ShibbolethModule extends AbstractSpringModule implements ConfigOnOf private String attribute2; @Value("${shibboleth.ac.attribute2Values:#{null}}") private String attribute2Values; - + @Autowired public ShibbolethModule(CoordinatorManager coordinatorManager) { super(coordinatorManager); } - + @Override public void init() { if (enableShibbolethLogins) { log.info("Shibboleth logins enabled."); - - if(useLanguageInReq) { - log.info("Language code is sent as parameter in the AAI request with lang: "+languageParamName); - } else { - log.info("Language code is not sent with AAI request."); - } } else { log.info("Shibboleth logins disabled."); } - + //module enabled/disabled String accessControlByAttributesObj = getStringPropertyValue("accessControlByAttributes", true); if(StringHelper.containsNonWhitespace(accessControlByAttributesObj)) { accessControlByAttributes = "true".equals(accessControlByAttributesObj); } - + + if (!checkShibboletAttributeNameIsNotEmpty(UserConstants.EMAIL)) return; + if (!checkShibboletAttributeNameIsNotEmpty(UserConstants.FIRSTNAME)) return; + if (!checkShibboletAttributeNameIsNotEmpty(UserConstants.LASTNAME)) return; + String attribute1Obj = getStringPropertyValue("attribute1", true); if(StringHelper.containsNonWhitespace(attribute1Obj)) { attribute1 = attribute1Obj; } - + String attribute1ValuesObj = getStringPropertyValue("attribute1Values", true); if(StringHelper.containsNonWhitespace(attribute1ValuesObj)) { attribute1Values = attribute1ValuesObj; } - + String attribute2Obj = getStringPropertyValue("attribute2", true); if(StringHelper.containsNonWhitespace(attribute2Obj)) { attribute2 = attribute2Obj; } - + String attribute2ValuesObj = getStringPropertyValue("attribute2Values", true); if(StringHelper.containsNonWhitespace(attribute2ValuesObj)) { attribute2Values = attribute2ValuesObj; } } - + @Override protected void initFromChangedProperties() { init(); } - + + /** + * Internal helper to check for empty configuration variables + * + * @param param + * @return true: not empty; false: empty or null + */ + private boolean checkShibboletAttributeNameIsNotEmpty(String userProperty) { + String attributeName = getShibbolethAttributeName(userProperty); + if (StringHelper.containsNonWhitespace(attributeName)) { + return true; + } + + log.error("Missing configuration for user property '" + userProperty + + "'. Add this configuration to olat.local.properties first. Disabling Shibboleth."); + enableShibbolethLogins = false; + return false; + } + /** * @return True if shibboleth logins are allowed. */ public boolean isEnableShibbolethLogins() { return enableShibbolethLogins; } - + @Override public boolean isEnabled() { return isEnableShibbolethLogins(); } - /** - * @return true if the language should be sent in the aai request - */ - public boolean useLanguageInReq() { - return useLanguageInReq; - } - - /** - * @return the get request parameter name to be used sending the language code. - */ - public String getLanguageParamName() { - return languageParamName; - } - public AttributeTranslator getAttributeTranslator() { return attributeTranslator; } - public String[] getRegisteredOperatorKeys() { - return null; - } - public List<String> getOperatorKeys() { return operators; } /** - * + * * @return the shib. default attribute which identifies an user by an unique key */ public String getDefaultUIDAttribute() { return defaultUIDAttribute; } - - /** - * @param attributesMap - * @return First Name value from shibboleth attributes. - */ - public String getFirstName() { - return userMapping.get(CONF_OLATUSERMAPPING_FIRSTNAME); - } - - /** - * @return Last Name value from shibboleth attributes. - */ - public String getLastName() { - return userMapping.get(CONF_OLATUSERMAPPING_LASTNAME); - } - - /** - * @return EMail value from shibboleth attributes. - */ - public String getEMail() { - return userMapping.get(CONF_OLATUSERMAPPING_EMAIL); - } - - /** - * @return Institutional EMail value from shibboleth attributes. - */ - public String getInstitutionalEMail() { - return userMapping.get(CONF_OLATUSERMAPPING_INSTITUTIONALEMAIL); - } - - /** - * @return Institutional Name value from shibboleth attributes. - */ - public String getInstitutionalName() { - return userMapping.get(CONF_OLATUSERMAPPING_INSTITUTIONALNAME); - } - - /** - * @return Institutional User Identifyer value from shibboleth attributes. - */ - public String getInstitutionalUserIdentifier() { - return userMapping.get(CONF_OLATUSERMAPPING_INSTITUTIONALUSERIDENTIFIER); - } - - /** - * @return OrgUnit User Identifyer value from shibboleth attributes or NULL if not defined. - */ - public String getOrgUnit() { - return userMapping.get(CONF_OLATUSERMAPPING_ORGUNIT); - } - - /** - * @return Prefered language value from shibboleth attributes. - */ - public String getPreferedLanguage() { - return userMapping.get(CONF_OLATUSERMAPPING_PREFERED_LANGUAGE); - } public String getLoginTemplate() { return loginTemplate; @@ -324,4 +256,50 @@ public class ShibbolethModule extends AbstractSpringModule implements ConfigOnOf this.attribute2Values = attribute2Values; setStringProperty("attribute2Values", attribute2Values, true); } + + public String getPreferredLanguageAttribute() { + return preferredLanguageAttribute; + } + + /** + * Returns the mapping of a Shibboleth user to an OpenOLAT user. The key + * is the Shibboleth attribute name. The value is the user property. + * + * @return + */ + public Map<String, String> getUserMapping() { + return userMapping; + } + + /** + * Returns the name of a Shibboleth attribute for a given user property name + * of null if not found. + * + * @param userProperty + * @return + */ + public String getShibbolethAttributeName(String userProperty) { + for (Entry<String, String> mapping : userMapping.entrySet()) { + if (userProperty != null && userProperty.equals(mapping.getValue())) { + return mapping.getKey(); + } + } + return null; + } + + /** + * Returns the name of the ShibbolethAttributeHandler for the name of a + * Shibboleth attribute. + * + * @param attributeName + * @return + */ + public String getShibbolethAttributeHandlerName(String attributeName) { + String attributeHandlerName = attributeHandler.get(attributeName); + if (!StringHelper.containsNonWhitespace(attributeHandlerName)) { + attributeHandlerName = DEFAULT_ATTRIBUTE_HANDLER; + } + return attributeHandlerName; + } + } \ No newline at end of file diff --git a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java index 388ba45ecddf26412db04b86235c7a4360596619..0bedbc4598bf1745aa1d9a0b86f9de7eda1efcbe 100644 --- a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java +++ b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java @@ -35,8 +35,6 @@ import org.olat.basesecurity.Authentication; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.BaseSecurityModule; -import org.olat.basesecurity.Constants; -import org.olat.basesecurity.SecurityGroup; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.chiefcontrollers.LanguageChangedEvent; import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; @@ -66,7 +64,6 @@ import org.olat.registration.LanguageChooserController; import org.olat.registration.RegistrationManager; import org.olat.registration.RegistrationModule; import org.olat.registration.UserNameCreationInterceptor; -import org.olat.shibboleth.util.ShibbolethHelper; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; @@ -74,7 +71,7 @@ import org.springframework.beans.factory.annotation.Autowired; * Initial Date: 09.08.2004 * * @author Mike Stock - * + * * Comment: * User wants ShibbolethAuthentication * - Basic flow: @@ -84,7 +81,7 @@ import org.springframework.beans.factory.annotation.Autowired; * - System asks for emailaddress (no institutionalEmail is set !!!) * 2. no email in shibbolethAttributesMap and User already exists in System * - System asks for password (no institutionalEmail is set !!!) - * + * */ public class ShibbolethRegistrationController extends DefaultController implements ControllerEventListener { @@ -92,35 +89,38 @@ public class ShibbolethRegistrationController extends DefaultController implemen private static final String VELOCITY_ROOT = Util.getPackageVelocityRoot(ShibbolethModule.class); private static final String KEY_SHIBATTRIBUTES = "shibattr"; private static final String KEY_SHIBUNIQUEID = "shibuid"; - + private VelocityContainer mainContainer; private ShibbolethRegistrationForm regForm; private ShibbolethMigrationForm migrationForm; private ShibbolethRegistrationWithEmailForm regWithEmailForm; private DisclaimerController dclController; private LanguageChooserController languageChooserController; - + private Translator translator; private Map<String,String> shibbolethAttributesMap; private String shibbolethUniqueID; - + private int state = STATE_UNDEFINED; private static final int STATE_UNDEFINED = 0; private static final int STATE_NEW_SHIB_USER = 1; private static final int STATE_MIGRATED_SHIB_USER = 2; private String proposedUsername; - + Locale locale; + private boolean hasEmailInShibAttr; - + @Autowired private ShibbolethModule shibbolethModule; @Autowired + private ShibbolethManager shibbolethManager; + @Autowired private RegistrationModule registrationModule; - + /** * Implements the shibboleth registration workflow. * @param ureq - * @param wControl + * @param wControl */ public ShibbolethRegistrationController(UserRequest ureq, WindowControl wControl) { super(wControl); @@ -128,8 +128,8 @@ public class ShibbolethRegistrationController extends DefaultController implemen translator = Util.createPackageTranslator(ShibbolethModule.class, ureq.getLocale()); shibbolethAttributesMap = (Map<String,String>)ureq.getUserSession().getEntry(KEY_SHIBATTRIBUTES); shibbolethUniqueID = (String)ureq.getUserSession().getEntry(KEY_SHIBUNIQUEID); - - if (shibbolethUniqueID == null) { + + if (shibbolethUniqueID == null) { ChiefController msgcc = MessageWindowController.createMessageChiefController(ureq, new AssertException("ShibbolethRegistrationController was unable to fetch ShibbolethUniqueID from session."), translator.translate("error.shibboleth.generic"), null); msgcc.getWindow().dispatchRequest(ureq, true); @@ -139,11 +139,11 @@ public class ShibbolethRegistrationController extends DefaultController implemen if (shibbolethAttributesMap == null) throw new AssertException("ShibbolethRegistrationController was unable to fetch ShibbolethAttribuitesMap from session."); - hasEmailInShibAttr = (shibbolethModule.getEMail() == null) ? false : true; - - Locale locale = (Locale)ureq.getUserSession().getEntry(LocaleNegotiator.NEGOTIATED_LOCALE); + hasEmailInShibAttr = (shibbolethModule.getShibbolethAttributeName(UserConstants.EMAIL) == null) ? false : true; + + locale = (Locale)ureq.getUserSession().getEntry(LocaleNegotiator.NEGOTIATED_LOCALE); if(locale == null) { - String preferedLanguage = shibbolethModule.getPreferedLanguage(); + String preferedLanguage = shibbolethAttributesMap.get(shibbolethModule.getPreferredLanguageAttribute()); if(preferedLanguage == null) { locale = LocaleNegotiator.getPreferedLocale(ureq); } else { @@ -156,15 +156,15 @@ public class ShibbolethRegistrationController extends DefaultController implemen ureq.getUserSession().setLocale(locale); I18nManager.updateLocaleInfoToThread(ureq.getUserSession()); ureq.getUserSession().putEntry(LocaleNegotiator.NEGOTIATED_LOCALE, locale); - + translator = Util.createPackageTranslator(ShibbolethModule.class, ureq.getLocale()); mainContainer = new VelocityContainer("main", VELOCITY_ROOT + "/langchooser.html", translator, this); - + languageChooserController = new LanguageChooserController(ureq, wControl, false); languageChooserController.addControllerListener(this); mainContainer.put("select.language", languageChooserController.getInitialComponent()); mainContainer.contextPut("languageCode", locale.getLanguage()); - + if(registrationModule.getUsernamePresetBean() != null) { UserNameCreationInterceptor interceptor = registrationModule.getUsernamePresetBean(); proposedUsername = interceptor.getUsernameFor(shibbolethAttributesMap); @@ -193,7 +193,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen regWithEmailForm.addControllerListener(this); //mainContainer.put("regWithEmailForm", regWithEmailForm); mainContainer.setPage(VELOCITY_ROOT + "/registerwithemail.html"); - } + } } } } else { @@ -203,25 +203,25 @@ public class ShibbolethRegistrationController extends DefaultController implemen dclController = new DisclaimerController(ureq, getWindowControl()); dclController.addControllerListener(this); mainContainer.put("dclComp", dclController.getInitialComponent()); - + // load view in layout LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), null, mainContainer, null); setInitialComponent(layoutCtr.getInitialComponent()); } - + private void setErrorPage(String errorKey, WindowControl wControl) { String error = translator.translate(errorKey); wControl.setError(error); mainContainer.contextPut("error_msg", error); mainContainer.setPage(VELOCITY_ROOT + "/error.html"); } - + private void setRegistrationForm(UserRequest ureq, WindowControl wControl, String proposedUsername) { regForm = new ShibbolethRegistrationForm(ureq, wControl, proposedUsername); regForm.addControllerListener(this); mainContainer.put("regForm", regForm.getInitialComponent()); } - + /** * Put shibboleth attributes map in reqest for later usage. * @param req @@ -230,7 +230,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen public static final void putShibAttributes(HttpServletRequest req, Map<String,String> attributes) { CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(req).putEntry(KEY_SHIBATTRIBUTES, attributes); } - + /** * Put shibboleth unique identifier in request for later usage. * @param req @@ -240,9 +240,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(req).putEntry(KEY_SHIBUNIQUEID, uniqueID); } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) - */ + @Override public void event(UserRequest ureq, Component source, Event event) { if (event instanceof LocaleChangedEvent) { LocaleChangedEvent lce = (LocaleChangedEvent)event; @@ -252,9 +250,6 @@ public class ShibbolethRegistrationController extends DefaultController implemen } } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) - */ @Override public void event(UserRequest ureq, Controller source, Event event) { if (source == migrationForm) { @@ -270,14 +265,14 @@ public class ShibbolethRegistrationController extends DefaultController implemen } else if (event == Event.DONE_EVENT) { state = STATE_NEW_SHIB_USER; mainContainer.setPage(VELOCITY_ROOT + "/disclaimer.html"); - } + } } else if (source == regForm) { if (event == Event.DONE_EVENT) { String choosenLogin = regForm.getLogin(); BaseSecurity secMgr = BaseSecurityManager.getInstance(); Identity identity = secMgr.findIdentityByName(choosenLogin); - + if (identity == null) { // ok, create new user if (!hasEmailInShibAttr){ regWithEmailForm = new ShibbolethRegistrationWithEmailForm(ureq, getWindowControl(), choosenLogin); @@ -289,7 +284,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen mainContainer.setPage(VELOCITY_ROOT + "/disclaimer.html"); } } else { // offer identity migration, if OLAT provider exists - Authentication auth = secMgr.findAuthentication(identity, BaseSecurityModule.getDefaultAuthProviderIdentifier()); + Authentication auth = secMgr.findAuthentication(identity, BaseSecurityModule.getDefaultAuthProviderIdentifier()); if (auth == null) { // no OLAT provider, migration not possible... getWindowControl().setError(translator.translate("sr.error.loginexists", new String[] {WebappHelper.getMailConfig("mailSupport")})); } else { // OLAT provider exists, offer migration... @@ -318,7 +313,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen } else { choosenLogin = regForm.getLogin(); } - + // check if login has been taken by another user in the meantime... BaseSecurity secMgr = BaseSecurityManager.getInstance(); @@ -331,19 +326,19 @@ public class ShibbolethRegistrationController extends DefaultController implemen return; } - String email; if(!hasEmailInShibAttr){ - email = regWithEmailForm.getEmail(); - } else { - email = ShibbolethHelper.getFirstValueOf(shibbolethModule.getEMail(), shibbolethAttributesMap); + shibbolethAttributesMap.put(shibbolethModule.getShibbolethAttributeName(UserConstants.EMAIL), regWithEmailForm.getEmail()); } + String emailAttributeName = shibbolethModule.getShibbolethAttributeName(UserConstants.EMAIL); + String emailAttributeValue = shibbolethAttributesMap.get(emailAttributeName); + String email = shibbolethManager.parseShibbolethAttribute(emailAttributeName, emailAttributeValue); User user = null; Identity id = UserManager.getInstance().findIdentityByEmail(email); if (id != null) { user = id.getUser(); } - + if (user != null) { // error, email already exists. should actually not happen if OLAT Authenticator has // been set after removing shibboleth authenticator @@ -353,25 +348,8 @@ public class ShibbolethRegistrationController extends DefaultController implemen return; } - String firstName = shibbolethAttributesMap.get(shibbolethModule.getFirstName()); - String lastName = shibbolethAttributesMap.get(shibbolethModule.getLastName()); - user = UserManager.getInstance().createUser(firstName, lastName, email); - user.setProperty(UserConstants.INSTITUTIONALNAME, shibbolethAttributesMap.get(shibbolethModule.getInstitutionalName())); - if(hasEmailInShibAttr){ - String institutionalEmail = ShibbolethHelper.getFirstValueOf(shibbolethModule.getInstitutionalEMail(), shibbolethAttributesMap); - user.setProperty(UserConstants.INSTITUTIONALEMAIL, institutionalEmail); - } - user.setProperty(UserConstants.INSTITUTIONALUSERIDENTIFIER, shibbolethAttributesMap.get(shibbolethModule.getInstitutionalUserIdentifier())); - // Optional organization unit property - String orgUnitIdent = shibbolethModule.getOrgUnit(); - if(orgUnitIdent != null) { - String s = ShibbolethHelper.getFirstValueOf(orgUnitIdent, shibbolethAttributesMap); - if (s != null) user.setProperty(UserConstants.ORGUNIT, s); - } + identity = shibbolethManager.createAndPersistUser(choosenLogin, shibbolethUniqueID, locale.getLanguage(), shibbolethAttributesMap); - identity = secMgr.createAndPersistIdentityAndUser(choosenLogin, null, user, ShibbolethDispatcher.PROVIDER_SHIB, shibbolethUniqueID); - SecurityGroup olatUserGroup = secMgr.findSecurityGroupByName(Constants.GROUP_OLATUSERS); - secMgr.addIdentityToSecurityGroup(identity, olatUserGroup); // tell system that this user did accept the disclaimer CoreSpringFactory.getImpl(RegistrationManager.class).setHasConfirmedDislaimer(identity); doLogin(identity, ureq); @@ -382,27 +360,10 @@ public class ShibbolethRegistrationController extends DefaultController implemen Identity authenticationedIdentity = auth.getIdentity(); BaseSecurity secMgr = BaseSecurityManager.getInstance(); secMgr.createAndPersistAuthentication(authenticationedIdentity, ShibbolethDispatcher.PROVIDER_SHIB, shibbolethUniqueID, null, null); - + // update user profile - User user = authenticationedIdentity.getUser(); - String s = shibbolethAttributesMap.get(shibbolethModule.getFirstName()); - if (s != null) user.setProperty(UserConstants.FIRSTNAME, s); - s = shibbolethAttributesMap.get(shibbolethModule.getLastName()); - if (s != null) user.setProperty(UserConstants.LASTNAME, s); - s = shibbolethAttributesMap.get(shibbolethModule.getInstitutionalName()); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALNAME, s); - s = ShibbolethHelper.getFirstValueOf(shibbolethModule.getInstitutionalEMail(), shibbolethAttributesMap); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALEMAIL, s); - s = shibbolethAttributesMap.get(shibbolethModule.getInstitutionalUserIdentifier()); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALUSERIDENTIFIER, s); - // Optional organization unit property - String orgUnitIdent = shibbolethModule.getOrgUnit(); - if(orgUnitIdent != null) { - s = ShibbolethHelper.getFirstValueOf(orgUnitIdent, shibbolethAttributesMap); - if (s != null) user.setProperty(UserConstants.ORGUNIT, s); - } - - UserManager.getInstance().updateUser(user); + shibbolethManager.syncUser(authenticationedIdentity, shibbolethAttributesMap); + doLogin(authenticationedIdentity, ureq); return; } @@ -428,17 +389,18 @@ public class ShibbolethRegistrationController extends DefaultController implemen ureq.getUserSession().getIdentityEnvironment().addAttributes( shibbolethModule.getAttributeTranslator().translateAttributesMap(shibbolethAttributesMap)); } - + /** - * + * * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) */ + @Override protected void doDispose() { if (dclController != null) { dclController.dispose(); dclController = null; } - + if (languageChooserController != null) { languageChooserController.dispose(); languageChooserController = null; diff --git a/src/main/java/org/olat/shibboleth/_spring/shibbolethContext.xml b/src/main/java/org/olat/shibboleth/_spring/shibbolethContext.xml index 61432c380edfced3f5e5593ba304be9abcf3b209..5cca3250b452dcc47677b0a71c21eab805ddd209 100644 --- a/src/main/java/org/olat/shibboleth/_spring/shibbolethContext.xml +++ b/src/main/java/org/olat/shibboleth/_spring/shibbolethContext.xml @@ -3,18 +3,18 @@ xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" - http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd - http://www.springframework.org/schema/context + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.olat.shibboleth" /> - + <!-- Shibboleth admin. panel --> <bean class="org.olat.core.extensions.action.GenericActionExtension" id="sysadmin.menupoint.syscfg.shibbolethcfg" init-method="initExtensionPoints"> <property name="order" value="8830" /> <property name="enabled" value="${shibboleth.enable}" /> - <property name="actionController"> + <property name="actionController"> <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> <property name="className" value="org.olat.shibboleth.ShibbolethAdminController"/> </bean> @@ -24,11 +24,11 @@ <property name="i18nDescriptionKey" value="admin.menu.shibboleth.desc"/> <property name="translationPackage" value="org.olat.shibboleth"/> <property name="extensionPoints"> - <list> - <value>org.olat.admin.SystemAdminMainController</value> + <list> + <value>org.olat.admin.SystemAdminMainController</value> </list> </property> - <property name="parentTreeNodeIdentifier" value="loginAndSecurityParent" /> + <property name="parentTreeNodeIdentifier" value="loginAndSecurityParent" /> </bean> <bean name="shibbolethOperators" class="java.util.ArrayList" scope="prototype" > @@ -43,18 +43,66 @@ </list> </constructor-arg> </bean> - + <bean name="shibbolethUserMapping" class="java.util.HashMap" scope="prototype" > + <constructor-arg> + <map key-type="java.lang.String" value-type="java.lang.String"> + <!-- These attributes are mandatory --> + <entry key='${shibboleth.user.mapping.shib.email}' value="email" /> + <entry key='${shibboleth.user.mapping.shib.first.name}' value="firstName" /> + <entry key='${shibboleth.user.mapping.shib.last.name}' value="lastName" /> + + <!-- All other attributes are optional --> + <entry key='${shibboleth.user.mapping.shib.key1}' value='${shibboleth.user.mapping.olat.key1}' /> + <entry key='${shibboleth.user.mapping.shib.key2}' value='${shibboleth.user.mapping.olat.key2}' /> + <entry key='${shibboleth.user.mapping.shib.key3}' value='${shibboleth.user.mapping.olat.key3}' /> + <entry key='${shibboleth.user.mapping.shib.key4}' value='${shibboleth.user.mapping.olat.key4}' /> + <entry key='${shibboleth.user.mapping.shib.key5}' value='${shibboleth.user.mapping.olat.key5}' /> + <entry key='${shibboleth.user.mapping.shib.key6}' value='${shibboleth.user.mapping.olat.key6}' /> + <entry key='${shibboleth.user.mapping.shib.key7}' value='${shibboleth.user.mapping.olat.key7}' /> + <entry key='${shibboleth.user.mapping.shib.key8}' value='${shibboleth.user.mapping.olat.key8}' /> + <entry key='${shibboleth.user.mapping.shib.key9}' value='${shibboleth.user.mapping.olat.key9}' /> + <entry key='${shibboleth.user.mapping.shib.key10}' value='${shibboleth.user.mapping.olat.key10}' /> + <entry key='${shibboleth.user.mapping.shib.key11}' value='${shibboleth.user.mapping.olat.key11}' /> + <entry key='${shibboleth.user.mapping.shib.key12}' value='${shibboleth.user.mapping.olat.key12}' /> + <entry key='${shibboleth.user.mapping.shib.key13}' value='${shibboleth.user.mapping.olat.key13}' /> + <entry key='${shibboleth.user.mapping.shib.key14}' value='${shibboleth.user.mapping.olat.key14}' /> + <entry key='${shibboleth.user.mapping.shib.key15}' value='${shibboleth.user.mapping.olat.key15}' /> + <entry key='${shibboleth.user.mapping.shib.key16}' value='${shibboleth.user.mapping.olat.key16}' /> + <entry key='${shibboleth.user.mapping.shib.key17}' value='${shibboleth.user.mapping.olat.key17}' /> + <entry key='${shibboleth.user.mapping.shib.key18}' value='${shibboleth.user.mapping.olat.key18}' /> + <entry key='${shibboleth.user.mapping.shib.key19}' value='${shibboleth.user.mapping.olat.key19}' /> + <entry key='${shibboleth.user.mapping.shib.key20}' value='${shibboleth.user.mapping.olat.key20}' /> + </map> + </constructor-arg> + </bean> + + <bean name="shibbolethAttributeHandler" class="java.util.HashMap" scope="prototype" > <constructor-arg> <map key-type="java.lang.String" value-type="java.lang.String"> - <entry key="FirstName" value="Shib-InetOrgPerson-givenName" /> - <entry key="LastName" value="Shib-Person-surname" /> - <entry key="EMail" value="Shib-InetOrgPerson-mail" /> - <entry key="InstitutionalName" value="Shib-SwissEP-HomeOrganization" /> - <entry key="InstitutionalEMail" value="Shib-InetOrgPerson-mail" /> - <entry key="InstitutionalUserIdentifier" value="Shib-InetOrgPerson-employeeNumber" /> - <!-- <entry key="OrgUnit" value="" /> --> - <!-- <entry key="PreferedLanguage" value="" /> --> + <entry key='${shibboleth.user.mapping.shib.email}' value='${shibboleth.user.mapping.handler.email}' /> + <entry key='${shibboleth.user.mapping.shib.first.name}' value='${shibboleth.user.mapping.handler.first.name}' /> + <entry key='${shibboleth.user.mapping.shib.last.name}' value='${shibboleth.user.mapping.handler.last.name}' /> + <entry key='${shibboleth.user.mapping.shib.key1}' value='${shibboleth.user.mapping.handler.key1}' /> + <entry key='${shibboleth.user.mapping.shib.key2}' value='${shibboleth.user.mapping.handler.key2}' /> + <entry key='${shibboleth.user.mapping.shib.key3}' value='${shibboleth.user.mapping.handler.key3}' /> + <entry key='${shibboleth.user.mapping.shib.key4}' value='${shibboleth.user.mapping.handler.key4}' /> + <entry key='${shibboleth.user.mapping.shib.key5}' value='${shibboleth.user.mapping.handler.key5}' /> + <entry key='${shibboleth.user.mapping.shib.key6}' value='${shibboleth.user.mapping.handler.key6}' /> + <entry key='${shibboleth.user.mapping.shib.key7}' value='${shibboleth.user.mapping.handler.key7}' /> + <entry key='${shibboleth.user.mapping.shib.key8}' value='${shibboleth.user.mapping.handler.key8}' /> + <entry key='${shibboleth.user.mapping.shib.key9}' value='${shibboleth.user.mapping.handler.key9}' /> + <entry key='${shibboleth.user.mapping.shib.key10}' value='${shibboleth.user.mapping.handler.key10}' /> + <entry key='${shibboleth.user.mapping.shib.key11}' value='${shibboleth.user.mapping.handler.key11}' /> + <entry key='${shibboleth.user.mapping.shib.key12}' value='${shibboleth.user.mapping.handler.key12}' /> + <entry key='${shibboleth.user.mapping.shib.key13}' value='${shibboleth.user.mapping.handler.key13}' /> + <entry key='${shibboleth.user.mapping.shib.key14}' value='${shibboleth.user.mapping.handler.key14}' /> + <entry key='${shibboleth.user.mapping.shib.key15}' value='${shibboleth.user.mapping.handler.key15}' /> + <entry key='${shibboleth.user.mapping.shib.key16}' value='${shibboleth.user.mapping.handler.key16}' /> + <entry key='${shibboleth.user.mapping.shib.key17}' value='${shibboleth.user.mapping.handler.key17}' /> + <entry key='${shibboleth.user.mapping.shib.key18}' value='${shibboleth.user.mapping.handler.key18}' /> + <entry key='${shibboleth.user.mapping.shib.key19}' value='${shibboleth.user.mapping.handler.key19}' /> + <entry key='${shibboleth.user.mapping.shib.key20}' value='${shibboleth.user.mapping.handler.key20}' /> </map> </constructor-arg> </bean> @@ -65,15 +113,15 @@ <!-- Attributes to translate for easier reading/handling within OLAT. Attributes will be available by their translated name (value) within OLAT. - - As an option, for each attribute predefined selectable values can be added as + + As an option, for each attribute predefined selectable values can be added as in the example below. These are used in the course editors easy mode to display a list of items to choose from instead of a text input field. - - All attributes value and all selectableValue can be translated in the - ShibbolethModule package or the default package. When not translation is found, + + All attributes value and all selectableValue can be translated in the + ShibbolethModule package or the default package. When not translation is found, the keys defined in this file will be displayed. - + Example: To make a GUI translation of the attribute "urn:mace:switch.ch:attribute-def:swissEduPersonHomeOrganization" you must define an value="swissEduPersonHomeOrganization" and add some selectable values. Now in the i18n @@ -97,11 +145,11 @@ <entry key="Shib-SwissEP-StudyLevel" value="swissEduPersonStudyLevel" /> <entry key="Shib-SwissEP-StaffCategory" value="swissEduPersonStaffCategory" /> <!-- Is anyone using these attributes? it's not in the attribute-map.xml - <entry key="urn:mace:switch.ch:attribute-def:eduPersonOrgUnitDN" value="eduPersonOrgUnitDN" /> - <entry key="urn:mace:dir:attribute-def:eduPersonScopedAffiliation" value="eduPersonScopedAffiliation" /> + <entry key="urn:mace:switch.ch:attribute-def:eduPersonOrgUnitDN" value="eduPersonOrgUnitDN" /> + <entry key="urn:mace:dir:attribute-def:eduPersonScopedAffiliation" value="eduPersonScopedAffiliation" /> <entry key="urn:mace:dir:attribute-def:swissEduPersonGender" value="swissEduPersonGender" /> --> - <entry key="Shib-OrgPerson-postalAddress" value="postalAddress" /> + <entry key="Shib-OrgPerson-postalAddress" value="postalAddress" /> <entry key="Shib-InetOrgPerson-employeeNumber" value="employeeNumber" /> <entry key="Shib-Person-ou" value="organizationalUnit" /> <entry key="Shib-InetOrgPerson-preferredLanguage" value="PreferedLanguage" /> @@ -220,7 +268,7 @@ <value>81</value> <value>82</value> <value>83</value> - <value>84</value> + <value>84</value> <!-- University of Applied Sciences --> <value>10101</value> <value>10102</value> @@ -546,22 +594,22 @@ <value>304</value> <value>305</value> <value>306</value> - <value>307</value> - <value>308</value> + <value>307</value> + <value>308</value> </list> </entry> </map> </property> </bean> - <bean id="switchShibbolethAuthenticationConfigurator" class="org.olat.shibboleth.SwitchShibbolethAuthenticationConfigurator"> - <property name="wayfSPEntityID" value="${shibboleth.wayfSPEntityID}" /> + <bean id="switchShibbolethAuthenticationConfigurator" class="org.olat.shibboleth.SwitchShibbolethAuthenticationConfigurator"> + <property name="wayfSPEntityID" value="${shibboleth.wayfSPEntityID}" /> <property name="wayfSPHandlerURL" value="${shibboleth.wayfSPHandlerURL}" /> <property name="wayfSPSamlDSURL" value="${shibboleth.wayfSPSamlDSURL}" /> <property name="wayfReturnUrl" value="${shibboleth.wayfReturnUrl}" /> <property name="wayfReturnMobileUrl" value="${shibboleth.wayfReturnMobileUrl}" /> - <property name="additionalIdentityProviders" value="${shibboleth.wayf.additionalIDPs}" /> - </bean> + <property name="additionalIdentityProviders" value="${shibboleth.wayf.additionalIDPs}" /> + </bean> <bean id="registrationPresetUsername.byShibbolethAttribute" class="org.olat.shibboleth.ShibbolethUserNameFromAttributeUserNameCreationInterceptor" lazy-init="true"> diff --git a/src/main/java/org/olat/shibboleth/handler/DoNothingHandler.java b/src/main/java/org/olat/shibboleth/handler/DoNothingHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..7ac68a852974abc81dedbe0e71fbfd6cd47400b7 --- /dev/null +++ b/src/main/java/org/olat/shibboleth/handler/DoNothingHandler.java @@ -0,0 +1,39 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import org.springframework.stereotype.Component; + +/** + * This Handler does nothing that is it returns raw input. + * + * Initial date: 21.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component("DoNothing") +public class DoNothingHandler implements ShibbolethAttributeHandler { + + @Override + public String parse(String shibbolethAttributeValue) { + return shibbolethAttributeValue; + } + +} diff --git a/src/main/java/org/olat/shibboleth/handler/FirstValueHandler.java b/src/main/java/org/olat/shibboleth/handler/FirstValueHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..a321eacaee69a89a1be4d9a98a53cbe7f2417d3f --- /dev/null +++ b/src/main/java/org/olat/shibboleth/handler/FirstValueHandler.java @@ -0,0 +1,46 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import org.olat.shibboleth.ShibbolethModule; +import org.springframework.stereotype.Component; + +/** + * A Shibboleth attribute may contain multiple values delimited by ";". This + * handler splits the Shibboleth attribute in its separate values and returns + * the first value. + * + * Initial date: 21.07.2017<br> + * + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component("FirstValue") +public class FirstValueHandler implements ShibbolethAttributeHandler { + + @Override + public String parse(String shibbolethAttributeValue) { + if (shibbolethAttributeValue == null) return null; + + String[] values = shibbolethAttributeValue.split(ShibbolethModule.MULTIVALUE_SEPARATOR); + return values[0]; + } + +} diff --git a/src/main/java/org/olat/shibboleth/handler/SchacGenderHandler.java b/src/main/java/org/olat/shibboleth/handler/SchacGenderHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..e46d231bbd707292a6fbe8f64898be8638e2a49f --- /dev/null +++ b/src/main/java/org/olat/shibboleth/handler/SchacGenderHandler.java @@ -0,0 +1,48 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import org.springframework.stereotype.Component; + +/** + * Handles the values from SchacGender (http://macedir.org/ontologies/attribute/2012-11-10/attributeOntologyDoc/schacgender.html) + * + * Initial date: 21.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component("SchacGender") +public class SchacGenderHandler implements ShibbolethAttributeHandler { + + @Override + public String parse(String shibbolethAttributeValue) { + if (shibbolethAttributeValue == null) return null; + + switch(shibbolethAttributeValue) { + case "1": + return "male"; + case "2": + return "female"; + default: + return "-"; + } + } + +} diff --git a/src/main/java/org/olat/shibboleth/handler/ShibbolethAttributeHandler.java b/src/main/java/org/olat/shibboleth/handler/ShibbolethAttributeHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..9c5540f70071e0a75e208be3007327b737a13a95 --- /dev/null +++ b/src/main/java/org/olat/shibboleth/handler/ShibbolethAttributeHandler.java @@ -0,0 +1,44 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +/** + * A ShibollethAttributeHandler parses the value of a Shibboleth attribute, so + * that the resulting value has the right form to use as a user property. For + * example a concrete implementation maps the Shibboleth gender values "1" and + * "2" to the user gender values "female" and "male". The implementation have to + * be Spring Services (use @Service) because they are get from the Spring + * application context by there name. + * + * Initial date: 21.07.2017<br> + * + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface ShibbolethAttributeHandler { + + /** + * Parses the value of the Shibboleth attribute. + * + * @param shibbolethAttributeValue + * @return + */ + public String parse(String shibbolethAttributeValue); +} diff --git a/src/main/java/org/olat/shibboleth/manager/ShibbolethManagerImpl.java b/src/main/java/org/olat/shibboleth/manager/ShibbolethManagerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..1f8bbff703ef119af29283abedeb482b0969eca4 --- /dev/null +++ b/src/main/java/org/olat/shibboleth/manager/ShibbolethManagerImpl.java @@ -0,0 +1,123 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import java.util.Map; + +import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.BaseSecurityManager; +import org.olat.basesecurity.Constants; +import org.olat.basesecurity.SecurityGroup; +import org.olat.core.CoreSpringFactory; +import org.olat.core.id.Identity; +import org.olat.core.id.User; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.shibboleth.ShibbolethDispatcher; +import org.olat.shibboleth.ShibbolethManager; +import org.olat.shibboleth.ShibbolethModule; +import org.olat.shibboleth.handler.ShibbolethAttributeHandler; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 19.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Service +public class ShibbolethManagerImpl implements ShibbolethManager { + + private static final OLog log = Tracing.createLoggerFor(ShibbolethManagerImpl.class); + + private BaseSecurity securityManager; + + @Autowired + private ShibbolethModule shibbolethModule; + @Autowired + private UserManager userManager; + + public ShibbolethManagerImpl() { + securityManager = BaseSecurityManager.getInstance(); + } + + @Override + public Identity createAndPersistUser(String username, String shibbolethUniqueID, String language, Map<String, String> shibbolethAttributes) { + if (shibbolethAttributes == null) return null; + + User user = userManager.createUser(null, null, null); + user = syncAttributes(user, shibbolethAttributes); + user.getPreferences().setLanguage(language); + Identity identity = securityManager.createAndPersistIdentityAndUser(username, null, user, + ShibbolethDispatcher.PROVIDER_SHIB, shibbolethUniqueID); + + SecurityGroup olatUserGroup = securityManager.findSecurityGroupByName(Constants.GROUP_OLATUSERS); + securityManager.addIdentityToSecurityGroup(identity, olatUserGroup); + + return identity; + } + + @Override + public void syncUser(Identity identity, Map<String, String> shibbolethAttributes) { + if (identity == null || shibbolethAttributes == null) { + return; + } + + User user = identity.getUser(); + user = syncAttributes(user, shibbolethAttributes); + userManager.updateUser(user); + } + + @Override + public User syncAttributes(User user, Map<String, String> shibbolethAttributes) { + if (user == null) return null; + if (shibbolethAttributes == null) return user; + + for (Map.Entry<String, String> mapping : shibbolethModule.getUserMapping().entrySet()) { + String attributeName = mapping.getKey(); + String attributeValue = shibbolethAttributes.get(attributeName); + attributeValue = parseShibbolethAttribute(attributeName, attributeValue); + user.setProperty(mapping.getValue(), attributeValue); + } + + return user; + } + + @Override + public String parseShibbolethAttribute(String attributeName, String attributeValue) { + String parsedArrtibuteValue = attributeValue; + + String shibbolethAttributeHandlerName = + shibbolethModule.getShibbolethAttributeHandlerName(attributeName); + try { + ShibbolethAttributeHandler shibbolethAttributeHandler = + (ShibbolethAttributeHandler) CoreSpringFactory.getBean(shibbolethAttributeHandlerName); + parsedArrtibuteValue = shibbolethAttributeHandler.parse(attributeValue); + } catch (Exception e) { + log.error("Not able to parse the Shibboleth attribute. ShibbolethAttributeHandler '" + + shibbolethAttributeHandlerName + "' does not exist."); + } + + return parsedArrtibuteValue; + } + +} diff --git a/src/main/java/org/olat/shibboleth/util/ShibbolethHelper.java b/src/main/java/org/olat/shibboleth/util/ShibbolethHelper.java deleted file mode 100644 index 3c6ff18be57472d8ea9d9198dd590ce3c14fd4ea..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/shibboleth/util/ShibbolethHelper.java +++ /dev/null @@ -1,47 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <p> -* Licensed under the Apache License, Version 2.0 (the "License"); <br> -* you may not use this file except in compliance with the License.<br> -* You may obtain a copy of the License at -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <p> -* Unless required by applicable law or agreed to in writing,<br> -* software distributed under the License is distributed on an "AS IS" BASIS, <br> -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> -* See the License for the specific language governing permissions and <br> -* limitations under the License. -* <p> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.shibboleth.util; - -import java.util.Map; - -/** - * Initial Date: Oct 29, 2010 <br> - * @author patrick - */ -public class ShibbolethHelper { - - /** - * @return the first value of a multivalue shibboleth attribute, works also for singlevalue attributes. - */ - public static String getFirstValueOf(String attributeName, Map<String, String> shibbolethAttributesMap) { - String attrVal = shibbolethAttributesMap.get(attributeName); - if (attrVal != null) { - ShibbolethAttribute multivalueShibbAttributeEmail = new ShibbolethAttribute(attributeName, attrVal); - return multivalueShibbAttributeEmail.getFirstValue(); - } - else return null; - } - -} diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties index cb8c26bd818254c193817e357d7eeb131fe46e66..e6d0740a946ad16fd955022cee7b1c239b7f1255 100644 --- a/src/main/resources/serviceconfig/olat.properties +++ b/src/main/resources/serviceconfig/olat.properties @@ -54,7 +54,7 @@ folder.force.download.values=true,false # Initial setting for the system default locale # (used on the OLAT login page as well as when creating new user accounts) # NOTE: Once set at runtime via the admin GUI (System configuration -> Languages) -# this default setting will be overridden by the values in +# this default setting will be overridden by the values in # ${userdata.dir}/system/configuration/org.olat.core.util.i18n.I18nModule.properties defaultlang=en @@ -62,15 +62,15 @@ defaultlang=en project.build.home.directory= -# The language that is used as a fallback in case the system does not find a key in -# the users language nor in the default language. Note that in this language all -# keys must exist! Since developers only add the 'de' and 'en' keys it is strongly +# The language that is used as a fallback in case the system does not find a key in +# the users language nor in the default language. Note that in this language all +# keys must exist! Since developers only add the 'de' and 'en' keys it is strongly # recommended that you don't set it to any other value that this. If unsure, use the default 'de'. fallbacklang=de fallbacklang.comment=Set this only to a language that is 100% translated when compared to 'de' fallbacklang.values=de,en -# Initial setting for enabled languages: comma separated list of lang keys. +# Initial setting for enabled languages: comma separated list of lang keys. # Example: # enabledLanguages=en,de,fr,it,es,da,cs,el,ru,pl,zh_CN,zh_TW,lt,fa,pt_PT,pt_BR,tr,hu,sq,in,ar,rm,af,iw,vi,mn # or @@ -78,14 +78,14 @@ fallbacklang.values=de,en # Example: # enabledLanguages=all # NOTE: Once set at runtime via the admin GUI (System configuration -> Languages) -# this default setting will be overridden by the values in +# this default setting will be overridden by the values in # ${userdata.dir}/system/configuration/org.olat.core.util.i18n.I18nModule.properties enabledLanguages=en,de,fr,it,es # determines the character set of files written to the file system # e.g.: US-ASCII, ISO-8859-1, UTF-8 defaultcharset=UTF-8 -# abort system startup when no UTF-8 capable file system is detected. In production this should be set to +# abort system startup when no UTF-8 capable file system is detected. In production this should be set to # true to prevent accidental startup with another encoding which leads to a big data mess enforce.utf8.filesystem=true @@ -97,11 +97,11 @@ history.resume.enabled.default.values=none,auto,ondemand # the owner of repository-entries of deleted users deletionModule.adminUserName=administrator -# Session timeout configuration. -# Note that this are default values only. If you want to change the configuration, open the administration panel -# in OpenOLAT and change the values there. They are stored in olatdata/system/configuration/ and will override +# Session timeout configuration. +# Note that this are default values only. If you want to change the configuration, open the administration panel +# in OpenOLAT and change the values there. They are stored in olatdata/system/configuration/ and will override # the values from the olat.local.properties file. -# a) Session timeout in seconds for not-authenticated sessions (login screen etc). +# a) Session timeout in seconds for not-authenticated sessions (login screen etc). # Keep small to prevent denial of service attacks. Default is 5 minutes. session.timeout=300 # b) Session timeout in seconds for authenticated users and guest users. Default is two hours. @@ -172,7 +172,7 @@ registration.enableDisclaimer=true # add a second checkbox to the disclaimer registration.disclaimerAdditionalCheckbox=false # add a link to the disclaimer with a file download -# if set to true you can add downloadable disclaimer files in olatdata/customizing/disclaimer/ +# if set to true you can add downloadable disclaimer files in olatdata/customizing/disclaimer/ # the names of the files can be configured in the i18n key org.olat.registration:disclaimer.filedownloadurl registration.disclaimerAdditionaLinkText=false @@ -203,8 +203,8 @@ invitation.login=${login.invitationLogin} # Allow users to login using alternatively their email address or username login.using.username.or.email.enabled=true -# permit users to change their own passwords -# (if you set this to false, nobody can can change their pws!) +# permit users to change their own passwords +# (if you set this to false, nobody can can change their pws!) password.change.allowed=true # default deletion behavior is to retain details (marked as deleted) and # ensure they cannot be used, otherwise (if false) values will be replaced @@ -243,17 +243,17 @@ group.card.contact.values=never,always,groupconfig group.userlist.download.default.allowed=false group.userlist.download.default.allowed.values=true,false -# Behavior when manually adding a user to a group. There are two workflow elements regarding data privacy +# Behavior when manually adding a user to a group. There are two workflow elements regarding data privacy # that can be configured: -# a) Email notification: is the notification email about the new group membership mandatory or optional? +# a) Email notification: is the notification email about the new group membership mandatory or optional? # Default is true for normal users and optional for users with role author, usermanager, groupmanager or administrator group.mandatory.enrolment.email.users=true group.mandatory.enrolment.email.authors=false group.mandatory.enrolment.email.usermanagers=false group.mandatory.enrolment.email.groupmanagers=false group.mandatory.enrolment.email.administrators=false -# b) Invitation only or direct membership: is the new group membership immediate or is it only an invitation -# that must be accepted by the invited user? +# b) Invitation only or direct membership: is the new group membership immediate or is it only an invitation +# that must be accepted by the invited user? # Default is invitation-only for normal users and immediate group membership without the need to accept # for users with the role author, usermanager, groupmanager or administrator group.accept.membership.users=true @@ -283,12 +283,12 @@ assessment.mode.values=enabled,disabled #### # Olat -> default assessmentplugin -# Onyx -> The Onyx-Testplayer (onyxassessmentplugin) can be downloaded at http://www.olat.de/onyx. -# The Testplayer is one element of the Onyx-Testsuite and has been designed, +# Onyx -> The Onyx-Testplayer (onyxassessmentplugin) can be downloaded at http://www.olat.de/onyx. +# The Testplayer is one element of the Onyx-Testsuite and has been designed, # developed and tested by BPS - Bildungsportal Sachsen GmbH - http://www.bps-system.de -# OLAT makes no representations or warranties of any kind, either express or implied, +# OLAT makes no representations or warranties of any kind, either express or implied, # nor shall OLAT have any liability whatsoever to any person using Onyx, with respect to its functionality. -# For all questions and help concerning the Onyx-Testplayer and the Onyx-Testsuite +# For all questions and help concerning the Onyx-Testplayer and the Onyx-Testsuite # including any support write to support@bps-system.de #### assessmentplugin.activate=Olat @@ -323,7 +323,7 @@ onyx.reporter.webservice=${onyx.plugin.wslocation}/reporterservices onyx.update.results.job=disabled onyx.plugin.exammodelocation=${onyx.plugin.wslocation}/onyxexamservices -### set or overwrite this switch to "true" if this olat-node is either a single-node or should be the controlling entity in a clustered-olat +### set or overwrite this switch to "true" if this olat-node is either a single-node or should be the controlling entity in a clustered-olat exam.mode.masternode=true ######################################################################## @@ -342,15 +342,15 @@ qti21.digital.signature.certificate= ######################################################################## # Certificates ######################################################################## -# Send a copy of the certificates mails to someone +# Send a copy of the certificates mails to someone certificate.bcc= ##### # Help course and context help ##### -# Enable the help system. This create context help links all over the system that points to the help system configured by the help.plugin variable. -# By default, the help opens the manual hosted in a confluence wiki at confluence.openolat.org. If you want to build your own help system, write -# your own help plugin and configure it here. +# Enable the help system. This create context help links all over the system that points to the help system configured by the help.plugin variable. +# By default, the help opens the manual hosted in a confluence wiki at confluence.openolat.org. If you want to build your own help system, write +# your own help plugin and configure it here. help.enabled=true # Define the plugin which generate the help URL help.plugin=ooConfluenceLinkHelp @@ -374,7 +374,7 @@ layout.coursetemplates.blacklist= # Absolute path to directory where custom themes are loaded from (optional) layout.custom.themes.dir=${userdata.dir}/customizing/themes -# CSS class prefixes from the content.css file that are to be displayed in +# CSS class prefixes from the content.css file that are to be displayed in # the menu in the HTML editor. Default is /\.b_/ (javaScript regexp) html.editor.css.class.prefix=/\.b_/ @@ -390,12 +390,12 @@ localization.cache=true allow.loadtest.mode=false # Whether or not the gui demo site should be enabled=shown. Note that when set to true the -# two other conditions must be met to show the site: user must be administrator and +# two other conditions must be met to show the site: user must be administrator and # olat.debug must also be set to true. When olat.debug=false, the flag has no meaning whatsoever. guidemo.enabled=true ######################################################################## -# OLAT sites / tabs +# OLAT sites / tabs ######################################################################## # enable / disable homeSite. Those are the tools visible in the personal menu site.minimalhome.enabled=true @@ -448,7 +448,7 @@ portlet.repository.student.entries=6 portlet.repository.teacher.enabled=true portlet.repository.teacher.entries=6 # the info message portlet is a counterpart of the course building block -# course.node.infomessage, see further down this file. +# course.node.infomessage, see further down this file. portlet.infomessages.enabled=true # Optional portlets, disabled by default portlet.shiblogin.enabled=false @@ -466,9 +466,9 @@ portlet.sysinfo.filepath=pathToYourEventsFile/static/events.html repo.managed=false repo.managed.values=true,false -# The course database: a REST key-value store that can be used in single pages to -# implement all kind of fancy things that need a storage, e.g. build your own -# survey or "I've read this" checkbox. Course authors have the possibility do +# The course database: a REST key-value store that can be used in single pages to +# implement all kind of fancy things that need a storage, e.g. build your own +# survey or "I've read this" checkbox. Course authors have the possibility do # download the course db with the values from all users and check for values using # expert rules course.db.enabled=false @@ -486,8 +486,8 @@ webdav.enabled=true #webdav manager (show or don't webdav links in GUI) webdav.links.enabled=true auth.digest.enabled=true -#sort courses using semester terms for better discoverability. Only -#usefull when semester terms are defined in admin area and used by courses +#sort courses using semester terms for better discoverability. Only +#usefull when semester terms are defined in admin area and used by courses webdav.termsfolders.enabled=true ######################################################################## @@ -549,9 +549,9 @@ db.vendor=mysql db.vendor.values=mysql,postgresql,oracle db.vendor.values.comment=supported vendors currently include "mysql", "postgresql" and "oracle" -# The local data source works out of the box with the Hikari database connection pool. However, we stronlgy +# The local data source works out of the box with the Hikari database connection pool. However, we stronlgy # recommend using a jndi container managed data source for better stability and realibility. -# When using jndi, make sure you copy the database connector to your application server lib directory and remove it from +# When using jndi, make sure you copy the database connector to your application server lib directory and remove it from # the OpenOLAT release. db.source=local db.source.values=local,jndi @@ -573,7 +573,7 @@ db.pass=olat #this option is currently only for oracle db.default.schema=olat -# Special options for mysql database. Set useOldUTF8Behavior=true if +# Special options for mysql database. Set useOldUTF8Behavior=true if # your mysql database is setup up with iso-latin (or any other) encoding. # Remove the useOldUTF8Behavior parameter if you use native UTF-8 on the # database (recommended when setting up a new system) @@ -608,7 +608,7 @@ velocity.parser.pool.size.comment=20 is Velocity default value, use more when yo # Instant Messaging / chat ######################################################################## -# As of 8.4 no external instant messaging server is needed. Configuration +# As of 8.4 no external instant messaging server is needed. Configuration # of the instant messaging / chat infrastructure is done in the admin GUI instantMessaging.enable=true @@ -695,7 +695,7 @@ userinfos.tunnelcoursebuildingblock=disabled userDisplayName=userDisplayName_lastname_firstname userDisplayName.values=userDisplayName_firstname_lastname, userDisplayName_lastname_firstname -# An additional image attached to the user profile, eg. for the company logo. +# An additional image attached to the user profile, eg. for the company logo. # Diplayed on the users vising card user.logoByProfile=disabled user.logoByProfile.values=enabled,disabled @@ -705,7 +705,7 @@ user.logoByProfile.values=enabled,disabled ######################################################################## # Enable search-service for only one node per cluster [ enabled | disabled ] search.service=enabled -# The full text indexer can be configured in two ways: +# The full text indexer can be configured in two ways: # 1) Start indexer during startup and restart periodicaly in a given interval generate.index.at.startup=false # but only if startup is during the restart window... @@ -726,8 +726,8 @@ search.indexing.restart.interval=0 # 2) Enable triggering indexer via cron-job instead at startup [ enabled | disabled ] # When enabled , configure 'generate.index.at.startup=false' search.indexing.cronjob=enabled -# Example '0 0 3 * * ?' start indexer at 03:00 ever day. If you do not provide a valid -# expression but have set search.indexing.cronjob=enabled, the system will generate a +# Example '0 0 3 * * ?' start indexer at 03:00 ever day. If you do not provide a valid +# expression but have set search.indexing.cronjob=enabled, the system will generate a # cron expression that triggers the indexer every four hour depending on your tomcat.id variable search.indexing.cronjob.expression=0 0 3 * * ? #examples: @@ -750,25 +750,19 @@ restapi.ips.system= restapi.ips.system.values=192.168.1.200,192.168.1.201 ######################################################################## -# Statistics +# Statistics ######################################################################## # Calculate the course statistics statistics.cronjob.expression=0 10 5 * * ? ######################################################################## -# Security +# Shibboleth ######################################################################## shibboleth.enable=false # set the name of the Shibboleth attribute used to identify authorized users shibboleth.defaultUID=defaultUID -# the Authentication and Authorization Infrastructure (AAI) is a -# federated identity management system used in Switzerland that -# supports the sending of a locale code within an AAI request using -# a key as named in the language.param setting -language.enable=false -language.param=YOUR_PARAM_NAME # if you change this all current users will no longer be able to login! default.auth.provider.identifier=OLAT @@ -796,6 +790,81 @@ shibbolethUZH.default=false shibbolethGeneric.enable=false shibbolethGeneric.default=false +#Shibboleth attribute to use if a user logs in the first time. +shibboleth.preferred.language= +#Define which Shibboleth attributes are mapped to OLAT user properties +#and how the attributes are mapped. Use a handler to transform the from +#Shibboleth delivered value to the desired form. +shibboleth.user.mapping.handler.values=DoNothing,FirstValue,SchacGender +#These attributes are mandatory to create new users. +shibboleth.user.mapping.shib.email=Shib-InetOrgPerson-mail +shibboleth.user.mapping.handler.email=FirstValue +shibboleth.user.mapping.shib.first.name=Shib-InetOrgPerson-givenName +shibboleth.user.mapping.handler.first.name= +shibboleth.user.mapping.shib.last.name=Shib-Person-surname +shibboleth.user.mapping.handler.last.name= +#Further attributes may be mapped if wanted. +shibboleth.user.mapping.shib.key1= +shibboleth.user.mapping.olat.key1= +shibboleth.user.mapping.handler.key1= +shibboleth.user.mapping.shib.key2= +shibboleth.user.mapping.olat.key2= +shibboleth.user.mapping.handler.key2= +shibboleth.user.mapping.shib.key3= +shibboleth.user.mapping.olat.key3= +shibboleth.user.mapping.handler.key3= +shibboleth.user.mapping.shib.key4= +shibboleth.user.mapping.olat.key4= +shibboleth.user.mapping.handler.key4= +shibboleth.user.mapping.shib.key5= +shibboleth.user.mapping.olat.key5= +shibboleth.user.mapping.handler.key5= +shibboleth.user.mapping.shib.key6= +shibboleth.user.mapping.olat.key6= +shibboleth.user.mapping.handler.key6= +shibboleth.user.mapping.shib.key7= +shibboleth.user.mapping.olat.key7= +shibboleth.user.mapping.handler.key7= +shibboleth.user.mapping.shib.key8= +shibboleth.user.mapping.olat.key8= +shibboleth.user.mapping.handler.key8= +shibboleth.user.mapping.shib.key9= +shibboleth.user.mapping.olat.key9= +shibboleth.user.mapping.handler.key9= +shibboleth.user.mapping.shib.key10= +shibboleth.user.mapping.olat.key10= +shibboleth.user.mapping.handler.key10= +shibboleth.user.mapping.shib.key11= +shibboleth.user.mapping.olat.key11= +shibboleth.user.mapping.handler.key11= +shibboleth.user.mapping.shib.key12= +shibboleth.user.mapping.olat.key12= +shibboleth.user.mapping.handler.key12= +shibboleth.user.mapping.shib.key13= +shibboleth.user.mapping.olat.key13= +shibboleth.user.mapping.handler.key13= +shibboleth.user.mapping.shib.key14= +shibboleth.user.mapping.olat.key14= +shibboleth.user.mapping.handler.key14= +shibboleth.user.mapping.shib.key15= +shibboleth.user.mapping.olat.key15= +shibboleth.user.mapping.handler.key15= +shibboleth.user.mapping.shib.key16= +shibboleth.user.mapping.olat.key16= +shibboleth.user.mapping.handler.key16= +shibboleth.user.mapping.shib.key17= +shibboleth.user.mapping.olat.key17= +shibboleth.user.mapping.handler.key17= +shibboleth.user.mapping.shib.key18= +shibboleth.user.mapping.olat.key18= +shibboleth.user.mapping.handler.key18= +shibboleth.user.mapping.shib.key19= +shibboleth.user.mapping.olat.key19= +shibboleth.user.mapping.handler.key19= +shibboleth.user.mapping.shib.key20= +shibboleth.user.mapping.olat.key20= +shibboleth.user.mapping.handler.key20= + ######################################################################## # Clustering settings ######################################################################## @@ -842,15 +911,15 @@ hibernate.caching.use.query.cache=true hibernate.use.second.level.cache=true hibernate.connection.timeout=120 -##### +######################################## # LDAP configuration parameters (optional) # for advanced config options see webapp/WEB-INF/src/serviceconfig/org/olat/ldap/_spring/olatextconfig.xml -##### +######################################## ldap.enable=false # is ldap your default provider? true or false ldap.default=false ldap.activeDirectory=false -# The date format is not the same for OpenLDAP (yyyyMMddHHmmss'Z') or +# The date format is not the same for OpenLDAP (yyyyMMddHHmmss'Z') or # ActiveDirectory (yyyyMMddHHmmss'.0Z') ldap.dateFormat=yyyyMMddHHmmss'Z' ldap.dateFormat.values=yyyyMMddHHmmss'Z',yyyyMMddHHmmss'.0Z' @@ -875,14 +944,14 @@ ldap.ldapCreateUsersOnLogin=true # When users log in via LDAP, the system can keep a copy of the password as encrypted # hash in the database. This makes OLAT more independent from an offline LDAP server # and users can use their LDAP password to use the WebDAV functionality. -# If you have a mixed environment where some users have webDAV passwords and some have +# If you have a mixed environment where some users have webDAV passwords and some have # only local OLAT user accounts, you have to set this flag to 'true. # When setting to true (recommended), make sure you configured password.change.allowed=false # unless you also set ldap.propagatePasswordChangedOnLdapServer=true ldap.cacheLDAPPwdAsOLATPwdOnLogin=true # Change the password on the LDAP server too ldap.propagatePasswordChangedOnLdapServer=false -# Reset the password lock timeout on the active directory in case it is +# Reset the password lock timeout on the active directory in case it is # an active directory and also remove user from failed login list ldap.resetLockTimoutOnPasswordChange=true # Define an external url where the users can change their password @@ -904,13 +973,13 @@ ldap.deleteRemovedLDAPUsersOnSync=false # Value= 0 (never delete) to 100 (always delete). ldap.deleteRemovedLDAPUsersPercentage=50 # Should users be created and synchronized automatically on OLAT startup? Set this option to -# 'true' to create and sync all LDAP users in a batch manner on each OLAT startup.If you set +# 'true' to create and sync all LDAP users in a batch manner on each OLAT startup.If you set # this configuration to 'false', the users will be generated on-the-fly when they log in # For the cron syntax see http://quartz.sourceforge.net/javadoc/org/quartz/CronTrigger.html ldap.ldapSyncOnStartup=true # Independent of ldap.ldapSyncOnStartup, users can be created / synced in a batch manner -# peridically. Set ldap.ldapSyncCronSync=true if you want such a behaviour and set an -# appropriate cron expression to define the interval. The default cron expression will +# peridically. Set ldap.ldapSyncCronSync=true if you want such a behaviour and set an +# appropriate cron expression to define the interval. The default cron expression will # sync the LDAP database with the OLAT database each hour. ldap.ldapSyncCronSync=${ldap.ldapSyncOnStartup} ldap.ldapSyncCronSyncExpression=0 0 * * * ? @@ -919,7 +988,7 @@ ldap.ldapSyncCronSyncExpression=0 0 * * * ? ldap.ldapUserObjectClass=person # Filter that uses the user object class. Can be exteded to include group memberships as well. Default is a standard object class filter. ldap.ldapUserFilter=(objectClass=${ldap.ldapUserObjectClass}) -# Example for more complex filter: +# Example for more complex filter: # ldap.ldapUserFilter=(&(objectClass=${ldap.ldapUserObjectClass})(memberOf=CN=OpenOLATAccess,OU=Students,DC=openolat,DC=org)) # Attribute to resolve the DN of the suer during login (value is the internal attribute) ldap.ldapUserCreatedTimestampAttribute=whenCreated @@ -932,8 +1001,8 @@ ldap.attributename.useridentifyer=sAMAccountName ldap.attributename.email=mail ldap.attributename.firstName=givenName ldap.attributename.lastName=sn -# Attribute used as username to log in. Note: the configured login attribute MUST be one of the mapped attributes below, e.g. genericTextProperty1 -# If the login attribute should not be visible in OO, then disable the OO user property in all contexts. +# Attribute used as username to log in. Note: the configured login attribute MUST be one of the mapped attributes below, e.g. genericTextProperty1 +# If the login attribute should not be visible in OO, then disable the OO user property in all contexts. ldap.login.attribute=${ldap.attributename.useridentifyer} #mappings from ldap-attrib to olat-userproperty ldap.attrib.gen.map.ldapkey1= @@ -1074,7 +1143,7 @@ method.paypal.enabled=false paypal.security.user.id= # API PASSWORD, Replace RHS with your API password you obtained from sandbox/live server. paypal.security.password= -# API SIGNATURE ,If you are using the 3 token credential then you should uncomment the following +# API SIGNATURE ,If you are using the 3 token credential then you should uncomment the following # line and specify/change the signature on the RHS of the = sign. The module only implements the # 3 token credential. paypal.security.signature= @@ -1241,11 +1310,11 @@ monitoring.dependency.server=myserver video.enabled=true video.coursenode.enabled=true video.site.enable=false -# Enable transcoding if you want to create optimized version of your video for delivery. +# Enable transcoding if you want to create optimized version of your video for delivery. video.transcoding.enabled=false -# The transcoding process can run locally in s separate process using HandBrake. In that -# case, the binary "HandBrakeCLI" must be installed in your system and available to the -# java environment of your system. +# The transcoding process can run locally in s separate process using HandBrake. In that +# case, the binary "HandBrakeCLI" must be installed in your system and available to the +# java environment of your system. # Alternatively, you can disable local transcoding and implement a shell script that runs # on another server which reads from the o_vid_transcoding table to separate transcoding # from the main server. For larger installations it is recommendet to run the transcoding @@ -1257,18 +1326,18 @@ video.transcoding.taskset.cpuconfig.values=0,1 to indicate usage of 2 cores, set # List of transcoding versions to be generated by the transcoder video.transcoding.resolutions=1080,720,480,360 video.transcoding.resolutions.values=2160,1080,720,480,360,240 -# The preferred resolution if multiple video versions are available and the user has no +# The preferred resolution if multiple video versions are available and the user has no # customized setting. Should be a values from video.transcoding.resolutions video.transcoding.resolution.preferred=720 -# Where to store transcoded versions. This can be located on another path in case the -# transcoding service is working on another physical server or you just want it to use -# another (cheap) disk. By default it is also located in the olatdata dir. -# The master video files are kept in the olatdata directory, this is only about the +# Where to store transcoded versions. This can be located on another path in case the +# transcoding service is working on another physical server or you just want it to use +# another (cheap) disk. By default it is also located in the olatdata dir. +# The master video files are kept in the olatdata directory, this is only about the # transcoded versions. # If you set video.transcoding.local=false and use an external script for transcoding, this # other script must have access to this video.transcoding.dir as well to store the transcoded # videos. Make sure the access permissions are implemented in a way so that the OpenOLAT process -# can always delete the files from this video.transcoding.dir directory (when deleting the +# can always delete the files from this video.transcoding.dir directory (when deleting the # master video) video.transcoding.dir=${folder.root}/transcodedVideos video.transcoding.dir.values=${folder.root}/transcodedVideos, /mount/cheap/disk/transcodedVideos diff --git a/src/test/java/org/olat/shibboleth/handler/DoNothingHandlerTest.java b/src/test/java/org/olat/shibboleth/handler/DoNothingHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c8d6d87d84c9f6e7555185c7f5fd0455589a180e --- /dev/null +++ b/src/test/java/org/olat/shibboleth/handler/DoNothingHandlerTest.java @@ -0,0 +1,44 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * + * Initial date: 21.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class DoNothingHandlerTest { + + private DoNothingHandler sut = new DoNothingHandler(); + + @Test + public void parseShouldReturnTheSameString() { + String input = "input"; + + String parsed = sut.parse(input); + + assertThat(parsed).isEqualTo(input); + } +} diff --git a/src/test/java/org/olat/shibboleth/handler/FirstValueHandlerTest.java b/src/test/java/org/olat/shibboleth/handler/FirstValueHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c4e36edba17bd72ab0c9ac804e7a0ef6aeda8ab4 --- /dev/null +++ b/src/test/java/org/olat/shibboleth/handler/FirstValueHandlerTest.java @@ -0,0 +1,61 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * + * Initial date: 21.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class FirstValueHandlerTest { + + FirstValueHandler sut = new FirstValueHandler(); + + @Test + public void parseShoudReturnFirstValueIfMultipleVales() { + String expected = "abc"; + String input = expected + ";abc;222;a;erer;sdfsfd"; + + String parsed = sut.parse(input); + + assertThat(parsed).isEqualTo(expected); + } + + @Test + public void parseShoudReturnFirstValueIfOneValue() { + String input = "abc"; + + String parsed = sut.parse(input); + + assertThat(parsed).isEqualTo(input); + } + + @Test + public void parseShoudReturnFirstValueIfNull() { + String parsed = sut.parse(null); + + assertThat(parsed).isNull(); + } +} diff --git a/src/test/java/org/olat/shibboleth/handler/SchacGenderHandlerTest.java b/src/test/java/org/olat/shibboleth/handler/SchacGenderHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..99f8c10796fc5ecc19d7011121ba134cf247addd --- /dev/null +++ b/src/test/java/org/olat/shibboleth/handler/SchacGenderHandlerTest.java @@ -0,0 +1,72 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * + * Initial date: 21.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class SchacGenderHandlerTest { + + private SchacGenderHandler sut = new SchacGenderHandler(); + + @Test + public void parseShouldHandleMale() { + String schacMale = "1"; + String olatMale = "male"; + + String parsed = sut.parse(schacMale); + + assertThat(parsed).isEqualTo(olatMale); + } + + @Test + public void parseShouldHandleFemale() { + String schacFemale = "2"; + String olatFemale = "female"; + + String parsed = sut.parse(schacFemale); + + assertThat(parsed).isEqualTo(olatFemale); + } + + @Test + public void parseShouldHandleOther() { + String randomValue = "abc"; + String olatUnknown = "-"; + + String parsed = sut.parse(randomValue); + + assertThat(parsed).isEqualTo(olatUnknown); + } + + @Test + public void parseShouldHandleNull() { + String parsed = sut.parse(null); + + assertThat(parsed).isNull(); + } +} diff --git a/src/test/java/org/olat/shibboleth/manager/ShibbolethManagerImplTest.java b/src/test/java/org/olat/shibboleth/manager/ShibbolethManagerImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cddd9ee74705dcf9f022bd59710bb8a9162ab646 --- /dev/null +++ b/src/test/java/org/olat/shibboleth/manager/ShibbolethManagerImplTest.java @@ -0,0 +1,100 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.core.id.User; +import org.olat.core.id.UserConstants; +import org.olat.shibboleth.ShibbolethModule; +import org.olat.test.OlatTestCase; +import org.olat.user.UserImpl; + +/** + * + * Initial date: 19.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class ShibbolethManagerImplTest extends OlatTestCase { + + private final String DEFAULT_SHIBBOLETH_ATTRIBUTE_HANDLER = "DoNothingHandler"; + private final String LAST_NAME_SHIB_KEY = "lastNameShibKey"; + private final String LAST_NAME_USER_KEY = UserConstants.LASTNAME; + private final String LAST_NAME_VALUE = "lastName"; + private final String USER_PROPERTY_SHIB_KEY = "userPropertyShibKey"; + private final String USER_PROPERTY_USER_KEY = "city"; + private final String USER_PROPERTY_VALUE = "userProperty"; + private final String EXISTING_VALUE = "existingValue"; + private final Map<String, String> userMapping = new HashMap<>(); + private final Map<String, String> shibbolethAttributes = new HashMap<>(); + + @Mock + private ShibbolethModule shibbolethModuleMock; + + @InjectMocks + private ShibbolethManagerImpl sut; + + @Before + public void setUp() { + // init mocks + MockitoAnnotations.initMocks(this); + when(shibbolethModuleMock.getUserMapping()).thenReturn(userMapping); + when(shibbolethModuleMock.getShibbolethAttributeHandlerName(any(String.class))) + .thenReturn(DEFAULT_SHIBBOLETH_ATTRIBUTE_HANDLER); + + // init mapping + userMapping.put(LAST_NAME_SHIB_KEY, LAST_NAME_USER_KEY); + userMapping.put(USER_PROPERTY_SHIB_KEY, USER_PROPERTY_USER_KEY); + } + + @Test + public void syncAttributesShouldAddAttribute() { + User user = new UserImpl(); + shibbolethAttributes.put(LAST_NAME_SHIB_KEY, LAST_NAME_VALUE); + shibbolethAttributes.put(USER_PROPERTY_SHIB_KEY, USER_PROPERTY_VALUE); + + user = sut.syncAttributes(user, shibbolethAttributes); + + assertThat(user.getLastName()).isEqualTo(LAST_NAME_VALUE); + assertThat(user.getProperty(USER_PROPERTY_USER_KEY, null)).isEqualTo(USER_PROPERTY_VALUE); + } + + @Test + public void syncAttributesShouldRemovePropertyIfAttributeHasNoValue() { + User user = new UserImpl(); + user.setProperty(USER_PROPERTY_USER_KEY, EXISTING_VALUE); + + user = sut.syncAttributes(user, shibbolethAttributes); + + assertThat(user.getProperty(USER_PROPERTY_USER_KEY, null)).isNull(); + } + +} diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index f9f5ba03b3cbe6b3f914a2f941c6e24e977eaaa6..205981947b5b636a6478e326efeba88de383fa51 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -20,7 +20,7 @@ * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. +* under the Apache 2.0 license as the original file. * <p> */ package org.olat.test; @@ -40,7 +40,7 @@ package org.olat.test; import org.junit.runner.RunWith; import org.junit.runners.Suite; - + @RunWith(Suite.class) @Suite.SuiteClasses({ org.olat.core.util.i18n.I18nTest.class, @@ -324,12 +324,16 @@ import org.junit.runners.Suite; org.olat.modules.fo.WordCountTest.class, org.olat.modules.webFeed.manager.FeedManagerImplTest.class, org.olat.modules.webFeed.manager.RomeFeedFetcherTest.class, + org.olat.shibboleth.manager.ShibbolethManagerImplTest.class, + org.olat.shibboleth.handler.DoNothingHandlerTest.class, + org.olat.shibboleth.handler.FirstValueHandlerTest.class, + org.olat.shibboleth.handler.SchacGenderHandlerTest.class, /** - * + * * Place tests which load their own Spring context - * with @ContextConfiguration below the others as they may taint the + * with @ContextConfiguration below the others as they may taint the * cached Spring context - * + * * IMPORTANT: If you create mock spring contexts in the test source tree of olatcore and * you like to use them in olat3 you have to copy them to the test source tree of olat3 * as well as the tests on hudson run agains a jar version of olatcore where the test source