diff --git a/src/main/java/org/olat/admin/user/imp/TransientIdentity.java b/src/main/java/org/olat/admin/user/imp/TransientIdentity.java index fad7b2470525fe1cc3786c40da5bc1d8c659cd7d..c10747776e9ea3cf573d8808dba757750d398db0 100644 --- a/src/main/java/org/olat/admin/user/imp/TransientIdentity.java +++ b/src/main/java/org/olat/admin/user/imp/TransientIdentity.java @@ -85,6 +85,11 @@ public class TransientIdentity implements Identity, User { return properties.get(UserConstants.EMAIL); } + @Override + public String getInstitutionalEmail() { + return properties.get(UserConstants.INSTITUTIONALEMAIL); + } + public String getPassword() { return password; } diff --git a/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java b/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java index 60b9c43c0fc31eca06bfa9dd5295f90a2d019e17..bcfaf150e09372c21b38e5beafd478ff9e380710 100644 --- a/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java +++ b/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java @@ -168,6 +168,11 @@ public class UpdateIdentity implements Identity { return updatedProperties.get(UserConstants.EMAIL); } + @Override + public String getInstitutionalEmail() { + return updatedProperties.get(UserConstants.INSTITUTIONALEMAIL); + } + @Override public Date getCreationDate() { return user.getCreationDate(); diff --git a/src/main/java/org/olat/basesecurity/BaseSecurity.java b/src/main/java/org/olat/basesecurity/BaseSecurity.java index c2445becd78ba24a3d1fc8aa92b68b84719cd7ac..e37f2d1bc73409250da8f9877d6f4325a4a31c1d 100644 --- a/src/main/java/org/olat/basesecurity/BaseSecurity.java +++ b/src/main/java/org/olat/basesecurity/BaseSecurity.java @@ -367,6 +367,8 @@ public interface BaseSecurity { */ public Authentication findAuthentication(IdentityRef identity, String provider); + public List<Authentication> findAuthentications(IdentityRef identity, List<String> providers); + public String findAuthenticationName(IdentityRef identity, String provider); @@ -526,6 +528,9 @@ public interface BaseSecurity { * found */ public Authentication findAuthenticationByAuthusername(String authusername, String provider); + + + public List<Authentication> findAuthenticationByAuthusername(String authusername, List<String> providers); /** diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java index d71ffa545081bac5350051de15ee371f098bb8b6..8cd688ad74dd73e080c5e351935c8bea756bbbb8 100644 --- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java +++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java @@ -1,4 +1,5 @@ /** + * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> @@ -1384,6 +1385,18 @@ public class BaseSecurityManager implements BaseSecurity { return results.get(0); } + @Override + public List<Authentication> findAuthentications(IdentityRef identity, List<String> providers) { + StringBuilder sb = new StringBuilder(); + sb.append("select auth from ").append(AuthenticationImpl.class.getName()) + .append(" as auth where auth.identity.key=:identityKey and auth.provider in (:providers)"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Authentication.class) + .setParameter("identityKey", identity.getKey()) + .setParameter("providers", providers) + .getResultList(); + } + @Override public String findAuthenticationName(IdentityRef identity, String provider) { if (identity==null) { @@ -1518,6 +1531,19 @@ public class BaseSecurityManager implements BaseSecurity { } return results.get(0); } + + @Override + public List<Authentication> findAuthenticationByAuthusername(String authusername, List<String> providers) { + StringBuilder sb = new StringBuilder(); + sb.append("select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth") + .append(" inner join fetch auth.identity ident") + .append(" where auth.provider in (:providers) and auth.authusername=:authusername"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Authentication.class) + .setParameter("providers", providers) + .setParameter("authusername", authusername) + .getResultList(); + } /** * @see org.olat.basesecurity.Manager#getVisibleIdentitiesByPowerSearch(java.lang.String, java.util.Map, boolean, org.olat.basesecurity.SecurityGroup[], org.olat.basesecurity.PermissionOnResourceable[], java.lang.String[], java.util.Date, java.util.Date) diff --git a/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVAuthManager.java b/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVAuthManager.java index ec28f37f574d9e7d6a9e681d507e895d39f22691..589bb4e4844249d5d821d759f6265881f473ad53 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVAuthManager.java +++ b/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVAuthManager.java @@ -20,6 +20,9 @@ package org.olat.core.commons.services.webdav.manager; +import java.util.ArrayList; +import java.util.List; + import org.olat.basesecurity.Authentication; import org.olat.basesecurity.BaseSecurity; import org.olat.core.commons.services.webdav.WebDAVModule; @@ -49,7 +52,11 @@ import org.springframework.stereotype.Service; public class WebDAVAuthManager implements AuthenticationSPI { public static final String PROVIDER_WEBDAV = "WEBDAV"; + public static final String PROVIDER_WEBDAV_EMAIL = "WEBDAV-E"; + public static final String PROVIDER_WEBDAV_INSTITUTIONAL_EMAIL = "WEBDAV-I"; public static final String PROVIDER_HA1 = "HA1"; + public static final String PROVIDER_HA1_EMAIL = "HA1-E"; + public static final String PROVIDER_HA1_INSTITUTIONAL_EMAIL = "HA1-I"; private static final OLog log = Tracing.createLoggerFor(WebDAVAuthManager.class); @@ -65,25 +72,31 @@ public class WebDAVAuthManager implements AuthenticationSPI { public Identity digestAuthentication(String httpMethod, DigestAuthentication digestAuth) { String username = digestAuth.getUsername(); - Authentication olatAuth = securityManager.findAuthenticationByAuthusername(username, WebDAVAuthManager.PROVIDER_HA1); - if(olatAuth != null) { - if("auth".equals(digestAuth.getQop())) { - String nonce = digestAuth.getNonce(); - String response = digestAuth.getResponse(); - - String ha1 = olatAuth.getCredential(); - - String a2 = httpMethod + ":" + digestAuth.getUri(); - String ha2 = Encoder.md5hash(a2); - - String ver = ha1 + ":" + nonce + ":" + digestAuth.getNc() + ":" + digestAuth.getCnonce() + ":" + digestAuth.getQop() + ":" + ha2; - String verity = Encoder.md5hash(ver); - if(verity.equals(response)) { - Identity identity = olatAuth.getIdentity(); - return identity; - } else if(log.isDebug()) { - // don't log as error, happens all the time with certain clients, e.g. Microsoft-WebDAV-MiniRedir - log.debug("Verity::" + verity + " doesn't equals response::" + response); + List<String> providers = new ArrayList<>(3); + providers.add(PROVIDER_HA1); + providers.add(PROVIDER_HA1_EMAIL); + providers.add(PROVIDER_HA1_INSTITUTIONAL_EMAIL); + + List<Authentication> authentications = securityManager.findAuthenticationByAuthusername(username, providers); + if(authentications != null && authentications.size() > 0) { + for(Authentication authentication:authentications) { + if("auth".equals(digestAuth.getQop())) { + String nonce = digestAuth.getNonce(); + String response = digestAuth.getResponse(); + + String ha1 = authentication.getCredential(); + + String a2 = httpMethod + ":" + digestAuth.getUri(); + String ha2 = Encoder.md5hash(a2); + + String ver = ha1 + ":" + nonce + ":" + digestAuth.getNc() + ":" + digestAuth.getCnonce() + ":" + digestAuth.getQop() + ":" + ha2; + String verity = Encoder.md5hash(ver); + if(verity.equals(response)) { + return authentication.getIdentity(); + } else if(log.isDebug()) { + // don't log as error, happens all the time with certain clients, e.g. Microsoft-WebDAV-MiniRedir + log.debug("Verity::" + verity + " doesn't equals response::" + response); + } } } } @@ -92,30 +105,37 @@ public class WebDAVAuthManager implements AuthenticationSPI { @Override public Identity authenticate(Identity identity, String login, String password) { - Authentication authentication = null; + List<String> providers = new ArrayList<>(3); + providers.add(PROVIDER_WEBDAV); + providers.add(PROVIDER_WEBDAV_EMAIL); + providers.add(PROVIDER_WEBDAV_INSTITUTIONAL_EMAIL); + + List<Authentication> authentications = null; if (identity != null) { - authentication = securityManager.findAuthentication(identity, PROVIDER_WEBDAV); + authentications = securityManager.findAuthentications(identity, providers); } else { - authentication = securityManager.findAuthenticationByAuthusername(login, PROVIDER_WEBDAV); + authentications = securityManager.findAuthenticationByAuthusername(login, providers); } - if(authentication == null) { + if(authentications == null || authentications.isEmpty()) { //fallback to standard OLAT authentication return olatAuthenticationSpi.authenticate(identity, login, password); } - Identity authenticatedIdentity = authentication.getIdentity(); + Identity authenticatedIdentity = authentications.get(0).getIdentity(); boolean visible = securityManager.isIdentityVisible(authenticatedIdentity); if (!visible) { return null; } - if (securityManager.checkCredentials(authentication, password)) { - Algorithm algorithm = Algorithm.find(authentication.getAlgorithm()); - if(Algorithm.md5.equals(algorithm)) { - authentication = securityManager.updateCredentials(authentication, password, loginModule.getDefaultHashAlgorithm()); + for(Authentication authentication:authentications) { + if (securityManager.checkCredentials(authentication, password)) { + Algorithm algorithm = Algorithm.find(authentication.getAlgorithm()); + if(Algorithm.md5.equals(algorithm)) { + authentication = securityManager.updateCredentials(authentication, password, loginModule.getDefaultHashAlgorithm()); + } + return authentication.getIdentity(); } - return authentication.getIdentity(); } return null; } @@ -123,12 +143,8 @@ public class WebDAVAuthManager implements AuthenticationSPI { @Override public void upgradePassword(Identity identity, String login, String password) { if(webDAVModule.isEnabled() && webDAVModule.isDigestAuthenticationEnabled()) { - Authentication digestAuth = securityManager.findAuthentication(identity, PROVIDER_HA1); - if(digestAuth == null) { - String digestToken = login + ":" + WebDAVManagerImpl.BASIC_AUTH_REALM + ":" + password; - Identity reloadedIdentity = securityManager.loadIdentityByKey(identity.getKey()); - securityManager.createAndPersistAuthentication(reloadedIdentity, PROVIDER_HA1, login, digestToken, Encoder.Algorithm.md5_noSalt); - } + List<Authentication> digestAuths = securityManager.getAuthentications(identity); + updateDigestPasswords(identity, identity, password, digestAuths); } } @@ -140,27 +156,51 @@ public class WebDAVAuthManager implements AuthenticationSPI { * @return True upon success. */ public boolean changePassword(Identity doer, Identity identity, String newPwd) { - if (doer==null) throw new AssertException("password changing identity cannot be undefined!"); - if (identity == null || identity.getKey() == null) + if (doer==null) { + throw new AssertException("password changing identity cannot be undefined!"); + } + if (identity == null || identity.getKey() == null) { throw new AssertException("cannot change password on a nonpersisted identity"); + } //For Basic - Authentication auth = securityManager.findAuthentication(identity, PROVIDER_WEBDAV); - if (auth == null) { // create new authentication for provider OLAT + List<Authentication> auths = securityManager.getAuthentications(identity); + updateWebdavPassword(doer, identity, newPwd, auths); + //For Digest + changeDigestPassword(doer, identity, newPwd); + return true; + } + + private void updateWebdavPassword(Identity doer, Identity identity, String password, List<Authentication> authentications) { + updateWebDAVPassword(doer, identity, identity.getName(), password, PROVIDER_WEBDAV, authentications); + if(identity.getUser().getEmail() != null) { + updateWebDAVPassword(doer, identity, identity.getUser().getEmail(), password, PROVIDER_WEBDAV_EMAIL, authentications); + } + if(identity.getUser().getInstitutionalEmail() != null) { + updateWebDAVPassword(doer, identity, identity.getUser().getEmail(), password, PROVIDER_WEBDAV_INSTITUTIONAL_EMAIL, authentications); + } + + for(Authentication authentication:authentications) { + if(authentication.getProvider().startsWith(PROVIDER_WEBDAV)) { + securityManager.deleteAuthentication(authentication); + } + } + } + + private void updateWebDAVPassword(Identity doer, Identity identity, String authUsername, String password, + String provider, List<Authentication> authentications) { + Authentication authentication = getAndRemoveAuthentication(provider, authentications); + if (authentication == null) { // create new authentication for provider OLAT Identity reloadedIdentity = securityManager.loadIdentityByKey(identity.getKey()); - auth = securityManager.createAndPersistAuthentication(reloadedIdentity, PROVIDER_WEBDAV, identity.getName(), newPwd, loginModule.getDefaultHashAlgorithm()); - log.audit(doer.getName() + " created new WebDAV authentication for identity: " + identity.getName()); + securityManager.createAndPersistAuthentication(reloadedIdentity, provider, authUsername, password, loginModule.getDefaultHashAlgorithm()); + log.audit(doer.getName() + " created new WebDAV authentication for identity: " + identity.getKey() + " (" + authUsername + ")"); } else { - auth = securityManager.updateCredentials(auth, newPwd, loginModule.getDefaultHashAlgorithm()); - log.audit(doer.getName() + " set new WebDAV password for identity: " +identity.getName()); + securityManager.updateCredentials(authentication, password, loginModule.getDefaultHashAlgorithm()); + log.audit(doer.getName() + " set new WebDAV password for identity: " + identity.getKey() + " (" + authUsername + ")"); } - - //For Digest - changeDigestPassword(doer, identity, identity.getName(), newPwd); - return true; } - public boolean changeDigestPassword(Identity doer, Identity identity, String username, String newPwd) { + public boolean changeDigestPassword(Identity doer, Identity identity, String newPwd) { if (doer == null) { throw new AssertException("password changing identity cannot be undefined!"); } @@ -170,22 +210,57 @@ public class WebDAVAuthManager implements AuthenticationSPI { //For Digest if(webDAVModule.isDigestAuthenticationEnabled()) { - Authentication authHa1 = securityManager.findAuthentication(identity, PROVIDER_HA1); - String digestToken = username + ":" + WebDAVManagerImpl.BASIC_AUTH_REALM + ":" + newPwd; + List<Authentication> ha1Authentications = securityManager.getAuthentications(identity); + updateDigestPasswords(doer, identity, newPwd, ha1Authentications); + } + return true; + } + + private void updateDigestPasswords(Identity doer, Identity identity, String newPwd, + List<Authentication> authentications) { + updateDigestPassword(doer, identity, identity.getName(), newPwd, PROVIDER_HA1, authentications); + if(identity.getUser().getEmail() != null) { + updateDigestPassword(doer, identity, identity.getUser().getEmail(), newPwd, PROVIDER_HA1_EMAIL, authentications); + } + if(identity.getUser().getInstitutionalEmail() != null) { + updateDigestPassword(doer, identity, identity.getUser().getEmail(), newPwd, PROVIDER_HA1_INSTITUTIONAL_EMAIL, authentications); + } + + for(Authentication authentication:authentications) { + if(authentication.getProvider().startsWith(PROVIDER_HA1)) { + securityManager.deleteAuthentication(authentication); + } + } + } + + private void updateDigestPassword(Identity doer, Identity identity, String authUsername, String password, + String provider, List<Authentication> authentications) { + String digestToken = authUsername + ":" + WebDAVManagerImpl.BASIC_AUTH_REALM + ":" + password; + Authentication authHa1 = getAndRemoveAuthentication(provider, authentications); + if (authHa1 == null) { // create new authentication for provider OLAT + Identity reloadedIdentity = securityManager.loadIdentityByKey(identity.getKey()); + securityManager.createAndPersistAuthentication(reloadedIdentity, provider, authUsername, digestToken, Encoder.Algorithm.md5_noSalt); + log.audit(doer.getName() + " created new WebDAV (HA1) authentication for identity: " + identity.getKey() + " (" + authUsername + ")"); + } else { String md5DigestToken = Encoder.encrypt(digestToken, null, Encoder.Algorithm.md5_noSalt); - - if (authHa1 == null) { // create new authentication for provider OLAT - Identity reloadedIdentity = securityManager.loadIdentityByKey(identity.getKey()); - authHa1 = securityManager.createAndPersistAuthentication(reloadedIdentity, PROVIDER_HA1, username, digestToken, Encoder.Algorithm.md5_noSalt); - log.audit(doer.getName() + " created new WebDAV (HA1) authenticatin for identity: " + identity.getName()); - } else if (username != null && (!username.equals(authHa1.getAuthusername()) || !md5DigestToken.equals(authHa1.getCredential()))) { + if (!md5DigestToken.equals(authHa1.getCredential()) || !authHa1.getAuthusername().equals(authUsername)) { authHa1.setCredential(md5DigestToken); - authHa1.setAuthusername(username); - authHa1 = securityManager.updateAuthentication(authHa1); - log.audit(doer.getName() + " set new WebDAV (HA1) password for identity: " +identity.getName()); + authHa1.setAuthusername(authUsername); + securityManager.updateAuthentication(authHa1); + log.audit(doer.getName() + " set new WebDAV (HA1) password for identity: " + identity.getKey() + " (" + authUsername + ")"); } } - - return true; + } + + private Authentication getAndRemoveAuthentication(String provider, List<Authentication> authentications) { + if(authentications != null && authentications.size() > 0) { + for(Authentication authentication:authentications) { + if(provider.equals(authentication.getProvider())) { + authentications.remove(authentication); + return authentication; + } + } + } + return null; } } diff --git a/src/main/java/org/olat/core/id/User.java b/src/main/java/org/olat/core/id/User.java index 6ae56a24694d3fbc7edfa22882513d8078ea58e5..a91134f158d68e8990660318adecaa288b8f3ae6 100644 --- a/src/main/java/org/olat/core/id/User.java +++ b/src/main/java/org/olat/core/id/User.java @@ -49,6 +49,8 @@ public interface User extends CreateInfo, Persistable { public String getLastName(); public String getEmail(); + + public String getInstitutionalEmail(); /** * Get the users prefereces object diff --git a/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java b/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java index 031897abccbb0ae6a446254eb124b06d83bb2e16..655aef4d8a164354dba3abf4eb09591b9ae85386 100644 --- a/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java +++ b/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java @@ -121,6 +121,11 @@ public class EMailIdentity implements Identity { return data.get(UserConstants.EMAIL); } + @Override + public String getInstitutionalEmail() { + return data.get(UserConstants.INSTITUTIONALEMAIL); + } + @Override public Date getLastModified() { return null; diff --git a/src/main/java/org/olat/course/run/preview/PreviewIdentity.java b/src/main/java/org/olat/course/run/preview/PreviewIdentity.java index 8ec50a0f737f1eec21ca0b9b9db9f7fb92a666fd..f1053729bc1493ea75372796e06cf05c03d1e3b3 100644 --- a/src/main/java/org/olat/course/run/preview/PreviewIdentity.java +++ b/src/main/java/org/olat/course/run/preview/PreviewIdentity.java @@ -85,6 +85,11 @@ public final class PreviewIdentity implements Identity, User { return data.get(UserConstants.EMAIL); } + @Override + public String getInstitutionalEmail() { + return data.get(UserConstants.INSTITUTIONALEMAIL); + } + @Override public String getFirstName() { return data.get(UserConstants.FIRSTNAME); diff --git a/src/main/java/org/olat/login/auth/OLATAuthManager.java b/src/main/java/org/olat/login/auth/OLATAuthManager.java index db0509ecbcf85d970d67aaded0f75b1046ef22da..bb6028877c8d63c3b982b20c079064f8ea03a062 100644 --- a/src/main/java/org/olat/login/auth/OLATAuthManager.java +++ b/src/main/java/org/olat/login/auth/OLATAuthManager.java @@ -269,7 +269,7 @@ public class OLATAuthManager extends BasicManager implements AuthenticationSPI { } if(identity != null && StringHelper.containsNonWhitespace(username) && webDAVAuthManager != null) { - webDAVAuthManager.changeDigestPassword(doer, identity, username, newPwd); + webDAVAuthManager.changeDigestPassword(doer, identity, newPwd); } return true; } @@ -294,7 +294,7 @@ public class OLATAuthManager extends BasicManager implements AuthenticationSPI { } if(identity != null && StringHelper.containsNonWhitespace(username) && webDAVAuthManager != null) { - webDAVAuthManager.changeDigestPassword(doer, identity, username, newPwd); + webDAVAuthManager.changeDigestPassword(doer, identity, newPwd); } return true; } diff --git a/src/main/java/org/olat/user/UserImpl.java b/src/main/java/org/olat/user/UserImpl.java index 97bd673daf327ad2ff554bfaedf4bebfcafd324b..7b0fba26c4a380086ea04c4a9a07412914252358 100644 --- a/src/main/java/org/olat/user/UserImpl.java +++ b/src/main/java/org/olat/user/UserImpl.java @@ -318,6 +318,7 @@ public class UserImpl implements Persistable, User { this.firstName = firstName; } + @Override public String getLastName() { return lastName; } @@ -326,6 +327,7 @@ public class UserImpl implements Persistable, User { this.lastName = lastName; } + @Override public String getEmail() { return email; } @@ -334,6 +336,15 @@ public class UserImpl implements Persistable, User { this.email = email; } + @Override + public String getInstitutionalEmail() { + return institutionalEmail; + } + + public void setInstitutionalEmail(String institutionalEmail) { + this.institutionalEmail = institutionalEmail; + } + public boolean isWebdav() { return webdav; } diff --git a/src/main/java/org/olat/user/WebDAVPasswordController.java b/src/main/java/org/olat/user/WebDAVPasswordController.java index 517e67822ee9450d8c24d5ffda55334afc599d23..0527c7a643d1726949e1929b592ce6930e72f62f 100644 --- a/src/main/java/org/olat/user/WebDAVPasswordController.java +++ b/src/main/java/org/olat/user/WebDAVPasswordController.java @@ -87,7 +87,16 @@ public class WebDAVPasswordController extends FormBasicController { accessDataFlc = FormLayoutContainer.createDefaultFormLayout("flc_access_data", getTranslator()); layoutContainer.add(accessDataFlc); - uifactory.addStaticTextElement("pwdav.username", "pwdav.username", ureq.getIdentity().getName(), accessDataFlc); + + StringBuilder sb = new StringBuilder(); + sb.append(getIdentity().getName()); + if(StringHelper.containsNonWhitespace(getIdentity().getUser().getEmail())) { + sb.append(", ").append(getIdentity().getUser().getEmail()); + } + if(StringHelper.containsNonWhitespace(getIdentity().getUser().getInstitutionalEmail())) { + sb.append(", ").append(getIdentity().getUser().getInstitutionalEmail()); + } + uifactory.addStaticTextElement("pwdav.username", "pwdav.username", sb.toString(), accessDataFlc); boolean hasOlatToken = false; boolean hasWebDAVToken = false;