diff --git a/src/main/java/org/olat/basesecurity/manager/AuthenticationDAO.java b/src/main/java/org/olat/basesecurity/manager/AuthenticationDAO.java index fc20364deb31a3ea240fdef9170c5360b39cd0b1..c321d2fb5f34becc76832c157cd74bfe475a3074 100644 --- a/src/main/java/org/olat/basesecurity/manager/AuthenticationDAO.java +++ b/src/main/java/org/olat/basesecurity/manager/AuthenticationDAO.java @@ -30,7 +30,6 @@ import org.olat.basesecurity.AuthenticationImpl; import org.olat.basesecurity.BaseSecurityModule; import org.olat.basesecurity.IdentityRef; import org.olat.core.commons.persistence.DB; -import org.olat.ldap.ui.LDAPAuthenticationController; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -90,7 +89,8 @@ public class AuthenticationDAO { * @param maxAge The max. age of the authentication in seconds * @return */ - public boolean hasValidOlatAuthentication(IdentityRef identity, boolean changeOnce, int maxAge) { + public boolean hasValidOlatAuthentication(IdentityRef identity, boolean changeOnce, int maxAge, + List<String> exceptionProviders) { StringBuilder sb = new StringBuilder(256); sb.append("select auth.key from ").append(AuthenticationImpl.class.getName()).append(" as auth") .append(" where auth.identity.key=:identityKey and ((auth.provider=:olatProvider"); @@ -101,19 +101,18 @@ public class AuthenticationDAO { if(maxAge > 0) { sb.append(" and auth.lastModified>=:maxDate"); } - sb.append(") or auth.provider=:ldapProvider) "); + sb.append(") or auth.provider in (:providers))"); TypedQuery<Long> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Long.class) .setParameter("identityKey", identity.getKey()) .setParameter("olatProvider", BaseSecurityModule.getDefaultAuthProviderIdentifier()) - .setParameter("ldapProvider", LDAPAuthenticationController.PROVIDER_LDAP); + .setParameter("providers", exceptionProviders); if(maxAge > 0) { Calendar cal = Calendar.getInstance(); cal.add(Calendar.SECOND, -maxAge); query.setParameter("maxDate", cal.getTime()); - System.out.println(cal.getTime()); } List<Long> keys = query diff --git a/src/main/java/org/olat/core/dispatcher/_spring/dispatcherContext.xml b/src/main/java/org/olat/core/dispatcher/_spring/dispatcherContext.xml index 479e62acff4ca2be8b897b569047a4dab72bcdb0..13b532450d7b961fc669c34ad7762b4802259224 100644 --- a/src/main/java/org/olat/core/dispatcher/_spring/dispatcherContext.xml +++ b/src/main/java/org/olat/core/dispatcher/_spring/dispatcherContext.xml @@ -140,6 +140,14 @@ </property> </bean> </entry> + <!-- triggers oauth registration workflow --> + <entry key="/oauthdisclaimer/"> + <bean class="org.olat.core.gui.control.ChiefControllerCreator"> + <property name="contentControllerCreator"> + <bean class="org.olat.login.oauth.ui.OAuthDisclaimerCreator" /> + </property> + </bean> + </entry> <!-- triggers email change workflow --> <entry key="/emchange/"> diff --git a/src/main/java/org/olat/login/auth/OLATAuthManager.java b/src/main/java/org/olat/login/auth/OLATAuthManager.java index ce614b2f2772ec51484df548bc551226f217f692..ecbb70c31d52bc236231d31f9b125d7a02beef76 100644 --- a/src/main/java/org/olat/login/auth/OLATAuthManager.java +++ b/src/main/java/org/olat/login/auth/OLATAuthManager.java @@ -24,6 +24,7 @@ */ package org.olat.login.auth; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -60,8 +61,11 @@ import org.olat.ldap.LDAPLoginModule; import org.olat.ldap.ui.LDAPAuthenticationController; import org.olat.login.LoginModule; import org.olat.login.OLATAuthenticationController; +import org.olat.login.oauth.OAuthLoginModule; +import org.olat.login.oauth.OAuthSPI; import org.olat.registration.RegistrationManager; import org.olat.registration.TemporaryKey; +import org.olat.shibboleth.ShibbolethDispatcher; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -75,6 +79,8 @@ public class OLATAuthManager implements AuthenticationSPI { private static final OLog log = Tracing.createLoggerFor(OLATAuthManager.class); + @Autowired + private OAuthLoginModule oauthModule; @Autowired private UserManager userManager; @Autowired @@ -161,7 +167,13 @@ public class OLATAuthManager implements AuthenticationSPI { * @return */ public boolean hasValidAuthentication(IdentityRef identity, boolean changeOnce, int maxAge) { - return authenticationDao.hasValidOlatAuthentication(identity, changeOnce, maxAge); + List<String> fullProviders = new ArrayList<>(); + fullProviders.add(LDAPAuthenticationController.PROVIDER_LDAP); + fullProviders.add(ShibbolethDispatcher.PROVIDER_SHIB); + for(OAuthSPI spi:oauthModule.getAllSPIs()) { + fullProviders.add(spi.getProviderName()); + } + return authenticationDao.hasValidOlatAuthentication(identity, changeOnce, maxAge, fullProviders); } @Override diff --git a/src/main/java/org/olat/login/oauth/OAuthConstants.java b/src/main/java/org/olat/login/oauth/OAuthConstants.java index b2354f6b71ba68da31ae45f1dd89c85c8b19dd6c..1c3154af1c898cc184ae9f16e92d3c8582b22ee1 100644 --- a/src/main/java/org/olat/login/oauth/OAuthConstants.java +++ b/src/main/java/org/olat/login/oauth/OAuthConstants.java @@ -33,6 +33,9 @@ public interface OAuthConstants { public static final String REQUEST_TOKEN = "oauthToken"; public static final String OAUTH_SERVICE = "oauthService"; public static final String OAUTH_REGISTER_PATH = "oauthregister"; + public static final String OAUTH_DISCLAIMER_PATH = "oauthdisclaimer"; + public static final String OAUTH_USER_CREATOR_ATTR = "oauthUserCreator"; + public static final String OAUTH_USER_ATTR = "oauthUser"; public static final String OAUTH_SPI = "oauthSpi"; public static final String OAUTH_STATE = "oauthState"; public static final String OAUTH_NONCE = "oauthNonce"; diff --git a/src/main/java/org/olat/login/oauth/OAuthDispatcher.java b/src/main/java/org/olat/login/oauth/OAuthDispatcher.java index 355cdfed18cf2da37afe865fc649f04816d857d2..b3e39e9327a60f0578a06ee9b05f2c970e40e416 100644 --- a/src/main/java/org/olat/login/oauth/OAuthDispatcher.java +++ b/src/main/java/org/olat/login/oauth/OAuthDispatcher.java @@ -90,8 +90,7 @@ public class OAuthDispatcher implements Dispatcher { throw new AssertException("UTF-8 encoding not supported!!!!"); } String uriPrefix = DispatcherModule.getLegacyUriPrefix(request); - uri = uri.substring(uriPrefix.length()); - + UserRequest ureq = null; try{ //upon creation URL is checked for @@ -155,19 +154,16 @@ public class OAuthDispatcher implements Dispatcher { login(infos, registration); if(provider instanceof OAuthUserCreator) { - Identity newIdentity; OAuthUserCreator userCreator = (OAuthUserCreator)provider; - if(registration.getIdentity() == null) { - newIdentity = userCreator.createUser(infos); - } else { - newIdentity = userCreator.updateUser(infos, registration.getIdentity()); - } - if(newIdentity != null) { - registration.setIdentity(newIdentity); + if(registration.getIdentity() != null) { + Identity newIdentity = userCreator.updateUser(infos, registration.getIdentity()); + registration.setIdentity(newIdentity); } } - if(registration.getIdentity() == null) { + if(provider instanceof OAuthUserCreator && registration.getIdentity() == null) { + disclaimer(request, response, infos, (OAuthUserCreator)provider); + } else if(registration.getIdentity() == null) { if(CoreSpringFactory.getImpl(OAuthLoginModule.class).isAllowUserCreation()) { register(request, response, registration); } else { @@ -270,6 +266,16 @@ public class OAuthDispatcher implements Dispatcher { msgcc.getWindow().dispatchRequest(ureq, true); } + private void disclaimer(HttpServletRequest request, HttpServletResponse response, OAuthUser user, OAuthUserCreator userCreator) { + try { + request.getSession().setAttribute(OAuthConstants.OAUTH_USER_CREATOR_ATTR, userCreator); + request.getSession().setAttribute(OAuthConstants.OAUTH_USER_ATTR, user); + response.sendRedirect(WebappHelper.getServletContextPath() + DispatcherModule.getPathDefault() + OAuthConstants.OAUTH_DISCLAIMER_PATH + "/"); + } catch (IOException e) { + log.error("Redirect failed: url=" + WebappHelper.getServletContextPath() + DispatcherModule.getPathDefault(),e); + } + } + private void register(HttpServletRequest request, HttpServletResponse response, OAuthRegistration registration) { try { request.getSession().setAttribute("oauthRegistration", registration); diff --git a/src/main/java/org/olat/login/oauth/ui/OAuthDisclaimerController.java b/src/main/java/org/olat/login/oauth/ui/OAuthDisclaimerController.java new file mode 100644 index 0000000000000000000000000000000000000000..7787a93dffa3046401a652e717b083626f6dfe0d --- /dev/null +++ b/src/main/java/org/olat/login/oauth/ui/OAuthDisclaimerController.java @@ -0,0 +1,148 @@ +/** + * <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.login.oauth.ui; + +import java.util.List; + +import org.olat.admin.user.delete.service.UserDeletionManager; +import org.olat.basesecurity.AuthHelper; +import org.olat.core.dispatcher.DispatcherModule; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +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.gui.control.generic.dtabs.Activateable2; +import org.olat.core.id.Identity; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.Util; +import org.olat.core.util.WebappHelper; +import org.olat.login.oauth.OAuthUserCreator; +import org.olat.login.oauth.model.OAuthUser; +import org.olat.registration.DisclaimerController; +import org.olat.registration.RegistrationForm2; +import org.olat.registration.RegistrationManager; +import org.olat.user.propertyhandlers.UserPropertyHandler; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * This controller opens the disclaimer and if accepted + * create the user in background. + * + * Initial date: 20 avr. 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class OAuthDisclaimerController extends FormBasicController implements Activateable2 { + + public static final String USERPROPERTIES_FORM_IDENTIFIER = OAuthDisclaimerController.class.getCanonicalName(); + + private final OAuthUser user; + private final OAuthUserCreator userCreator; + + private CloseableModalController cmc; + private DisclaimerController disclaimerController; + + @Autowired + private RegistrationManager registrationManager; + + public OAuthDisclaimerController(UserRequest ureq, WindowControl wControl, OAuthUser user, OAuthUserCreator userCreator) { + super(ureq, wControl); + setTranslator(Util.createPackageTranslator(RegistrationForm2.class, getLocale(), getTranslator())); + setTranslator(Util.createPackageTranslator(UserPropertyHandler.class, getLocale(), getTranslator())); + + this.user = user; + this.userCreator = userCreator; + initForm(ureq); + } + + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + disclaimerController = new DisclaimerController(ureq, getWindowControl()); + listenTo(disclaimerController); + + cmc = new CloseableModalController(getWindowControl(), translate("close"), disclaimerController.getInitialComponent(), + true, translate("disclaimer.title")); + cmc.activate(); + listenTo(cmc); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + // + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(disclaimerController == source) { + cmc.deactivate(); + + if (event == Event.DONE_EVENT) { + // User accepted disclaimer, do login now + Identity authenticatedIdentity; + if(userCreator != null) { + authenticatedIdentity = userCreator.createUser(user); + registrationManager.setHasConfirmedDislaimer(authenticatedIdentity); + doLoginAndRegister(authenticatedIdentity, ureq); + } + } else if (event == Event.CANCELLED_EVENT) { + // User did not accept, workflow ends here + showWarning("disclaimer.form.cancelled"); + } + cleanUp(); + } else if(cmc == source) { + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + removeAsListenerAndDispose(disclaimerController); + removeAsListenerAndDispose(cmc); + disclaimerController = null; + cmc = null; + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + private void doLoginAndRegister(Identity authIdentity, UserRequest ureq) { + // prepare redirects to home etc, set status + int loginStatus = AuthHelper.doLogin(authIdentity, null, ureq); + if (loginStatus == AuthHelper.LOGIN_OK) { + //update last login date and register active user + UserDeletionManager.getInstance().setIdentityAsActiv(authIdentity); + } else if (loginStatus == AuthHelper.LOGIN_NOTAVAILABLE){ + DispatcherModule.redirectToServiceNotAvailable( ureq.getHttpResp() ); + } else { + getWindowControl().setError(translate("login.error", WebappHelper.getMailConfig("mailSupport"))); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/login/oauth/ui/OAuthDisclaimerCreator.java b/src/main/java/org/olat/login/oauth/ui/OAuthDisclaimerCreator.java new file mode 100644 index 0000000000000000000000000000000000000000..da7fe32042e79da38d6764dd28c7bdfc5096ffb3 --- /dev/null +++ b/src/main/java/org/olat/login/oauth/ui/OAuthDisclaimerCreator.java @@ -0,0 +1,59 @@ +/** + * <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.login.oauth.ui; + +import org.olat.core.commons.fullWebApp.BaseFullWebappController; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.creator.ControllerCreator; +import org.olat.login.DmzBFWCParts; +import org.olat.login.oauth.OAuthConstants; +import org.olat.login.oauth.OAuthUserCreator; +import org.olat.login.oauth.model.OAuthUser; + +/** + * + * Initial date: 20 avr. 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class OAuthDisclaimerCreator implements ControllerCreator { + + @Override + public Controller createController(UserRequest ureq, WindowControl wControl) { + DmzBFWCParts parts = new DmzBFWCParts(); + parts.setContentControllerCreator(new InternalCreator()); + BaseFullWebappController ctrl = new BaseFullWebappController(ureq, parts); + ctrl.activate(ureq, null, null); + return ctrl; + } + + private static class InternalCreator implements ControllerCreator { + @Override + public Controller createController(UserRequest ureq, WindowControl wControl) { + OAuthUser user = (OAuthUser)ureq.getHttpReq() + .getSession().getAttribute(OAuthConstants.OAUTH_USER_ATTR); + OAuthUserCreator userCreator = (OAuthUserCreator)ureq.getHttpReq() + .getSession().getAttribute(OAuthConstants.OAUTH_USER_CREATOR_ATTR); + return new OAuthDisclaimerController(ureq, wControl, user, userCreator); + } + } +} diff --git a/src/main/java/org/olat/login/oauth/ui/OAuthRegistrationController.java b/src/main/java/org/olat/login/oauth/ui/OAuthRegistrationController.java index 1759ab1e2d8e84efb389a528949739a37602ab05..120890c319aae761f39979d315173b71a2c64ac1 100644 --- a/src/main/java/org/olat/login/oauth/ui/OAuthRegistrationController.java +++ b/src/main/java/org/olat/login/oauth/ui/OAuthRegistrationController.java @@ -167,7 +167,7 @@ public class OAuthRegistrationController extends FormBasicController { @Override protected boolean validateFormLogic(UserRequest ureq) { - boolean allOk = true; + boolean allOk = super.validateFormLogic(ureq); // validate each user field for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { FormItem fi = propFormItems.get(userPropertyHandler.getName()); @@ -191,7 +191,7 @@ public class OAuthRegistrationController extends FormBasicController { allOk &= false; } } - return allOk & super.validateFormLogic(ureq); + return allOk; } @Override diff --git a/src/main/java/org/olat/registration/DisclaimerController.java b/src/main/java/org/olat/registration/DisclaimerController.java index 90bb3384f8ef5878dfc98234ad5dba7a4787f051..17de3a8a5b4fdac26ad289434deff21e8c7ac8e6 100644 --- a/src/main/java/org/olat/registration/DisclaimerController.java +++ b/src/main/java/org/olat/registration/DisclaimerController.java @@ -66,8 +66,8 @@ import org.springframework.beans.factory.annotation.Autowired; public class DisclaimerController extends BasicController { - private final String SR_ERROR_DISCLAIMER_CHECKBOX = "sr.error.disclaimer.checkbox"; - private final String SR_ERROR_DISCLAIMER_CHECKBOXES = "sr.error.disclaimer.checkboxes"; + private static final String SR_ERROR_DISCLAIMER_CHECKBOX = "sr.error.disclaimer.checkbox"; + private static final String SR_ERROR_DISCLAIMER_CHECKBOXES = "sr.error.disclaimer.checkboxes"; private VelocityContainer main; private DisclaimerFormController disclaimerFormController; diff --git a/src/test/java/org/olat/basesecurity/manager/AuthenticationDAOTest.java b/src/test/java/org/olat/basesecurity/manager/AuthenticationDAOTest.java index d0025316a117ea6ed7b08e6bfd990c70ec275bba..0ed6727ee338e970fac93ebed9540561297cd1c0 100644 --- a/src/test/java/org/olat/basesecurity/manager/AuthenticationDAOTest.java +++ b/src/test/java/org/olat/basesecurity/manager/AuthenticationDAOTest.java @@ -19,7 +19,9 @@ */ package org.olat.basesecurity.manager; +import java.util.ArrayList; import java.util.Calendar; +import java.util.List; import java.util.UUID; import org.junit.Assert; @@ -29,6 +31,7 @@ import org.olat.basesecurity.AuthenticationImpl; import org.olat.basesecurity.BaseSecurity; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; +import org.olat.ldap.ui.LDAPAuthenticationController; import org.olat.restapi.security.RestSecurityBeanImpl; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; @@ -86,16 +89,18 @@ public class AuthenticationDAOTest extends OlatTestCase { Authentication auth = securityManager.createAndPersistAuthentication(ident, "OLAT", ident.getName(), token, null); dbInstance.commitAndCloseSession(); Assert.assertNotNull(auth); - System.out.println(auth.getLastModified()); + + List<String> fullProviders = new ArrayList<>(); + fullProviders.add(LDAPAuthenticationController.PROVIDER_LDAP); //check nothing at the end - boolean valid = authenticationDao.hasValidOlatAuthentication(ident, false, 0); + boolean valid = authenticationDao.hasValidOlatAuthentication(ident, false, 0, fullProviders); Assert.assertTrue(valid); //check if the authentication is new - boolean brandNew = authenticationDao.hasValidOlatAuthentication(ident, true, 0); + boolean brandNew = authenticationDao.hasValidOlatAuthentication(ident, true, 0, fullProviders); Assert.assertFalse(brandNew); //check if the authentication is new - boolean fresh = authenticationDao.hasValidOlatAuthentication(ident, false, 60); + boolean fresh = authenticationDao.hasValidOlatAuthentication(ident, false, 60, fullProviders); Assert.assertTrue(fresh); } @@ -115,7 +120,9 @@ public class AuthenticationDAOTest extends OlatTestCase { dbInstance.commitAndCloseSession(); //check if the authentication is new - boolean tooOld = authenticationDao.hasValidOlatAuthentication(ident, false, 60); + List<String> fullProviders = new ArrayList<>(); + fullProviders.add(LDAPAuthenticationController.PROVIDER_LDAP); + boolean tooOld = authenticationDao.hasValidOlatAuthentication(ident, false, 60, fullProviders); Assert.assertFalse(tooOld); } }