Skip to content
Snippets Groups Projects
Commit afe7ec74 authored by srosse's avatar srosse
Browse files

OO-3449: implements disclaimer for OAuth provider with auto creation of userss

parent cb9de329
No related branches found
No related tags found
No related merge requests found
Showing
with 268 additions and 26 deletions
...@@ -30,7 +30,6 @@ import org.olat.basesecurity.AuthenticationImpl; ...@@ -30,7 +30,6 @@ import org.olat.basesecurity.AuthenticationImpl;
import org.olat.basesecurity.BaseSecurityModule; import org.olat.basesecurity.BaseSecurityModule;
import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.IdentityRef;
import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DB;
import org.olat.ldap.ui.LDAPAuthenticationController;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -90,7 +89,8 @@ public class AuthenticationDAO { ...@@ -90,7 +89,8 @@ public class AuthenticationDAO {
* @param maxAge The max. age of the authentication in seconds * @param maxAge The max. age of the authentication in seconds
* @return * @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); StringBuilder sb = new StringBuilder(256);
sb.append("select auth.key from ").append(AuthenticationImpl.class.getName()).append(" as auth") sb.append("select auth.key from ").append(AuthenticationImpl.class.getName()).append(" as auth")
.append(" where auth.identity.key=:identityKey and ((auth.provider=:olatProvider"); .append(" where auth.identity.key=:identityKey and ((auth.provider=:olatProvider");
...@@ -101,19 +101,18 @@ public class AuthenticationDAO { ...@@ -101,19 +101,18 @@ public class AuthenticationDAO {
if(maxAge > 0) { if(maxAge > 0) {
sb.append(" and auth.lastModified>=:maxDate"); sb.append(" and auth.lastModified>=:maxDate");
} }
sb.append(") or auth.provider=:ldapProvider) "); sb.append(") or auth.provider in (:providers))");
TypedQuery<Long> query = dbInstance.getCurrentEntityManager() TypedQuery<Long> query = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Long.class) .createQuery(sb.toString(), Long.class)
.setParameter("identityKey", identity.getKey()) .setParameter("identityKey", identity.getKey())
.setParameter("olatProvider", BaseSecurityModule.getDefaultAuthProviderIdentifier()) .setParameter("olatProvider", BaseSecurityModule.getDefaultAuthProviderIdentifier())
.setParameter("ldapProvider", LDAPAuthenticationController.PROVIDER_LDAP); .setParameter("providers", exceptionProviders);
if(maxAge > 0) { if(maxAge > 0) {
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, -maxAge); cal.add(Calendar.SECOND, -maxAge);
query.setParameter("maxDate", cal.getTime()); query.setParameter("maxDate", cal.getTime());
System.out.println(cal.getTime());
} }
List<Long> keys = query List<Long> keys = query
......
...@@ -140,6 +140,14 @@ ...@@ -140,6 +140,14 @@
</property> </property>
</bean> </bean>
</entry> </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 --> <!-- triggers email change workflow -->
<entry key="/emchange/"> <entry key="/emchange/">
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
*/ */
package org.olat.login.auth; package org.olat.login.auth;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
...@@ -60,8 +61,11 @@ import org.olat.ldap.LDAPLoginModule; ...@@ -60,8 +61,11 @@ import org.olat.ldap.LDAPLoginModule;
import org.olat.ldap.ui.LDAPAuthenticationController; import org.olat.ldap.ui.LDAPAuthenticationController;
import org.olat.login.LoginModule; import org.olat.login.LoginModule;
import org.olat.login.OLATAuthenticationController; 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.RegistrationManager;
import org.olat.registration.TemporaryKey; import org.olat.registration.TemporaryKey;
import org.olat.shibboleth.ShibbolethDispatcher;
import org.olat.user.UserManager; import org.olat.user.UserManager;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -75,6 +79,8 @@ public class OLATAuthManager implements AuthenticationSPI { ...@@ -75,6 +79,8 @@ public class OLATAuthManager implements AuthenticationSPI {
private static final OLog log = Tracing.createLoggerFor(OLATAuthManager.class); private static final OLog log = Tracing.createLoggerFor(OLATAuthManager.class);
@Autowired
private OAuthLoginModule oauthModule;
@Autowired @Autowired
private UserManager userManager; private UserManager userManager;
@Autowired @Autowired
...@@ -161,7 +167,13 @@ public class OLATAuthManager implements AuthenticationSPI { ...@@ -161,7 +167,13 @@ public class OLATAuthManager implements AuthenticationSPI {
* @return * @return
*/ */
public boolean hasValidAuthentication(IdentityRef identity, boolean changeOnce, int maxAge) { 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 @Override
......
...@@ -33,6 +33,9 @@ public interface OAuthConstants { ...@@ -33,6 +33,9 @@ public interface OAuthConstants {
public static final String REQUEST_TOKEN = "oauthToken"; public static final String REQUEST_TOKEN = "oauthToken";
public static final String OAUTH_SERVICE = "oauthService"; public static final String OAUTH_SERVICE = "oauthService";
public static final String OAUTH_REGISTER_PATH = "oauthregister"; 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_SPI = "oauthSpi";
public static final String OAUTH_STATE = "oauthState"; public static final String OAUTH_STATE = "oauthState";
public static final String OAUTH_NONCE = "oauthNonce"; public static final String OAUTH_NONCE = "oauthNonce";
......
...@@ -90,8 +90,7 @@ public class OAuthDispatcher implements Dispatcher { ...@@ -90,8 +90,7 @@ public class OAuthDispatcher implements Dispatcher {
throw new AssertException("UTF-8 encoding not supported!!!!"); throw new AssertException("UTF-8 encoding not supported!!!!");
} }
String uriPrefix = DispatcherModule.getLegacyUriPrefix(request); String uriPrefix = DispatcherModule.getLegacyUriPrefix(request);
uri = uri.substring(uriPrefix.length());
UserRequest ureq = null; UserRequest ureq = null;
try{ try{
//upon creation URL is checked for //upon creation URL is checked for
...@@ -155,19 +154,16 @@ public class OAuthDispatcher implements Dispatcher { ...@@ -155,19 +154,16 @@ public class OAuthDispatcher implements Dispatcher {
login(infos, registration); login(infos, registration);
if(provider instanceof OAuthUserCreator) { if(provider instanceof OAuthUserCreator) {
Identity newIdentity;
OAuthUserCreator userCreator = (OAuthUserCreator)provider; OAuthUserCreator userCreator = (OAuthUserCreator)provider;
if(registration.getIdentity() == null) { if(registration.getIdentity() != null) {
newIdentity = userCreator.createUser(infos); Identity newIdentity = userCreator.updateUser(infos, registration.getIdentity());
} else { registration.setIdentity(newIdentity);
newIdentity = userCreator.updateUser(infos, registration.getIdentity());
}
if(newIdentity != null) {
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()) { if(CoreSpringFactory.getImpl(OAuthLoginModule.class).isAllowUserCreation()) {
register(request, response, registration); register(request, response, registration);
} else { } else {
...@@ -270,6 +266,16 @@ public class OAuthDispatcher implements Dispatcher { ...@@ -270,6 +266,16 @@ public class OAuthDispatcher implements Dispatcher {
msgcc.getWindow().dispatchRequest(ureq, true); 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) { private void register(HttpServletRequest request, HttpServletResponse response, OAuthRegistration registration) {
try { try {
request.getSession().setAttribute("oauthRegistration", registration); request.getSession().setAttribute("oauthRegistration", registration);
......
/**
* <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
/**
* <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);
}
}
}
...@@ -167,7 +167,7 @@ public class OAuthRegistrationController extends FormBasicController { ...@@ -167,7 +167,7 @@ public class OAuthRegistrationController extends FormBasicController {
@Override @Override
protected boolean validateFormLogic(UserRequest ureq) { protected boolean validateFormLogic(UserRequest ureq) {
boolean allOk = true; boolean allOk = super.validateFormLogic(ureq);
// validate each user field // validate each user field
for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
FormItem fi = propFormItems.get(userPropertyHandler.getName()); FormItem fi = propFormItems.get(userPropertyHandler.getName());
...@@ -191,7 +191,7 @@ public class OAuthRegistrationController extends FormBasicController { ...@@ -191,7 +191,7 @@ public class OAuthRegistrationController extends FormBasicController {
allOk &= false; allOk &= false;
} }
} }
return allOk & super.validateFormLogic(ureq); return allOk;
} }
@Override @Override
......
...@@ -66,8 +66,8 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -66,8 +66,8 @@ import org.springframework.beans.factory.annotation.Autowired;
public class DisclaimerController extends BasicController { public class DisclaimerController extends BasicController {
private final String SR_ERROR_DISCLAIMER_CHECKBOX = "sr.error.disclaimer.checkbox"; private static 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_CHECKBOXES = "sr.error.disclaimer.checkboxes";
private VelocityContainer main; private VelocityContainer main;
private DisclaimerFormController disclaimerFormController; private DisclaimerFormController disclaimerFormController;
......
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
*/ */
package org.olat.basesecurity.manager; package org.olat.basesecurity.manager;
import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.junit.Assert; import org.junit.Assert;
...@@ -29,6 +31,7 @@ import org.olat.basesecurity.AuthenticationImpl; ...@@ -29,6 +31,7 @@ import org.olat.basesecurity.AuthenticationImpl;
import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurity;
import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DB;
import org.olat.core.id.Identity; import org.olat.core.id.Identity;
import org.olat.ldap.ui.LDAPAuthenticationController;
import org.olat.restapi.security.RestSecurityBeanImpl; import org.olat.restapi.security.RestSecurityBeanImpl;
import org.olat.test.JunitTestHelper; import org.olat.test.JunitTestHelper;
import org.olat.test.OlatTestCase; import org.olat.test.OlatTestCase;
...@@ -86,16 +89,18 @@ public class AuthenticationDAOTest extends OlatTestCase { ...@@ -86,16 +89,18 @@ public class AuthenticationDAOTest extends OlatTestCase {
Authentication auth = securityManager.createAndPersistAuthentication(ident, "OLAT", ident.getName(), token, null); Authentication auth = securityManager.createAndPersistAuthentication(ident, "OLAT", ident.getName(), token, null);
dbInstance.commitAndCloseSession(); dbInstance.commitAndCloseSession();
Assert.assertNotNull(auth); Assert.assertNotNull(auth);
System.out.println(auth.getLastModified());
List<String> fullProviders = new ArrayList<>();
fullProviders.add(LDAPAuthenticationController.PROVIDER_LDAP);
//check nothing at the end //check nothing at the end
boolean valid = authenticationDao.hasValidOlatAuthentication(ident, false, 0); boolean valid = authenticationDao.hasValidOlatAuthentication(ident, false, 0, fullProviders);
Assert.assertTrue(valid); Assert.assertTrue(valid);
//check if the authentication is new //check if the authentication is new
boolean brandNew = authenticationDao.hasValidOlatAuthentication(ident, true, 0); boolean brandNew = authenticationDao.hasValidOlatAuthentication(ident, true, 0, fullProviders);
Assert.assertFalse(brandNew); Assert.assertFalse(brandNew);
//check if the authentication is new //check if the authentication is new
boolean fresh = authenticationDao.hasValidOlatAuthentication(ident, false, 60); boolean fresh = authenticationDao.hasValidOlatAuthentication(ident, false, 60, fullProviders);
Assert.assertTrue(fresh); Assert.assertTrue(fresh);
} }
...@@ -115,7 +120,9 @@ public class AuthenticationDAOTest extends OlatTestCase { ...@@ -115,7 +120,9 @@ public class AuthenticationDAOTest extends OlatTestCase {
dbInstance.commitAndCloseSession(); dbInstance.commitAndCloseSession();
//check if the authentication is new //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); Assert.assertFalse(tooOld);
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment