diff --git a/src/main/java/org/olat/admin/user/imp/ImportStep00.java b/src/main/java/org/olat/admin/user/imp/ImportStep00.java index f68ac727d16fa4e20757388a44cffd35344b5c5e..ac4438260513bb634717da63c0953e5ec82e8158 100644 --- a/src/main/java/org/olat/admin/user/imp/ImportStep00.java +++ b/src/main/java/org/olat/admin/user/imp/ImportStep00.java @@ -58,6 +58,7 @@ import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; import org.olat.registration.RegistrationManager; import org.olat.registration.TemporaryKey; +import org.olat.shibboleth.ShibbolethModule; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; @@ -197,7 +198,10 @@ class ImportStep00 extends BasicStep { if (parts.length > columnId) { pwd = parts[columnId].trim(); if (StringHelper.containsNonWhitespace(pwd)) { - if (!UserManager.getInstance().syntaxCheckOlatPassword(pwd)) { + if(pwd.startsWith(UserImportController.SHIBBOLETH_MARKER) + && ShibbolethModule.isEnableShibbolethLogins()) { + //something to check? + } else if (!UserManager.getInstance().syntaxCheckOlatPassword(pwd)) { textAreaElement.setErrorKey("error.pwd", new String[] { String.valueOf(i + 1), pwd }); importDataError = true; break; @@ -241,7 +245,7 @@ class ImportStep00 extends BasicStep { idents.add(uIdentity); updateIdents.add(uIdentity); - importDataError = updateUserProperties(uIdentity, parts, i, columnId, tempEmailsInUse, importedEmails, true); + importDataError = updateUserProperties(uIdentity, parts, i, columnId, tempEmailsInUse, importedEmails); if(importDataError) break; } else { // no identity/user yet, create @@ -260,7 +264,7 @@ class ImportStep00 extends BasicStep { ud.setName(login); ud.setPassword(pwd); ud.setLanguage(lang); - importDataError = updateUserProperties(ud, parts, i, columnId, tempEmailsInUse, importedEmails, false); + importDataError = updateUserProperties(ud, parts, i, columnId, tempEmailsInUse, importedEmails); if(importDataError) break; idents.add(ud); @@ -290,7 +294,7 @@ class ImportStep00 extends BasicStep { } private boolean updateUserProperties(Identity ud, String[] parts, int i, int columnId, - Set<String> tempEmailsInUse, List<String> importedEmails, boolean update) { + Set<String> tempEmailsInUse, List<String> importedEmails) { boolean importDataError = false; for (int j = 0; j < userPropertyHandlers.size(); j++) { diff --git a/src/main/java/org/olat/admin/user/imp/UserImportController.java b/src/main/java/org/olat/admin/user/imp/UserImportController.java index 8e69ff2a751645f9999917dfab89bd63701e472c..bae0dfd4a2791e5b8163b2a1f517ed97c70049ca 100644 --- a/src/main/java/org/olat/admin/user/imp/UserImportController.java +++ b/src/main/java/org/olat/admin/user/imp/UserImportController.java @@ -30,6 +30,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import org.olat.basesecurity.AuthHelper; import org.olat.basesecurity.Authentication; @@ -56,6 +57,8 @@ import org.olat.core.util.mail.MailPackage; import org.olat.group.BusinessGroupService; import org.olat.group.model.BusinessGroupMembershipChange; import org.olat.login.auth.OLATAuthManager; +import org.olat.shibboleth.ShibbolethDispatcher; +import org.olat.shibboleth.ShibbolethModule; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; @@ -71,6 +74,8 @@ import org.olat.user.propertyhandlers.UserPropertyHandler; */ public class UserImportController extends BasicController { + public static final String SHIBBOLETH_MARKER = "SHIBBOLETH::"; + private List<UserPropertyHandler> userPropertyHandlers; private static final String usageIdentifyer = UserImportController.class.getCanonicalName(); private boolean canCreateOLATPassword; @@ -106,6 +111,7 @@ public class UserImportController extends BasicController { * @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==importStepsController){ if (event == Event.CANCELLED_EVENT) { @@ -113,13 +119,25 @@ public class UserImportController extends BasicController { removeAsListenerAndDispose(importStepsController); } else if (event == Event.CHANGED_EVENT || event == Event.DONE_EVENT) { getWindowControl().pop(); + StepsRunContext ctxt = importStepsController.getRunContext(); + ImportReport report = (ImportReport)ctxt.get("report"); removeAsListenerAndDispose(importStepsController); - showInfo("import.success"); + if(report.isHasErrors()) { + StringBuilder errorMsg = new StringBuilder(); + errorMsg.append("<ul>"); + for(String error:report.getErrors()) { + errorMsg.append("<li>").append(error).append("</li>"); + } + errorMsg.append("</ul>"); + showError("import.errors", errorMsg.toString()); + } else { + showInfo("import.success"); + } } } } - private Identity doCreateAndPersistIdentity(TransientIdentity singleUser) { + private Identity doCreateAndPersistIdentity(TransientIdentity singleUser, ImportReport report) { // Create new user and identity and put user to users group String login = singleUser.getName(); //pos 0 is used for existing/non-existing user flag String pwd = singleUser.getPassword(); @@ -148,24 +166,52 @@ public class UserImportController extends BasicController { newUser.getPreferences().setLanguage(lang); newUser.getPreferences().setInformSessionTimeout(true); // Save everything in database - Identity ident = AuthHelper.createAndPersistIdentityAndUserWithUserGroup(login, pwd, newUser); + Identity ident; + if(pwd.startsWith(SHIBBOLETH_MARKER) && ShibbolethModule.isEnableShibbolethLogins()) { + String uniqueID = pwd.substring(SHIBBOLETH_MARKER.length()); + ident = AuthHelper.createAndPersistIdentityAndUserWithUserGroup(login, ShibbolethDispatcher.PROVIDER_SHIB, uniqueID, newUser); + report.incrementCreatedUser(); + report.incrementUpdatedShibboletAuthentication(); + } else { + ident = AuthHelper.createAndPersistIdentityAndUserWithUserGroup(login, pwd, newUser); + report.incrementCreatedUser(); + } return ident; } - private Identity doUpdateIdentity(UpdateIdentity userToUpdate, Boolean updateUsers, Boolean updatePassword) { + private Identity doUpdateIdentity(UpdateIdentity userToUpdate, Boolean updateUsers, Boolean updatePassword, ImportReport report) { Identity identity; if(updateUsers != null && updateUsers.booleanValue()) { identity = userToUpdate.getIdentity(true); - um.updateUserFromIdentity(identity); + if(um.updateUserFromIdentity(identity)) { + report.incrementUpdatedUser(); + } } else { identity = userToUpdate.getIdentity(); } String password = userToUpdate.getPassword(); - if(StringHelper.containsNonWhitespace(password) && updatePassword != null && updatePassword.booleanValue()) { - Authentication auth = securityManager.findAuthentication(identity, "OLAT"); - if(auth != null) { - olatAuthManager.changePassword(getIdentity(), identity, password); + if(StringHelper.containsNonWhitespace(password)) { + if(password.startsWith(SHIBBOLETH_MARKER) && ShibbolethModule.isEnableShibbolethLogins()) { + String uniqueID = password.substring(SHIBBOLETH_MARKER.length()); + Authentication auth = securityManager.findAuthentication(identity, ShibbolethDispatcher.PROVIDER_SHIB); + if(auth == null) { + securityManager.createAndPersistAuthentication(identity, ShibbolethDispatcher.PROVIDER_SHIB, uniqueID, null, null); + report.incrementUpdatedShibboletAuthentication(); + } else if(!uniqueID.equals(auth.getAuthusername())) { + //remove the old authentication + securityManager.deleteAuthentication(auth); + DBFactory.getInstance().commit(); + //create the new one with the new authusername + securityManager.createAndPersistAuthentication(identity, ShibbolethDispatcher.PROVIDER_SHIB, uniqueID, null, null); + report.incrementUpdatedShibboletAuthentication(); + } + } else if(updatePassword != null && updatePassword.booleanValue()) { + Authentication auth = securityManager.findAuthentication(identity, "OLAT"); + if(auth != null) { + olatAuthManager.changePassword(getIdentity(), identity, password); + report.incrementUpdatedPassword(); + } } } return userToUpdate.getIdentity(); @@ -190,14 +236,15 @@ public class UserImportController extends BasicController { StepRunnerCallback finish = new StepRunnerCallback() { public Step execute(UserRequest ureq1, WindowControl wControl1, StepsRunContext runContext) { // all information to do now is within the runContext saved - boolean hasChanges = false; + ImportReport report = new ImportReport(); + runContext.put("report", report); try { if (runContext.containsKey("validImport") && ((Boolean) runContext.get("validImport")).booleanValue()) { // create new users and persist @SuppressWarnings("unchecked") List<TransientIdentity> newIdents = (List<TransientIdentity>) runContext.get("newIdents"); for (TransientIdentity newIdent:newIdents) { - doCreateAndPersistIdentity(newIdent); + doCreateAndPersistIdentity(newIdent, report); } Boolean updateUsers = (Boolean)runContext.get("updateUsers"); @@ -205,7 +252,7 @@ public class UserImportController extends BasicController { @SuppressWarnings("unchecked") List<UpdateIdentity> updateIdents = (List<UpdateIdentity>) runContext.get("updateIdents"); for (UpdateIdentity updateIdent:updateIdents) { - doUpdateIdentity(updateIdent, updateUsers, updatePasswords); + doUpdateIdentity(updateIdent, updateUsers, updatePasswords, report); } @SuppressWarnings("unchecked") @@ -213,22 +260,22 @@ public class UserImportController extends BasicController { @SuppressWarnings("unchecked") List<Long> partGroups = (List<Long>) runContext.get("partGroups"); - if (ownGroups.size() > 0 || partGroups.size() > 0){ + if ((ownGroups != null && ownGroups.size() > 0) || (partGroups != null && partGroups.size() > 0)) { @SuppressWarnings("unchecked") List<Identity> allIdents = (List<Identity>) runContext.get("idents"); Boolean sendMailObj = (Boolean)runContext.get("sendMail"); boolean sendmail = sendMailObj == null ? true : sendMailObj.booleanValue(); processGroupAdditionForAllIdents(allIdents, ownGroups, partGroups, sendmail); } - hasChanges = true; + report.setHasChanges(true); } } catch (Exception any) { - // return new ErrorStep + logError("", any); + report.addError("Unexpected error, see log files or call your system administrator"); } // signal correct completion and tell if changes were made or not. - return hasChanges ? StepsMainRunController.DONE_MODIFIED : StepsMainRunController.DONE_UNCHANGED; + return report.isHasChanges() ? StepsMainRunController.DONE_MODIFIED : StepsMainRunController.DONE_UNCHANGED; } - }; importStepsController = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, @@ -281,4 +328,73 @@ public class UserImportController extends BasicController { businessGroupService.updateMemberships(getIdentity(), changes, mailing); DBFactory.getInstance().commit(); } + + public static class ImportReport { + + private boolean hasChanges = false; + private boolean hasErrors = false; + + private AtomicInteger updatedUser = new AtomicInteger(0); + private AtomicInteger createdUser = new AtomicInteger(0); + private AtomicInteger updatedPassword = new AtomicInteger(0); + private AtomicInteger updatedShibboletAuthentication = new AtomicInteger(0); + + private List<String> errors = new ArrayList<>(); + + public boolean isHasChanges() { + return hasChanges; + } + + public void setHasChanges(boolean hasChanges) { + this.hasChanges = hasChanges; + } + + public boolean isHasErrors() { + return hasErrors; + } + + public void setHasErrors(boolean hasErrors) { + this.hasErrors = hasErrors; + } + + public List<String> getErrors() { + return errors; + } + + public void addError(String error) { + errors.add(error); + } + + public int getNumOfUpdatedUser() { + return updatedUser.get(); + } + + public void incrementUpdatedUser() { + updatedUser.incrementAndGet(); + } + + public int getCreatedUser() { + return createdUser.get(); + } + + public void incrementCreatedUser() { + createdUser.incrementAndGet(); + } + + public int getUpdatedPassword() { + return updatedPassword.get(); + } + + public void incrementUpdatedPassword() { + updatedPassword.incrementAndGet(); + } + + public int getUpdatedShibboletAuthentication() { + return updatedShibboletAuthentication.get(); + } + + public void incrementUpdatedShibboletAuthentication() { + updatedShibboletAuthentication.incrementAndGet(); + } + } } \ No newline at end of file diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_de.properties index 603b13f1f0580b9d8cd92c3809319b94857202be..10076212197875f9d55cfa72dd78860dd6c476c9 100644 --- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_de.properties @@ -26,6 +26,7 @@ import.description2=<i>Datenbeispiele\:</i> Sie sehen in einer Beispielabbildung import.description3=<i>Dateneingabe\:</i> Sie kopieren die Zeilen aus der Excel-Datei import.description4=<i>Vorschau der Benutzerdaten\:</i> Sie sehen, welche Benutzer bereits im System sind und welche neu angelegt werden. import.example=Beispielabbildung +import.errors=Die Benutzer wurden teilweise angelegt. Es gab Fehler während den Import Prozess: {0} import.start=Benutzerimport starten import.success=Die neuen Benutzer wurden erfolgreich angelegt. import.user.existing.alt=Dieser Benutzer existiert bereits, er wird nicht neu angelegt diff --git a/src/main/java/org/olat/basesecurity/AuthHelper.java b/src/main/java/org/olat/basesecurity/AuthHelper.java index bb23b752f518fc8333c9526bd91926c693305460..e1d3a30bcf2fa8c93300ca2038c2a8a80f07a10f 100644 --- a/src/main/java/org/olat/basesecurity/AuthHelper.java +++ b/src/main/java/org/olat/basesecurity/AuthHelper.java @@ -356,7 +356,7 @@ public class AuthHelper { * @param newUser unpersisted user * @return Identity */ - public static Identity createAndPersistIdentityAndUser(String loginName, String pwd, User newUser) { + private static Identity createAndPersistIdentityAndUser(String loginName, String pwd, User newUser) { Identity ident = null; if (pwd == null) { // when no password is used the provider must be set to null to not generate @@ -380,7 +380,7 @@ public class AuthHelper { * @param newUser unpersisted users * @return Identity */ - public static Identity createAndPersistIdentityAndUserWithUserGroup(String loginName, String pwd, User newUser) { + public static Identity createAndPersistIdentityAndUserWithUserGroup(String loginName, String pwd, User newUser) { Identity ident = createAndPersistIdentityAndUser(loginName, pwd, newUser); // Add user to system users group BaseSecurity securityManager = BaseSecurityManager.getInstance(); @@ -388,6 +388,25 @@ public class AuthHelper { securityManager.addIdentityToSecurityGroup(ident, olatuserGroup); return ident; } + + /** + * Persists the given user, creates an identity for it and adds the user to + * the users system group, create an authentication for an external provider + * + * @param loginName + * @param provider + * @param authusername + * @param newUser + * @return + */ + public static Identity createAndPersistIdentityAndUserWithUserGroup(String loginName, String provider, String authusername, User newUser) { + BaseSecurity securityManager = BaseSecurityManager.getInstance(); + Identity ident = securityManager.createAndPersistIdentityAndUser(loginName, newUser, provider, authusername, null); + // Add user to system users group + SecurityGroup olatuserGroup = securityManager.findSecurityGroupByName(Constants.GROUP_OLATUSERS); + securityManager.addIdentityToSecurityGroup(ident, olatuserGroup); + return ident; + } /** * This is a convenience method to log out. IMPORTANT: This method initiates a diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java index fcf34ff99fd9f4d787c8074b5cdccd163779c5c4..5fa92fbe2695b245983dfb69abb344cf35cb17bc 100644 --- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java +++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java @@ -1454,7 +1454,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity { public Authentication execute() { Authentication auth = findAuthentication(ident, provider); if(auth == null) { - if(algorithm != null) { + if(algorithm != null && credentials != null) { String salt = algorithm.isSalted() ? Encoder.getSalt() : null; String hash = Encoder.encrypt(credentials, salt, algorithm); auth = new AuthenticationImpl(ident, provider, authUserName, hash, salt, algorithm.name()); diff --git a/src/main/java/org/olat/core/gui/control/controller/BasicController.java b/src/main/java/org/olat/core/gui/control/controller/BasicController.java index f4154ea01e726e6923c5b333a7e0cf8800d2cdf1..b1537eb6f8b89b7c0021ae8718e30154d6633f27 100644 --- a/src/main/java/org/olat/core/gui/control/controller/BasicController.java +++ b/src/main/java/org/olat/core/gui/control/controller/BasicController.java @@ -447,6 +447,22 @@ public abstract class BasicController extends DefaultController { getWindowControl().setInfo( getTranslator().translate(key, new String[] { arg })); } + + /** + * convenience method to inform the user. this will call + * + * <pre> + * getWindowControl().setInfo(getTranslator().translate(key, args)); + * </pre> + * + * @param key + * the key to use (in the LocalStrings_curlanguage file of your + * controller) + * @param args + */ + protected void showInfo(String key, String[] args) { + getWindowControl().setInfo(getTranslator().translate(key, args)); + } /** * convenience method to inform the user with a warning message. this will diff --git a/src/main/java/org/olat/course/editor/EditorMainController.java b/src/main/java/org/olat/course/editor/EditorMainController.java index 4923075311ae2fbf0e05db18db27675c60140be5..44e40225df2fbb8276504fe0cf92d5489928393b 100644 --- a/src/main/java/org/olat/course/editor/EditorMainController.java +++ b/src/main/java/org/olat/course/editor/EditorMainController.java @@ -816,7 +816,7 @@ public class EditorMainController extends MainLayoutBasicController implements G menuTree.setSelectedNodeId(rootNodeIdent); updateViewForSelectedNodeId(ureq, rootNodeIdent); if(event == Event.CHANGED_EVENT){ - showInfo("pbl.success", null); + showInfo("pbl.success"); // do logging ThreadLocalUserActivityLogger.log(CourseLoggingAction.COURSE_EDITOR_PUBLISHED, getClass()); }//else Event.DONE -> nothing changed / else Event.CANCELLED -> cancelled wizard diff --git a/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java b/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java index f776a230966b7477c911c6e87e1316ccc0c9cae3..45cac0c532dba3d1cc54cbaaa13683e710b71265 100644 --- a/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java +++ b/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java @@ -282,7 +282,7 @@ public class QTIEditorMainController extends MainLayoutBasicController implement if (qtiPackage.getQTIDocument() == null) { notEditable = true; } else if (qtiPackage.isResumed()) { - showInfo("info.resumed", null); + showInfo("info.resumed"); } // init(ureq); // initialize the gui