This is an automated email from the ASF dual-hosted git repository. danhaywood pushed a commit to branch ISIS-3169 in repository https://gitbox.apache.org/repos/asf/isis.git
commit 849917841242f7e98dcda709583ddbb19e53efa3 Author: Dan Haywood <[email protected]> AuthorDate: Tue Aug 23 16:29:50 2022 +0100 ISIS-3169: also adds auto-created users to a set of initial roles. --- .../apache/isis/core/config/IsisConfiguration.java | 17 +++++++- .../dom/ApplicationUserAutoCreationService.java | 47 ++++++++++++++++++++-- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/core/config/src/main/java/org/apache/isis/core/config/IsisConfiguration.java b/core/config/src/main/java/org/apache/isis/core/config/IsisConfiguration.java index 2be200a9fe..c6bb6c980b 100644 --- a/core/config/src/main/java/org/apache/isis/core/config/IsisConfiguration.java +++ b/core/config/src/main/java/org/apache/isis/core/config/IsisConfiguration.java @@ -3105,7 +3105,6 @@ public class IsisConfiguration { public enum AutoCreatePolicy { AUTO_CREATE_AS_LOCKED, AUTO_CREATE_AS_UNLOCKED, - // NO_AUTO_CREATE } /** @@ -3115,10 +3114,26 @@ public class IsisConfiguration { * BE AWARE THAT if any users are auto-created as unlocked, then the set of roles that * they are given should be highly restricted !!! * </p> + * + * <p> + * NOTE also that this configuration policy is ignored if running secman with Spring OAuth2 + * or Keycloak as the authenticator; users are always auto-created. + * </p> */ @Getter @Setter private AutoCreatePolicy autoCreatePolicy = AutoCreatePolicy.AUTO_CREATE_AS_LOCKED; + /** + * The set of roles that users that have been automatically created are granted automatically. + * + * <p> + * Typically the regular user role (as per <code>isis.secman.seed.regular-user.role-name</code> + * will be one of the roles listed here; that will provide the ability for the end-user to logout, + * among other things (!). + * </p> + */ + private List<String> initialRoleNames = new ArrayList<>(); + } public enum PermissionsEvaluationPolicy { diff --git a/extensions/security/secman/delegated-springoauth2/src/main/java/org/apache/isis/extensions/secman/delegated/springoauth2/dom/ApplicationUserAutoCreationService.java b/extensions/security/secman/delegated-springoauth2/src/main/java/org/apache/isis/extensions/secman/delegated/springoauth2/dom/ApplicationUserAutoCreationService.java index f485a6825e..85289c6e31 100644 --- a/extensions/security/secman/delegated-springoauth2/src/main/java/org/apache/isis/extensions/secman/delegated/springoauth2/dom/ApplicationUserAutoCreationService.java +++ b/extensions/security/secman/delegated-springoauth2/src/main/java/org/apache/isis/extensions/secman/delegated/springoauth2/dom/ApplicationUserAutoCreationService.java @@ -20,16 +20,27 @@ package org.apache.isis.extensions.secman.delegated.springoauth2.dom; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + import javax.inject.Inject; import org.springframework.context.ApplicationListener; +import org.springframework.lang.Nullable; import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent; import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; import org.springframework.stereotype.Service; +import org.apache.isis.applib.services.factory.FactoryService; import org.apache.isis.applib.services.iactnlayer.InteractionService; +import org.apache.isis.core.config.IsisConfiguration; +import org.apache.isis.extensions.secman.applib.role.dom.ApplicationRoleRepository; +import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUser; import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUserRepository; import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUserStatus; +import org.apache.isis.extensions.secman.applib.user.dom.mixins.ApplicationUser_addRole; +import org.apache.isis.extensions.secman.applib.user.dom.mixins.ApplicationUser_updateEmailAddress; import lombok.RequiredArgsConstructor; import lombok.val; @@ -40,7 +51,10 @@ public class ApplicationUserAutoCreationService implements ApplicationListener<InteractiveAuthenticationSuccessEvent> { private final ApplicationUserRepository applicationUserRepository; + private final ApplicationRoleRepository applicationRoleRepository; private final InteractionService interactionService; + private final IsisConfiguration isisConfiguration; + private final FactoryService factoryService; @Override public void onApplicationEvent(final InteractiveAuthenticationSuccessEvent event) { @@ -53,8 +67,35 @@ public class ApplicationUserAutoCreationService val oidcUser = (DefaultOidcUser) principal; val username = oidcUser.getIdToken().getPreferredUsername(); val email = oidcUser.getIdToken().getEmail(); - val applicationUser = interactionService.callAnonymous(() -> applicationUserRepository.findOrCreateUserByUsername(username)); - applicationUser.setEmailAddress(email); - applicationUser.setStatus(ApplicationUserStatus.UNLOCKED); // locking not supported for keycloak + interactionService.runAnonymous(() -> { + Optional<ApplicationUser> userIfAny = applicationUserRepository.findByUsername(username); + if (userIfAny.isEmpty()) { + val status = ApplicationUserStatus.UNLOCKED; // locking not supported for spring delegated accounts + val applicationUser = applicationUserRepository.newDelegateUser(username, status); + factoryService.mixin(ApplicationUser_updateEmailAddress.class, applicationUser).act(email); + + val initialRoleNames = isisConfiguration.getExtensions().getSecman().getDelegatedUsers().getInitialRoleNames(); + if (notEmpty(initialRoleNames)) { + for (String initialRoleName : initialRoleNames) { + addRoleIfExists(applicationUser, initialRoleName); + } + } + } + }); } + + private void addRoleIfExists(ApplicationUser applicationUser, String initialRoleName) { + applicationRoleRepository.findByName(initialRoleName).ifPresent(role -> { + factoryService.mixin(ApplicationUser_addRole.class, applicationUser).act(role); + }); + } + + private static boolean notEmpty(List<String> initialRoleNames) { + return !isEmpty(initialRoleNames); + } + + private static boolean isEmpty(@Nullable Collection<?> collection) { + return collection == null || collection.isEmpty(); + } + }
