/**
* 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;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.olat.basesecurity.AuthHelper;
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;
import org.olat.core.dispatcher.DispatcherModule;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.ChiefController;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.ControllerEventListener;
import org.olat.core.gui.control.DefaultController;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.LocaleChangedEvent;
import org.olat.core.gui.control.WindowControl;
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.util.Util;
import org.olat.core.util.WebappHelper;
import org.olat.core.util.i18n.I18nManager;
import org.olat.core.util.session.UserSessionManager;
import org.olat.dispatcher.LocaleNegotiator;
import org.olat.registration.DisclaimerController;
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;
/**
* Initial Date: 09.08.2004
*
* @author Mike Stock
*
* Comment:
* User wants ShibbolethAuthentication
* - Basic flow:
* System asks User for username and create olataccount with ShibbolethAuthentication
* Branches:
* 1. no email in shibbolethAttributesMap
* - 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 {
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;
private boolean hasEmailInShibAttr;
@Autowired
private ShibbolethModule shibbolethModule;
@Autowired
private RegistrationModule registrationModule;
/**
* Implements the shibboleth registration workflow.
* @param ureq
* @param wControl
*/
public ShibbolethRegistrationController(UserRequest ureq, WindowControl wControl) {
super(wControl);
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) {
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);
return;
}
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);
if(locale == null) {
String preferedLanguage = shibbolethModule.getPreferedLanguage();
if(preferedLanguage == null) {
locale = LocaleNegotiator.getPreferedLocale(ureq);
} else {
locale = LocaleNegotiator.getNegotiatedLocale(preferedLanguage);
if(locale == null) {
locale = LocaleNegotiator.getPreferedLocale(ureq);
}
}
}
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);
if(proposedUsername == null) {
if(interceptor.allowChangeOfUsername()) {
setRegistrationForm(ureq, wControl, proposedUsername);
} else {
setErrorPage("sm.error.no_username", wControl);
}
} else {
Identity identity = BaseSecurityManager.getInstance().findIdentityByName(proposedUsername);
if(identity != null) {
if(interceptor.allowChangeOfUsername()) {
setRegistrationForm(ureq, wControl, proposedUsername);
} else {
setErrorPage("sm.error.username_in_use", wControl);
}
} else if(interceptor.allowChangeOfUsername()) {
setRegistrationForm(ureq, wControl, proposedUsername);
} else {
if(hasEmailInShibAttr) {
state = STATE_NEW_SHIB_USER;
mainContainer.setPage(VELOCITY_ROOT + "/disclaimer.html");
} else {
regWithEmailForm = new ShibbolethRegistrationWithEmailForm(ureq, wControl, proposedUsername);
regWithEmailForm.addControllerListener(this);
//mainContainer.put("regWithEmailForm", regWithEmailForm);
mainContainer.setPage(VELOCITY_ROOT + "/registerwithemail.html");
}
}
}
} else {
setRegistrationForm(ureq, wControl, null);
}
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
* @param attributes
*/
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
* @param uniqueID
*/
public static final void putShibUniqueID(HttpServletRequest req, String uniqueID) {
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)
*/
public void event(UserRequest ureq, Component source, Event event) {
if (event instanceof LocaleChangedEvent) {
LocaleChangedEvent lce = (LocaleChangedEvent)event;
Locale newLocale = lce.getNewLocale();
translator.setLocale(newLocale);
dclController.changeLocale(newLocale);
}
}
/**
* @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) {
if (event == Event.CANCELLED_EVENT) {
mainContainer.setPage(VELOCITY_ROOT + "/register.html");
} else if (event == Event.DONE_EVENT) {
state = STATE_MIGRATED_SHIB_USER;
mainContainer.setPage(VELOCITY_ROOT + "/disclaimer.html");
}
} else if (source == regWithEmailForm){
if (event == Event.CANCELLED_EVENT) {
mainContainer.setPage(VELOCITY_ROOT + "/register.html");
} 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);
regWithEmailForm.addControllerListener(this);
mainContainer.put("regWithEmailForm", regWithEmailForm.getInitialComponent());
mainContainer.setPage(VELOCITY_ROOT + "/registerwithemail.html");
} else { // there is an emailaddress
state = STATE_NEW_SHIB_USER;
mainContainer.setPage(VELOCITY_ROOT + "/disclaimer.html");
}
} else { // offer identity migration, if OLAT provider exists
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...
migrationForm = new ShibbolethMigrationForm(ureq, getWindowControl(), auth);
migrationForm.addControllerListener(this);
mainContainer.put("migrationForm", migrationForm.getInitialComponent());
mainContainer.setPage(VELOCITY_ROOT + "/migration.html");
}
}
}
} else if (source == languageChooserController) {
if (event == Event.DONE_EVENT) { // language choosed
mainContainer.setPage(VELOCITY_ROOT + "/register.html");
ureq.getUserSession().removeEntry(LocaleNegotiator.NEGOTIATED_LOCALE);
} else if (event instanceof LanguageChangedEvent) {
LanguageChangedEvent lcev = (LanguageChangedEvent)event;
translator.setLocale(lcev.getNewLocale());
dclController.changeLocale(lcev.getNewLocale());
}
} else if (source == dclController) {
if (event == Event.DONE_EVENT) { // disclaimer accepted...
if (state == STATE_NEW_SHIB_USER) { // ...proceed and create user
String choosenLogin;
if(regForm == null ) {
choosenLogin = proposedUsername;
} else {
choosenLogin = regForm.getLogin();
}
// check if login has been taken by another user in the meantime...
BaseSecurity secMgr = BaseSecurityManager.getInstance();
// check if login has been taken by another user in the meantime...
Identity identity = secMgr.findIdentityByName(choosenLogin);
if (identity != null) {
getWindowControl().setError(translator.translate("sr.login.meantimetaken"));
mainContainer.setPage(VELOCITY_ROOT + "/register.html");
state = STATE_UNDEFINED;
return;
}
String email;
if(!hasEmailInShibAttr){
email = regWithEmailForm.getEmail();
} else {
email = ShibbolethHelper.getFirstValueOf(shibbolethModule.getEMail(), shibbolethAttributesMap);
}
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
getWindowControl().setError(translator.translate("sr.error.emailexists", new String[] {WebappHelper.getMailConfig("mailSupport")}));
mainContainer.setPage(VELOCITY_ROOT + "/register.html");
state = STATE_UNDEFINED;
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 = 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);
return;
} else if (state == STATE_MIGRATED_SHIB_USER) { // ...proceed and migrate user
// create additional authentication
Authentication auth = migrationForm.getAuthentication();
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);
doLogin(authenticationedIdentity, ureq);
return;
}
} else if (event == Event.CANCELLED_EVENT) {
mainContainer.setPage(VELOCITY_ROOT + "/register.html");
getWindowControl().setError(translator.translate("sr.error.disclaimer"));
}
}
}
private void doLogin(Identity identity, UserRequest ureq) {
int loginStatus = AuthHelper.doLogin(identity, ShibbolethDispatcher.PROVIDER_SHIB, ureq);
if (loginStatus != AuthHelper.LOGIN_OK) {
//REVIEW:2010-01-11:revisited:pb: do not redirect if already MediaResource is set before
//ureq.getDispatchResult().setResultingMediaResource(resultingMediaResource);
//instead set the media resource accordingly
//pb -> provide a DispatcherAction.getDefaultDispatcherRedirectMediaresource();
//to be used here. (and some more places like CatalogController.
DispatcherModule.redirectToDefaultDispatcher(ureq.getHttpResp()); // error, redirect to login screen
return;
}
// successfull login
ureq.getUserSession().getIdentityEnvironment().addAttributes(
shibbolethModule.getAttributeTranslator().translateAttributesMap(shibbolethAttributesMap));
}
/**
*
* @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
*/
protected void doDispose() {
if (dclController != null) {
dclController.dispose();
dclController = null;
}
if (languageChooserController != null) {
languageChooserController.dispose();
languageChooserController = null;
}
}
}