/**
* 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.
* <p>
*/
package org.olat.login;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import org.olat.basesecurity.AuthHelper;
import org.olat.basesecurity.Authentication;
import org.olat.basesecurity.ManagerFactory;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.form.Form;
import org.olat.core.gui.components.link.Link;
import org.olat.core.gui.components.link.LinkFactory;
import org.olat.core.gui.components.panel.Panel;
import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
import org.olat.core.id.Identity;
import org.olat.core.logging.OLATSecurityException;
import org.olat.core.logging.Tracing;
import org.olat.core.util.Encoder;
import org.olat.core.util.Util;
import org.olat.core.util.WebappHelper;
import org.olat.core.util.mail.MailHelper;
import org.olat.login.auth.AuthenticationController;
import org.olat.login.auth.OLATAuthentcationForm;
import org.olat.registration.DisclaimerController;
import org.olat.registration.PwChangeController;
import org.olat.registration.RegistrationController;
import org.olat.registration.RegistrationManager;
import org.olat.registration.RegistrationModule;
import org.olat.registration.TemporaryKey;
import org.olat.user.UserManager;
import org.olat.user.UserModule;
import com.thoughtworks.xstream.XStream;
/**
* Initial Date: 04.08.2004
*
* @author Mike Stock
*/
public class OLATAuthenticationController extends AuthenticationController {
/** identified this authentication provider */
public static final String PROVIDER_OLAT = "OLAT";
public static final String PARAM_LOGINERROR = "loginerror";
private VelocityContainer loginComp;
private OLATAuthentcationForm loginForm;
private Identity authenticatedIdentity;
private Controller subController;
private CloseableModalController cmc;
private DisclaimerController disclaimerCtr;
private Link pwLink;
private Link registerLink;
private Link anoLink;
private Panel mainPanel;
/**
* @see org.olat.login.auth.AuthenticationController#init(org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl)
*/
public OLATAuthenticationController(UserRequest ureq, WindowControl winControl) {
// use fallback translator to registration module
super(ureq, winControl, Util.createPackageTranslator(RegistrationManager.class, ureq.getLocale()));
loginComp = createVelocityContainer("olatlogin");
if(UserModule.isPwdchangeallowed()) {
pwLink = LinkFactory.createLink("menu.pw", loginComp, this);
pwLink.setCustomEnabledLinkCSS("o_login_pwd");
}
if (RegistrationModule.isSelfRegistrationEnabled()) {
registerLink = LinkFactory.createLink("menu.register", loginComp, this);
registerLink.setCustomEnabledLinkCSS("o_login_register");
}
if (LoginModule.isGuestLoginLinksEnabled()) {
anoLink = LinkFactory.createLink("menu.guest", loginComp, this);
anoLink.setCustomEnabledLinkCSS("o_login_guests");
}
// prepare login form
loginForm = new OLATAuthentcationForm("loginForm", getTranslator());
loginForm.addListener(this);
loginComp.put("loginForm",loginForm);
// Check if form is triggered by external loginworkflow that has been failed
if (ureq.getParameterSet().contains(PARAM_LOGINERROR)) {
getWindowControl().setError(translate("login.error", WebappHelper.getMailConfig("mailSupport")));
}
// support email
loginComp.contextPut("supportmailaddress", WebappHelper.getMailConfig("mailSupport"));
mainPanel = putInitialPanel(loginComp);
}
/**
* @see org.olat.login.auth.AuthenticationController#changeLocale(java.util.Locale)
*/
public void changeLocale(Locale newLocale) {
setLocale(newLocale, true);
}
/**
* @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 (source == loginForm) { // process login form events
if (event == Form.EVNT_VALIDATION_OK) {
String login = loginForm.getLogin();
String pass = loginForm.getPass();
authenticatedIdentity = authenticate(login, pass);
if (authenticatedIdentity == null) {
if (LoginModule.registerFailedLoginAttempt(login)) {
logAudit("Too many failed login attempts for " + login + ". Login blocked.", null);
getWindowControl().setError(translate("login.blocked", LoginModule.getAttackPreventionTimeoutMin().toString()));
return;
} else {
getWindowControl().setError(translate("login.error", WebappHelper.getMailConfig("mailSupport")));
return;
}
}
LoginModule.clearFailedLoginAttempts(login);
// Check if disclaimer has been accepted
if (RegistrationManager.getInstance().needsToConfirmDisclaimer(authenticatedIdentity)) {
// accept disclaimer first
disclaimerCtr = new DisclaimerController(ureq, getWindowControl());
listenTo(disclaimerCtr);
cmc = new CloseableModalController(getWindowControl(), translate("close"), disclaimerCtr.getInitialComponent());
listenTo(cmc);
cmc.activate();
} else {
// disclaimer acceptance not required
authenticated(ureq, authenticatedIdentity);
}
}
} else if (source == registerLink) {
subController = new RegistrationController(ureq, getWindowControl());
listenTo(subController);
cmc = new CloseableModalController(getWindowControl(), translate("close"), subController.getInitialComponent());
cmc.activate();
listenTo(cmc);
} else if (source == pwLink) {
// double-check if allowed first
if (!UserModule.isPwdchangeallowed()) throw new OLATSecurityException("chose password to be changed, but disallowed by config");
subController = new PwChangeController(ureq, getWindowControl());
listenTo(subController);
cmc = new CloseableModalController(getWindowControl(), translate("close"), subController.getInitialComponent());
cmc.activate();
listenTo(cmc);
} else if (source == anoLink){
int loginStatus = AuthHelper.doAnonymousLogin(ureq, ureq.getLocale());
if (loginStatus == AuthHelper.LOGIN_OK) {
return;
} else if (loginStatus == AuthHelper.LOGIN_NOTAVAILABLE){
getWindowControl().setError(translate("login.notavailable", WebappHelper.getMailConfig("mailSupport")));
} else {
getWindowControl().setError(translate("login.error", WebappHelper.getMailConfig("mailSupport")));
}
}
}
/**
* @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)
*/
public void event(UserRequest ureq, Controller source, Event event) {
if (source == subController) {
if (event == Event.CANCELLED_EVENT || event == Event.DONE_EVENT) {
cmc.deactivate();
removeAsListenerAndDispose(subController);
removeAsListenerAndDispose(cmc);
}
} else if (source == cmc) {
// cmc closes window itself. The only thing we do is cleanup of child controllers
removeAsListenerAndDispose(subController);
removeAsListenerAndDispose(cmc);
} else if (source == disclaimerCtr) {
cmc.deactivate();
removeAsListenerAndDispose(cmc);
removeAsListenerAndDispose(disclaimerCtr);
if (event == Event.DONE_EVENT) {
// User accepted disclaimer, do login now
RegistrationManager.getInstance().setHasConfirmedDislaimer(authenticatedIdentity);
authenticated(ureq, authenticatedIdentity);
} else if (event == Event.CANCELLED_EVENT) {
// User did not accept, workflow ends here
showWarning("disclaimer.form.cancelled");
}
}
}
/**
* @param login
* @param pass
* @return Identity if authentication was successfull, null otherwise.
* @deprecated should not be part of the controller
*/
public static Identity authenticate(String login, String pass) {
if (pass == null) return null; // do never accept empty passwords
Identity ident = ManagerFactory.getManager().findIdentityByName(login);
// check for email instead of username if ident is null
if (ident == null && LoginModule.allowLoginUsingEmail()) {
if (MailHelper.isValidEmailAddress(login)){
ident = UserManager.getInstance().findIdentityByEmail(login);
}
// check for email changed with verification workflow
if (ident == null) {
ident = findIdentInChangingEmailWorkflow(login);
}
}
if (ident == null) return null;
// find OLAT authentication provider
Authentication auth = ManagerFactory.getManager()
.findAuthentication(ident, OLATAuthenticationController.PROVIDER_OLAT);
if (auth != null && auth.getCredential().equals(Encoder.encrypt(pass))) return ident;
Tracing.logAudit("Error authenticating user "+login+" via provider OLAT", OLATAuthenticationController.class);
return null;
}
private static Identity findIdentInChangingEmailWorkflow(String login){
RegistrationManager rm = RegistrationManager.getInstance();
List<TemporaryKey> tk = rm.loadTemporaryKeyByAction(RegistrationManager.EMAIL_CHANGE);
if (tk != null) {
for (TemporaryKey temporaryKey : tk) {
XStream xml = new XStream();
HashMap<String, String> mails = (HashMap<String, String>) xml.fromXML(temporaryKey.getEmailAddress());
if (login.equals(mails.get("changedEMail"))) {
return ManagerFactory.getManager().findIdentityByName(mails.get("currentEMail"));
}
}
}
return null;
}
/**
* @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
*/
protected void doDispose() {
// disposed by BasicController:
subController = null;
disclaimerCtr = null;
cmc = null;
}
}