diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java b/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java index d621cc6e263..6d0bc74fca8 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java @@ -36,8 +36,6 @@ public class AuthProvider { private final boolean isDefaultProvider; - private final boolean isUserSyncSupported; - private final boolean isUserSyncAtStartupEnabled; private final String name; @@ -45,8 +43,7 @@ public class AuthProvider { private AuthProvider(ConfigFacade configFacade) { String configuredProvider = configFacade.getAuthenticationProvider(); isDefaultProvider = SORMAS.equalsIgnoreCase(configuredProvider); - isUserSyncSupported = KEYCLOAK.equalsIgnoreCase(configuredProvider); - isUserSyncAtStartupEnabled = isUserSyncSupported && configFacade.isAuthenticationProviderUserSyncAtStartupEnabled(); + isUserSyncAtStartupEnabled = KEYCLOAK.equalsIgnoreCase(configuredProvider) && configFacade.isAuthenticationProviderUserSyncAtStartupEnabled(); name = configuredProvider; } @@ -68,13 +65,6 @@ public boolean isDefaultProvider() { return isDefaultProvider; } - /** - * Authentication Provider enables users to be synced from the default provider. - */ - public boolean isUserSyncSupported() { - return isUserSyncSupported; - } - /** * Even if the Authentication Provider supports user sync, the user sync at startup might be disabled for startup performance reasons. * If user sync is not supported, this will always return false. diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java index 54ee2717460..a67e67dc2d5 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java @@ -130,6 +130,8 @@ public interface ConfigFacade { boolean isAuthenticationProviderUserSyncAtStartupEnabled(); + String getAuthenticationProviderSyncedNewUserRole(); + boolean isExternalJournalActive(); int getDashboardMapMarkerLimit(); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserFacade.java index b7628155784..8dd66e15369 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserFacade.java @@ -166,4 +166,8 @@ List getUserRefsByInfrastructure( * @return A set containing the user rights associated to all user roles assigned to the user */ List getUserRights(String userUuid); + + void syncUsersFromAuthenticationProvider(); + + boolean isSyncEnabled(); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java index 033258a9889..8087ed88c4d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java @@ -61,6 +61,7 @@ public class ConfigFacadeEjb implements ConfigFacade { private static final String AUTHENTICATION_PROVIDER = "authentication.provider"; private static final String AUTHENTICATION_PROVIDER_USER_SYNC_AT_STARTUP = "authentication.provider.userSyncAtStartup"; + private static final String AUTHENTICATION_PROVIDER_SYNCED_NEW_USER_ROLE = "authentication.provider.syncedNewUserRole"; public static final String COUNTRY_NAME = "country.name"; public static final String COUNTRY_LOCALE = "country.locale"; @@ -659,6 +660,11 @@ public boolean isAuthenticationProviderUserSyncAtStartupEnabled() { return getBoolean(AUTHENTICATION_PROVIDER_USER_SYNC_AT_STARTUP, false); } + @Override + public String getAuthenticationProviderSyncedNewUserRole() { + return getProperty(AUTHENTICATION_PROVIDER_SYNCED_NEW_USER_ROLE, null); + } + @Override public boolean isExternalJournalActive() { return !StringUtils.isAllBlank(getProperty(INTERFACE_SYMPTOM_JOURNAL_URL, null), getProperty(INTERFACE_PATIENT_DIARY_URL, null)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java index 8219f7860aa..ec8e92357c2 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java @@ -52,6 +52,7 @@ import de.symeda.sormas.backend.systemevent.SystemEventFacadeEjb.SystemEventFacadeEjbLocal; import de.symeda.sormas.backend.task.TaskFacadeEjb.TaskFacadeEjbLocal; import de.symeda.sormas.backend.travelentry.TravelEntryFacadeEjb; +import de.symeda.sormas.backend.user.UserFacadeEjb.UserFacadeEjbLocal; @Singleton @RunAs(UserRight._SYSTEM) @@ -93,6 +94,8 @@ public class CronService { private CoreEntityDeletionService coreEntityDeletionService; @EJB private SpecialCaseAccessFacadeEjbLocal specialCaseAccessFacade; + @EJB + private UserFacadeEjbLocal userFacade; @Schedule(hour = "*", minute = "*/" + TASK_UPDATE_INTERVAL, second = "0", persistent = false) public void sendNewAndDueTaskMessages() { @@ -184,12 +187,11 @@ public void archiveEvents() { final int daysAfterEventsGetsArchived = featureConfigurationFacade .getProperty(FeatureType.AUTOMATIC_ARCHIVING, DeletableEntityType.EVENT, FeatureTypeProperty.THRESHOLD_IN_DAYS, Integer.class); - final int daysAfterEventParticipantsGetsArchived = featureConfigurationFacade - .getProperty( - FeatureType.AUTOMATIC_ARCHIVING, - DeletableEntityType.EVENT_PARTICIPANT, - FeatureTypeProperty.THRESHOLD_IN_DAYS, - Integer.class); + final int daysAfterEventParticipantsGetsArchived = featureConfigurationFacade.getProperty( + FeatureType.AUTOMATIC_ARCHIVING, + DeletableEntityType.EVENT_PARTICIPANT, + FeatureTypeProperty.THRESHOLD_IN_DAYS, + Integer.class); if (daysAfterEventsGetsArchived < daysAfterEventParticipantsGetsArchived) { logger.warn( "{} for {} [{}] should be <= the one for {} [{}]", @@ -253,12 +255,11 @@ public void archiveContacts() { @Schedule(hour = "2", minute = "20", persistent = false) public void archiveEventParticipants() { - final int daysAfterEventParticipantGetsArchived = featureConfigurationFacade - .getProperty( - FeatureType.AUTOMATIC_ARCHIVING, - DeletableEntityType.EVENT_PARTICIPANT, - FeatureTypeProperty.THRESHOLD_IN_DAYS, - Integer.class); + final int daysAfterEventParticipantGetsArchived = featureConfigurationFacade.getProperty( + FeatureType.AUTOMATIC_ARCHIVING, + DeletableEntityType.EVENT_PARTICIPANT, + FeatureTypeProperty.THRESHOLD_IN_DAYS, + Integer.class); if (daysAfterEventParticipantGetsArchived >= 1) { eventParticipantFacade.archiveAllArchivableEventParticipants(daysAfterEventParticipantGetsArchived); @@ -273,7 +274,7 @@ public void archiveImmunizations() { if (daysAfterImmunizationsGetsArchived >= 1) { immunizationFacade.archiveAllArchivableImmunizations(daysAfterImmunizationsGetsArchived); } -} + } @Schedule(hour = "2", minute = "30", persistent = false) public void archiveTravelEntry() { @@ -289,4 +290,11 @@ public void archiveTravelEntry() { public void deleteExpiredSpecialCaseAccesses() { specialCaseAccessFacade.deleteExpiredSpecialCaseAccesses(); } + + @Schedule(hour = "2", minute = "35", persistent = false) + public void syncUsersFromAuthenticationProvider() { + if (userFacade.isSyncEnabled() && featureConfigurationFacade.isFeatureEnabled(FeatureType.AUTH_PROVIDER_TO_SORMAS_USER_SYNC)) { + userFacade.syncUsersFromAuthenticationProvider(); + } + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java index f48f031e5fd..70bc4697cde 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java @@ -616,11 +616,6 @@ private void syncUsers() { AuthProvider authProvider = AuthProvider.getProvider(configFacade); - if (!authProvider.isUserSyncSupported()) { - logger.info("Active Authentication Provider {} doesn't support user sync", authProvider.getName()); - return; - } - if (!authProvider.isUserSyncAtStartupEnabled()) { logger.info("User sync at startup is disabled. Enable this in SORMAS properties if the active Authentication Provider supports it"); return; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/KeycloakService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/KeycloakService.java index 5f42b7cd04a..b0d532d422c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/KeycloakService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/KeycloakService.java @@ -25,6 +25,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.PostConstruct; import javax.ejb.EJB; @@ -52,6 +54,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Functions; import com.jayway.jsonpath.JsonPath; import de.symeda.sormas.api.AuthProvider; @@ -59,6 +62,7 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.user.event.PasswordResetEvent; +import de.symeda.sormas.backend.user.event.SyncUsersFromProviderEvent; import de.symeda.sormas.backend.user.event.UserCreateEvent; import de.symeda.sormas.backend.user.event.UserUpdateEvent; @@ -229,6 +233,34 @@ public void handlePasswordResetEvent(@Observes PasswordResetEvent passwordResetE } } + public void handleSyncUsersFromProviderEvent(@Observes SyncUsersFromProviderEvent syncUsersFromProviderEvent) { + Optional keycloak = getKeycloakInstance(); + if (keycloak.isEmpty()) { + logger.warn("Cannot obtain keycloak instance. Will not sync users from provider"); + return; + } + + List existingUsers = syncUsersFromProviderEvent.getExistingUsers(); + Map existingUsersByUsername = + existingUsers.stream().collect(Collectors.toMap(user1 -> user1.getUserName().toLowerCase(), Functions.identity())); + List providerUsers = keycloak.get().realm(REALM_NAME).users().list(); + List syncedUsers = providerUsers.stream().map(user -> { + User sormasUser = existingUsersByUsername.get(user.getUsername().toLowerCase()); + if (sormasUser == null) { + sormasUser = new User(); + } + updateUser(sormasUser, user); + + return sormasUser; + }).collect(Collectors.toList()); + + Set providerUserNames = providerUsers.stream().map(UserRepresentation::getUsername).collect(Collectors.toSet()); + List deletedUsers = existingUsers.stream().filter(user -> !providerUserNames.contains(user.getUserName())).collect(Collectors.toList()); + + syncUsersFromProviderEvent.getCallback().accept(syncedUsers, deletedUsers); + + } + /** * Creates a {@link UserRepresentation} from the SORMAS user and send the request to create the user to Keycloak. * @@ -274,6 +306,15 @@ private UserRepresentation createUserRepresentation(User user, String hashedPass return userRepresentation; } + private void updateUser(User user, UserRepresentation userRepresentation) { + user.setActive(userRepresentation.isEnabled()); + user.setUserName(userRepresentation.getUsername()); + user.setFirstName(userRepresentation.getFirstName()); + user.setLastName(userRepresentation.getLastName()); + user.setLanguage(getLanguage(userRepresentation)); + user.setUserEmail(userRepresentation.getEmail()); + } + private Optional updateUser(Keycloak keycloak, String existingUsername, User newUser) { Optional userRepresentation = getUserByUsername(keycloak, existingUsername); @@ -371,6 +412,17 @@ private void sendPasswordResetEmail(Keycloak keycloak, String userId) { keycloak.realm(REALM_NAME).users().get(userId).executeActionsEmail(Collections.singletonList(ACTION_UPDATE_PASSWORD)); } + private Language getLanguage(UserRepresentation userRepresentation) { + Map> attributes = userRepresentation.getAttributes(); + if (attributes != null) { + List locale = attributes.get(LOCALE); + if (locale != null && !locale.isEmpty()) { + return Language.fromLocaleString(locale.get(0)); + } + } + return null; + } + private void setLanguage(UserRepresentation userRepresentation, Language language) { Map> attributes = userRepresentation.getAttributes(); if (attributes == null) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java index e3eaf4780b9..ba82e011fe5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java @@ -14,6 +14,7 @@ */ package de.symeda.sormas.backend.user; +import static de.symeda.sormas.api.AuthProvider.KEYCLOAK; import static java.util.Objects.isNull; import java.lang.reflect.InvocationTargetException; @@ -50,6 +51,7 @@ import javax.persistence.criteria.Subquery; import javax.validation.Valid; import javax.validation.ValidationException; +import javax.ws.rs.ForbiddenException; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.lang3.StringUtils; @@ -58,6 +60,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import de.symeda.sormas.api.AuthProvider; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.EntityDto; import de.symeda.sormas.api.InfrastructureDataReferenceDto; @@ -102,6 +105,7 @@ import de.symeda.sormas.backend.caze.CaseQueryContext; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactJoins; @@ -114,7 +118,7 @@ import de.symeda.sormas.backend.environment.EnvironmentQueryContext; import de.symeda.sormas.backend.event.EventJurisdictionPredicateValidator; import de.symeda.sormas.backend.event.EventQueryContext; -import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb; +import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityService; @@ -140,6 +144,7 @@ import de.symeda.sormas.backend.travelentry.TravelEntryQueryContext; import de.symeda.sormas.backend.user.UserRoleFacadeEjb.UserRoleFacadeEjbLocal; import de.symeda.sormas.backend.user.event.PasswordResetEvent; +import de.symeda.sormas.backend.user.event.SyncUsersFromProviderEvent; import de.symeda.sormas.backend.user.event.UserCreateEvent; import de.symeda.sormas.backend.user.event.UserUpdateEvent; import de.symeda.sormas.backend.util.DtoHelper; @@ -182,17 +187,21 @@ public class UserFacadeEjb implements UserFacade { @EJB private UserRoleFacadeEjbLocal userRoleFacade; @EJB - private FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; + private FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; @EJB private UserRoleService userRoleService; @EJB private PersonService personService; + @EJB + private ConfigFacadeEjbLocal configFacade; @Inject private Event userCreateEvent; @Inject private Event userUpdateEvent; @Inject private Event passwordResetEvent; + @Inject + private Event syncUsersFromProviderEventEvent; public static UserDto toDto(User source) { @@ -1042,6 +1051,56 @@ public UserSyncResult syncUser(String uuid) { return userSyncResult; } + @Override + @RightsAllowed({ + UserRight._USER_CREATE, + UserRight._USER_EDIT, + UserRight._SYSTEM }) + public void syncUsersFromAuthenticationProvider() { + + if (!isSyncEnabled()) { + throw new ForbiddenException("No default role for new users from authentication provider is configured"); + } + + String defaultRoleName = configFacade.getAuthenticationProviderSyncedNewUserRole(); + UserRole defaultRole = userRoleService.getByCaption(defaultRoleName); + + if (defaultRole == null) { + throw new ForbiddenException("No default role for new users from authentication provider is configured"); + } + + List existingUsers = userService.getAll(); + + syncUsersFromProviderEventEvent.fire(new SyncUsersFromProviderEvent(existingUsers, (syncedUsers, deletedUsers) -> { + syncedUsers.forEach(user -> { + if (user.getId() == null) { + user.setUuid(DataHelper.createUuid()); + user.setUserRoles(Collections.singleton(defaultRole)); + UserService.setNewPassword(user); + } + userService.ensurePersisted(user); + }); + + deletedUsers.forEach(user -> { + user.setActive(false); + userService.ensurePersisted(user); + }); + })); + } + + @Override + @RightsAllowed({ + UserRight._USER_CREATE, + UserRight._USER_EDIT, + UserRight._SYSTEM }) + public boolean isSyncEnabled() { + AuthProvider authProvider = AuthProvider.getProvider(configFacade); + return KEYCLOAK.equalsIgnoreCase(authProvider.getName()) + && (featureConfigurationFacade.isFeatureDisabled(FeatureType.AUTH_PROVIDER_TO_SORMAS_USER_SYNC) + || StringUtils.isNotBlank(configFacade.getAuthenticationProviderSyncedNewUserRole())); + + } + @Override // TODO - default password change only for ADMIN?? @PermitAll diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java index fd58a140468..0d88ceb7795 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java @@ -104,9 +104,7 @@ public User createUser() { User user = new User(); // dummy password to make sure no one can login with this user - String password = PasswordHelper.createPass(12); - user.setSeed(PasswordHelper.createPass(16)); - user.setPassword(PasswordHelper.encodePassword(password, user.getSeed())); + setNewPassword(user); return user; } @@ -642,10 +640,16 @@ public String resetPassword(String userUuid) { return null; } + String password = setNewPassword(user); + ensurePersisted(user); + + return password; + } + + public static String setNewPassword(User user) { String password = PasswordHelper.createPass(12); user.setSeed(PasswordHelper.createPass(16)); user.setPassword(PasswordHelper.encodePassword(password, user.getSeed())); - ensurePersisted(user); return password; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/event/SyncUsersFromProviderEvent.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/event/SyncUsersFromProviderEvent.java new file mode 100644 index 00000000000..be2ed0e3523 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/event/SyncUsersFromProviderEvent.java @@ -0,0 +1,41 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.user.event; + +import java.util.List; +import java.util.function.BiConsumer; + +import de.symeda.sormas.backend.user.User; + +public class SyncUsersFromProviderEvent { + + private final List existingUsers; + + private final BiConsumer, List> callback; + + public SyncUsersFromProviderEvent(List existingUsers, BiConsumer, List> callback) { + this.existingUsers = existingUsers; + this.callback = callback; + } + + public List getExistingUsers() { + return existingUsers; + } + + public BiConsumer, List> getCallback() { + return callback; + } +} diff --git a/sormas-base/setup/sormas.properties b/sormas-base/setup/sormas.properties index 3ce05183b6b..86168c8d8f6 100644 --- a/sormas-base/setup/sormas.properties +++ b/sormas-base/setup/sormas.properties @@ -256,6 +256,10 @@ app.url= # Default: false # Possible Values: true, false #authentication.provider.userSyncAtStartup=false +# Specifies what user role should be used as default for new users synced from the authentication provider (e.g. Keycloak). +# Default: empty, meaning no user role. +# Must be set to the name of an existing user role in the database when the feature AUTH_PROVIDER_TO_SORMAS_USER_SYNC is active +#authentication.provider.syncedNewUserRole= # GEOCODING SERVICE diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/login/LoginUI.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/login/LoginUI.java index 8b4ff7641a9..bee5810aad0 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/login/LoginUI.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/login/LoginUI.java @@ -17,12 +17,19 @@ *******************************************************************************/ package de.symeda.sormas.ui.login; +import java.io.IOException; + +import javax.inject.Inject; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; +import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.servlet.ServletSecurityElement; import javax.servlet.annotation.WebListener; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,8 +44,8 @@ import com.vaadin.server.VaadinServletService; import com.vaadin.server.VaadinSession; import com.vaadin.ui.UI; -import de.symeda.sormas.api.AuthProvider; +import de.symeda.sormas.api.AuthProvider; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.ui.SormasErrorHandler; @@ -46,13 +53,6 @@ import de.symeda.sormas.ui.utils.SormasDefaultConverterFactory; import fish.payara.security.openid.api.OpenIdContext; -import javax.inject.Inject; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - /** * Main UI class of the application that shows either the login screen or the * main view of the application depending on whether a user is signed in. @@ -80,14 +80,14 @@ public void init(VaadinRequest vaadinRequest) { getPage().setTitle(FacadeProvider.getConfigFacade().getSormasInstanceName()); setContent( - new LoginScreen( - DefaultPasswordUIHelper.getInterceptionLoginListener( - (LoginListener) () -> UI.getCurrent().getPage().setLocation( - VaadinServletService.getCurrentServletRequest().getContextPath() + "#" - + DataHelper.toStringNullable(UI.getCurrent().getPage().getUriFragment())), - UI.getCurrent()) - ) - ); + new LoginScreen( + DefaultPasswordUIHelper.getInterceptionLoginListener( + (LoginListener) () -> UI.getCurrent() + .getPage() + .setLocation( + VaadinServletService.getCurrentServletRequest().getContextPath() + "#" + + DataHelper.toStringNullable(UI.getCurrent().getPage().getUriFragment())), + UI.getCurrent()))); } public static class SormasLoginServlet extends VaadinServlet { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UserController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UserController.java index a057578e97c..115313f799b 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UserController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UserController.java @@ -346,8 +346,13 @@ public void setFlagIcons(ComboBox cbLanguage) { } public void sync() { - Window window = VaadinUiUtil.showPopupWindow(new UsersSyncLayout()); - window.setCaption(I18nProperties.getCaption(Captions.syncUsers)); + if (UiUtil.permitted(FeatureType.AUTH_PROVIDER_TO_SORMAS_USER_SYNC)) { + FacadeProvider.getUserFacade().syncUsersFromAuthenticationProvider(); + SormasUI.refreshView(); + } else { + Window window = VaadinUiUtil.showPopupWindow(new UsersSyncLayout()); + window.setCaption(I18nProperties.getCaption(Captions.syncUsers)); + } } public void enableAllSelectedItems(Collection selectedRows, UserGrid userGrid) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UsersView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UsersView.java index 740704b8492..26baf2ccad5 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UsersView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UsersView.java @@ -29,7 +29,6 @@ import com.vaadin.v7.ui.ComboBox; import com.vaadin.v7.ui.TextField; -import de.symeda.sormas.api.AuthProvider; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.feature.FeatureType; @@ -125,8 +124,7 @@ public UsersView() { addHeaderComponent(createButton); } - if (AuthProvider.getProvider(FacadeProvider.getConfigFacade()).isUserSyncSupported() - && FacadeProvider.getFeatureConfigurationFacade().isFeatureDisabled(FeatureType.AUTH_PROVIDER_TO_SORMAS_USER_SYNC)) { + if (FacadeProvider.getUserFacade().isSyncEnabled()) { syncButton = ButtonHelper.createIconButton(Captions.syncUsers, VaadinIcons.REFRESH, e -> ControllerProvider.getUserController().sync()); addHeaderComponent(syncButton);