You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/08/05 22:55:45 UTC
[isis] branch ISIS-2728 updated (118b815 -> 4d23cc8)
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a change to branch ISIS-2728
in repository https://gitbox.apache.org/repos/asf/isis.git.
discard 118b815 ISIS-2794: adds minor doc relating to flushing config property
discard 9949db7 ISIS-2483: adds missing docs on secman config
discard 53cb348 ISIS-2728: extends the ImpersonateMenuAdvisor SPI to also advise on the multiTokenTenancy
discard 16eb40a ISIS-2730: catches exception and falls back to welcome page
discard af24651 ISIS-2794: fixes entity change property to access values directly
discard cc1d574 ISIS-2728: adds secman implementation of UserMementoRefiner
discard 5536482 ISIS-2728: introduces UserMementoRefiner as a new SPI
discard 6de24fe ISIS-2728: adds UserMemento#multiTenancyToken unit tests
discard 243fb29 ISIS-2728: adds multiTenancyToken into UserMemento
add 416dc7b ISIS-2483: adds missing docs on secman config
new c846062 ISIS-2728: adds multiTenancyToken into UserMemento
new ecfce2a ISIS-2728: adds UserMemento#multiTenancyToken unit tests
new 0f8b5be ISIS-2728: introduces UserMementoRefiner as a new SPI
new 8c55e4b ISIS-2728: adds secman implementation of UserMementoRefiner
new 4d23cc8 ISIS-2728: extends the ImpersonateMenuAdvisor SPI to also advise on the multiTokenTenancy
This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version. This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:
* -- * -- B -- O -- O -- O (118b815)
\
N -- N -- N refs/heads/ISIS-2728 (4d23cc8)
You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.
Any revisions marked "omit" are not gone; other references still
refer to them. Any revisions marked "discard" are gone forever.
The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.run/SimpleApp.run.xml | 2 +-
.../isis/applib/services/iactnlayer/InteractionContext.java | 4 ++++
.../config/pages/sections/isis.core.runtime-services.adoc | 2 +-
.../java/org/apache/isis/core/config/IsisConfiguration.java | 9 +++++++--
.../services/objectlifecycle/ObjectLifecyclePublisher.java | 5 ++---
.../repository/RepositoryServiceDefault.java | 13 ++++++-------
.../standard/AuthenticationManager_authenticators_Test.java | 6 ++----
.../StandardAuthenticationManager_AuthenticationTest.java | 3 +--
.../apache/isis/viewer/wicket/ui/pages/home/HomePage.java | 9 +--------
.../AuthenticatedWebSessionForIsis_Authenticate.java | 13 ++++++-------
...> AuthenticatedWebSessionForIsis_NotYetImplemented.java} | 11 +++--------
.../integration/AuthenticatedWebSessionForIsis_SignIn.java | 9 +++------
12 files changed, 37 insertions(+), 49 deletions(-)
copy viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/{AuthenticatedWebSessionForIsis_DownCastsInheritedFunctionality.java => AuthenticatedWebSessionForIsis_NotYetImplemented.java} (78%)
[isis] 04/05: ISIS-2728: adds secman implementation of
UserMementoRefiner
Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-2728
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 8c55e4bd23309138b7bda9d550dbe6f0de3fd0d4
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Jun 29 10:23:09 2021 +0100
ISIS-2728: adds secman implementation of UserMementoRefiner
... to copy the ApplicationUser#atPath onto the UserMemento#multiTenancyToken
(cherry picked from commit b255e47d4206a6046fc0806e851fd4eb9536c993)
(cherry picked from commit cc1d5743ea40a2335a76290a891690364832322c)
---
.../UserMementoRefinerFromApplicationUser.java | 45 ++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/usermementorefiner/UserMementoRefinerFromApplicationUser.java b/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/usermementorefiner/UserMementoRefinerFromApplicationUser.java
new file mode 100644
index 0000000..2b29aa2
--- /dev/null
+++ b/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/usermementorefiner/UserMementoRefinerFromApplicationUser.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.extensions.secman.integration.usermementorefiner;
+
+import javax.inject.Inject;
+
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.applib.services.user.UserMemento;
+import org.apache.isis.core.security.authentication.manager.UserMementoRefiner;
+import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUserRepository;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+
+@Service
+@Log4j2
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class UserMementoRefinerFromApplicationUser implements UserMementoRefiner {
+
+ private final ApplicationUserRepository applicationUserRepository;
+
+ @Override
+ public UserMemento refine(UserMemento userMemento) {
+ return applicationUserRepository.findByUsername(userMemento.getName())
+ .map(applicationUser -> userMemento.withMultiTenancyToken(applicationUser.getAtPath()))
+ .orElse(userMemento);
+ }
+}
[isis] 05/05: ISIS-2728: extends the ImpersonateMenuAdvisor SPI to
also advise on the multiTokenTenancy
Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-2728
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 4d23cc85002025958d40676793c3df66070f998c
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Thu Aug 5 23:46:53 2021 +0100
ISIS-2728: extends the ImpersonateMenuAdvisor SPI to also advise on the multiTokenTenancy
(cherry picked from commit 53cb34831d0b1d6088a591cfbe052f311504ea71)
---
.../isis/applib/services/user/ImpersonateMenu.java | 20 +++++++++-------
.../services/user/ImpersonateMenuAdvisor.java | 19 +++++++++++----
.../isis/applib/services/user/UserService.java | 27 ++++++++++++----------
.../user/ImpersonateMenuAdvisorDefault.java | 10 +++++---
.../dom/ApplicationPermissionRepository.java | 2 +-
.../IsisModuleExtSecmanIntegration.java | 3 +++
.../spiimpl/ImpersonateMenuAdvisorForSecman.java | 13 ++++++++++-
.../applib/mixins/Object_impersonateWithRoles.java | 17 ++++++++------
8 files changed, 75 insertions(+), 36 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/user/ImpersonateMenu.java b/api/applib/src/main/java/org/apache/isis/applib/services/user/ImpersonateMenu.java
index f6fc227..fbf6d27 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/user/ImpersonateMenu.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/user/ImpersonateMenu.java
@@ -81,7 +81,7 @@ public class ImpersonateMenu {
final String userName) {
// TODO: should use an SPI for each configured viewer to add in its own role if necessary.
- this.userService.impersonateUser(userName, Collections.singletonList("org.apache.isis.viewer.wicket.roles.USER"));
+ this.userService.impersonateUser(userName, Collections.singletonList("org.apache.isis.viewer.wicket.roles.USER"), null);
this.messageService.informUser("Now impersonating " + userName);
}
@MemberSupport public boolean hideImpersonate() {
@@ -106,9 +106,9 @@ public class ImpersonateMenu {
* an {@link ImpersonateMenuAdvisor} implementation to provide the
* choices.
* </p>
- *
- * @param userName
+ * @param userName
* @param roleNames
+ * @param multiTenancyToken
*/
@Action(
domainEvent = ImpersonateWithRolesDomainEvent.class,
@@ -120,14 +120,15 @@ public class ImpersonateMenu {
@ActionLayout(sequence = "100.2", cssClassFa = "fa-mask")
public void impersonateWithRoles(
final String userName,
- final List<String> roleNames) {
+ final List<String> roleNames,
+ final String multiTenancyToken) {
// TODO: should use an SPI for each configured viewer to add in its own role if necessary.
- val roleNames2 = new ArrayList<>(roleNames);
- if(!roleNames2.contains("org.apache.isis.viewer.wicket.roles.USER")) {
- roleNames2.add("org.apache.isis.viewer.wicket.roles.USER");
+ val roleNamesCopy = new ArrayList<>(roleNames);
+ if(!roleNamesCopy.contains("org.apache.isis.viewer.wicket.roles.USER")) {
+ roleNamesCopy.add("org.apache.isis.viewer.wicket.roles.USER");
}
- this.userService.impersonateUser(userName, roleNames2);
+ this.userService.impersonateUser(userName, roleNamesCopy, multiTenancyToken);
this.messageService.informUser("Now impersonating " + userName);
}
@MemberSupport public boolean hideImpersonateWithRoles() {
@@ -145,6 +146,9 @@ public class ImpersonateMenu {
@MemberSupport public List<String> default1ImpersonateWithRoles(final String userName) {
return impersonateMenuAdvisor().roleNamesFor(userName);
}
+ @MemberSupport public String default2ImpersonateWithRoles(final String userName, final List<String> roleNames) {
+ return impersonateMenuAdvisor().multiTenancyTokenFor(userName);
+ }
private ImpersonateMenuAdvisor impersonateMenuAdvisor() {
// this is safe because there will always be at least one implementation.
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/user/ImpersonateMenuAdvisor.java b/api/applib/src/main/java/org/apache/isis/applib/services/user/ImpersonateMenuAdvisor.java
index f5c1351..8922044 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/user/ImpersonateMenuAdvisor.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/user/ImpersonateMenuAdvisor.java
@@ -3,7 +3,7 @@ package org.apache.isis.applib.services.user;
import java.util.List;
/**
- * Enables {@link ImpersonateMenu#impersonateWithRoles(String, List)}, to provides choices for user and roles.
+ * Enables {@link ImpersonateMenu#impersonateWithRoles(String, List, String)}, to provides choices for user and roles.
*
* <p>
* This will result in the simpler {@link ImpersonateMenu#impersonate(String)} (which simply allows a
@@ -20,7 +20,7 @@ public interface ImpersonateMenuAdvisor {
* <p>
* The {@link ImpersonateMenu} uses this to provide a choices
* (drop-down) for the username (string) argument of
- * {@link ImpersonateMenu#impersonateWithRoles(String, List)}.
+ * {@link ImpersonateMenu#impersonateWithRoles(String, List, String)}.
* </p>
*/
List<String> allUserNames();
@@ -31,7 +31,7 @@ public interface ImpersonateMenuAdvisor {
* <p>
* The {@link ImpersonateMenu} uses this to provide a choices
* (drop-down) for the rolenames (list) argument of
- * {@link ImpersonateMenu#impersonateWithRoles(String, List)}.
+ * {@link ImpersonateMenu#impersonateWithRoles(String, List, String)}.
* </p>
*/
List<String> allRoleNames();
@@ -42,9 +42,20 @@ public interface ImpersonateMenuAdvisor {
* <p>
* The {@link ImpersonateMenu} uses this to select the defaults
* for the rolenames (list) argument of
- * {@link ImpersonateMenu#impersonateWithRoles(String, List)}.
+ * {@link ImpersonateMenu#impersonateWithRoles(String, List, String)}.
* </p>
*/
List<String> roleNamesFor(final String username);
+ /**
+ * Returns the multi-tenancy token of the specified username.
+ *
+ * <p>
+ * The {@link ImpersonateMenu} uses this to select the defaults
+ * for the rolenames (list) argument of
+ * {@link ImpersonateMenu#impersonateWithRoles(String, List, String)}.
+ * </p>
+ */
+ String multiTenancyTokenFor(final String username);
+
}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserService.java b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserService.java
index e031623..f5437b9 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserService.java
@@ -83,7 +83,7 @@ public class UserService {
/**
* Returns the details about the current user, either the "effective" user (if being
- * {@link #impersonateUser(String, List) impersonated}) otherwise the "real" user (as obtained from
+ * {@link #impersonateUser(String, List, String) impersonated}) otherwise the "real" user (as obtained from
* the {@link InteractionContext} of the current thread).
*/
public Optional<UserMemento> currentUser() {
@@ -138,7 +138,7 @@ public class UserService {
*
* @see #currentUser()
* @see #supportsImpersonation()
- * @see #impersonateUser(String, List)
+ * @see #impersonateUser(String, List, String)
* @see #stopImpersonating()
*/
public boolean isImpersonating() {
@@ -157,7 +157,7 @@ public class UserService {
* This means that the result of this call varies on a request-by-request basis.
* </p>
*
- * @see #impersonateUser(String, List)
+ * @see #impersonateUser(String, List, String)
* @see #isImpersonating()
* @see #stopImpersonating()
*
@@ -199,17 +199,20 @@ public class UserService {
* @see #supportsImpersonation()
* @see #isImpersonating()
* @see #stopImpersonating()
- *
* @param userName - the name of the user to be impersonated
* @param roles - the collection of roles for the impersonated user to have.
+ * @param multiTenancyToken
*/
- public void impersonateUser(final String userName, final List<String> roles) {
+ public void impersonateUser(
+ final String userName,
+ final List<String> roles,
+ final String multiTenancyToken) {
impersonatingHolder().ifPresent(x ->
- {
- val userMemento = UserMemento.ofNameAndRoleNames(userName, roles)
- .withImpersonating(true);
- x.setUserMemento(userMemento);
- }
+ x.setUserMemento(
+ UserMemento.ofNameAndRoleNames(userName, roles)
+ .withImpersonating(true)
+ .withMultiTenancyToken(multiTenancyToken)
+ )
);
}
@@ -225,11 +228,11 @@ public class UserService {
*
* <p>
* Intended to be called at some point after
- * {@link #impersonateUser(String, List)} would have been called.
+ * {@link #impersonateUser(String, List, String)} would have been called.
* </p>
*
* @see #supportsImpersonation()
- * @see #impersonateUser(String, List)
+ * @see #impersonateUser(String, List, String)
* @see #isImpersonating()
*/
public void stopImpersonating() {
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/user/ImpersonateMenuAdvisorDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/user/ImpersonateMenuAdvisorDefault.java
index e83e021..11ef312 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/user/ImpersonateMenuAdvisorDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/user/ImpersonateMenuAdvisorDefault.java
@@ -17,7 +17,7 @@ import org.apache.isis.applib.services.user.ImpersonateMenuAdvisor;
* <p>
* This has the effect that the
* {@link org.apache.isis.applib.services.user.ImpersonateMenu}'s
- * {@link org.apache.isis.applib.services.user.ImpersonateMenu#impersonateWithRoles(String, List) impersonateWithRoles}
+ * {@link org.apache.isis.applib.services.user.ImpersonateMenu#impersonateWithRoles(String, List, String) impersonateWithRoles}
* action will be hidden.
* </p>
*/
@@ -38,9 +38,13 @@ public class ImpersonateMenuAdvisorDefault implements ImpersonateMenuAdvisor {
}
@Override
- public List<String> roleNamesFor(
- final String username) {
+ public List<String> roleNamesFor(final String username) {
return Collections.emptyList();
}
+ @Override
+ public String multiTenancyTokenFor(String username) {
+ return null;
+ }
+
}
diff --git a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/permission/dom/ApplicationPermissionRepository.java b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/permission/dom/ApplicationPermissionRepository.java
index 1ddfdd9..5ef5383 100644
--- a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/permission/dom/ApplicationPermissionRepository.java
+++ b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/permission/dom/ApplicationPermissionRepository.java
@@ -98,7 +98,7 @@ public interface ApplicationPermissionRepository {
* Uses the {@link UserMemento#getRoles() roles} held within the provided {@link UserMemento}.
*
* <p>
- * Added to support {@link org.apache.isis.applib.services.user.ImpersonateMenu#impersonateWithRoles(String, List) impersonation by role}.
+ * Added to support {@link org.apache.isis.applib.services.user.ImpersonateMenu#impersonateWithRoles(String, List, String) impersonation by role}.
* </p>
*
* @see #findByRoleNames(List)
diff --git a/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/IsisModuleExtSecmanIntegration.java b/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/IsisModuleExtSecmanIntegration.java
index 23eb2a8..ff1c766 100644
--- a/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/IsisModuleExtSecmanIntegration.java
+++ b/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/IsisModuleExtSecmanIntegration.java
@@ -26,6 +26,7 @@ import org.apache.isis.extensions.secman.integration.authorizor.AuthorizorSecman
import org.apache.isis.extensions.secman.integration.facets.TenantedAuthorizationPostProcessor;
import org.apache.isis.extensions.secman.integration.spiimpl.ImpersonateMenuAdvisorForSecman;
import org.apache.isis.extensions.secman.integration.spiimpl.TableColumnVisibilityServiceForSecman;
+import org.apache.isis.extensions.secman.integration.usermementorefiner.UserMementoRefinerFromApplicationUser;
import org.apache.isis.extensions.secman.integration.userreg.UserRegistrationServiceForSecman;
/**
@@ -43,6 +44,8 @@ import org.apache.isis.extensions.secman.integration.userreg.UserRegistrationSer
ImpersonateMenuAdvisorForSecman.class, //not activated by default yet
UserRegistrationServiceForSecman.class,
+ UserMementoRefinerFromApplicationUser.class,
+
})
public class IsisModuleExtSecmanIntegration {
diff --git a/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/spiimpl/ImpersonateMenuAdvisorForSecman.java b/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/spiimpl/ImpersonateMenuAdvisorForSecman.java
index 8e293f2..142a19f 100644
--- a/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/spiimpl/ImpersonateMenuAdvisorForSecman.java
+++ b/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/spiimpl/ImpersonateMenuAdvisorForSecman.java
@@ -7,10 +7,10 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Named;
-import org.apache.isis.applib.annotation.PriorityPrecedence;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
+import org.apache.isis.applib.annotation.PriorityPrecedence;
import org.apache.isis.applib.services.message.MessageService;
import org.apache.isis.applib.services.user.ImpersonateMenuAdvisor;
import org.apache.isis.applib.services.user.UserService;
@@ -68,4 +68,15 @@ public class ImpersonateMenuAdvisorForSecman implements ImpersonateMenuAdvisor {
.collect(Collectors.toList());
}
+ @Override
+ public String multiTenancyTokenFor(String username) {
+ if(username == null) {
+ return null;
+ }
+ val applicationUser =
+ applicationUserRepository.findByUsername(username)
+ .orElseThrow(RuntimeException::new);
+ return applicationUser.getAtPath();
+ }
+
}
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/applib/mixins/Object_impersonateWithRoles.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/applib/mixins/Object_impersonateWithRoles.java
index f326abf..2bc0da9 100644
--- a/viewers/common/src/main/java/org/apache/isis/viewer/common/applib/mixins/Object_impersonateWithRoles.java
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/applib/mixins/Object_impersonateWithRoles.java
@@ -37,7 +37,7 @@ import lombok.RequiredArgsConstructor;
import lombok.val;
/**
- * Same as {@link ImpersonateMenu#impersonateWithRoles(String, List)},
+ * Same as {@link ImpersonateMenu#impersonateWithRoles(String, List, String)},
* but implemented as a mixin so that can be invoked while accessing an object.
*
* @since 2.0 {@index}
@@ -67,8 +67,9 @@ public class Object_impersonateWithRoles {
public Object act(
final String userName,
- final List<String> roleNames) {
- impersonateMenu.impersonateWithRoles(userName, roleNames);
+ final List<String> roleNames,
+ final String multiTenancyToken) {
+ impersonateMenu.impersonateWithRoles(userName, roleNames, multiTenancyToken);
return holder;
}
@@ -94,16 +95,18 @@ public class Object_impersonateWithRoles {
return null;
}
- @MemberSupport public List<String> choices1Act(
- final String userName) {
+ @MemberSupport public List<String> choices1Act(final String userName) {
return impersonateMenu.choices1ImpersonateWithRoles(userName);
}
- @MemberSupport public List<String> default1Act(
- final String userName) {
+ @MemberSupport public List<String> default1Act(final String userName) {
return impersonateMenu.default1ImpersonateWithRoles(userName);
}
+ @MemberSupport public String default2Act(final String userName, final List<String> roleNames) {
+ return impersonateMenu.default2ImpersonateWithRoles(userName, roleNames);
+ }
+
@Inject ImpersonateMenu impersonateMenu;
}
[isis] 01/05: ISIS-2728: adds multiTenancyToken into UserMemento
Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-2728
in repository https://gitbox.apache.org/repos/asf/isis.git
commit c846062e254db48da6608e89df0e62f7e1c2a471
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Jun 29 07:22:04 2021 +0100
ISIS-2728: adds multiTenancyToken into UserMemento
(cherry picked from commit 279be8e853667adfece8ad321ee6c1b0ff32fe5c)
(cherry picked from commit 243fb2960ed04eb0c728671a9ece787995e187ef)
---
.../org/apache/isis/applib/services/user/UserMemento.java | 12 ++++++++++--
.../applib/services/user/UserMemento.layout.fallback.xml | 2 +-
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
index 38825f7..4469a1e 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
@@ -183,7 +183,7 @@ public class UserMemento implements Serializable {
* where the validity of the session is defined by headers in the request.
*/
@Property
- @PropertyLayout(fieldSetId = "authentication", sequence = "1")
+ @PropertyLayout(fieldSetId = "security", sequence = "1")
@Getter @Builder.Default @With(onMethod_ = {@Programmatic})
@NonNull
AuthenticationSource authenticationSource = AuthenticationSource.DEFAULT;
@@ -205,11 +205,18 @@ public class UserMemento implements Serializable {
@Property(optionality = Optionality.OPTIONAL)
- @PropertyLayout(fieldSetId = "authentication", sequence = "2")
+ @PropertyLayout(fieldSetId = "security", sequence = "2")
@Getter @Builder.Default @With(onMethod_ = {@Programmatic})
boolean impersonating = false;
+ @Property(optionality = Optionality.OPTIONAL)
+ @PropertyLayout(fieldSetId = "security", sequence = "3")
+ @Getter @With(onMethod_ = {@Programmatic})
+ @Nullable
+ String multiTenancyToken;
+
+
private static final String DEFAULT_AUTH_VALID_CODE = "";
/**
@@ -282,6 +289,7 @@ public class UserMemento implements Serializable {
.avatarUrl(avatarUrl)
.impersonating(impersonating)
.realName(realName)
+ .multiTenancyToken(multiTenancyToken)
.roles(roles);
}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.layout.fallback.xml b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.layout.fallback.xml
index 1b2d386..abe976c 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.layout.fallback.xml
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.layout.fallback.xml
@@ -53,7 +53,7 @@ under the License.
</bs3:tab>
</bs3:tabGroup>
<cpt:fieldSet name="Details" id="details"/>
- <cpt:fieldSet name="Authentication" id="authentication"/>
+ <cpt:fieldSet name="Security" id="security"/>
</bs3:col>
<bs3:col span="6">
<cpt:collection id="roles"/>
[isis] 02/05: ISIS-2728: adds UserMemento#multiTenancyToken unit
tests
Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-2728
in repository https://gitbox.apache.org/repos/asf/isis.git
commit ecfce2aa14d94447de1bc7d3ae268267df658a9f
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Jun 11 16:47:00 2021 +0100
ISIS-2728: adds UserMemento#multiTenancyToken unit tests
(cherry picked from commit e141c7ffb8f401eb80d99997e12b0121604a1d21)
(cherry picked from commit 6de24feb8a29d2ec325679d6497ac6887d9949f2)
---
.../isis/applib/services/user/UserMemento.java | 7 ++++++
.../applib/services/user/UserMemento_Test.java | 29 +++++++++++++++++++++-
2 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
index 4469a1e..5b5c78b 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
@@ -210,6 +210,13 @@ public class UserMemento implements Serializable {
boolean impersonating = false;
+ /**
+ * Indicates which tenancy (or tenancies) this user has access to.
+ *
+ * <p>
+ * The interpretation of this token is implementation-specific.
+ * </p>
+ */
@Property(optionality = Optionality.OPTIONAL)
@PropertyLayout(fieldSetId = "security", sequence = "3")
@Getter @With(onMethod_ = {@Programmatic})
diff --git a/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java b/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java
index 504ac66..8cef9df 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java
@@ -215,6 +215,29 @@ class UserMemento_Test {
}
@Nested
+ class withTenancyToken {
+
+ @Test
+ void user_and_roles_preserved_and_impersonating_flag_set() throws MalformedURLException {
+
+ // given
+ val userMemento = UserMemento.ofNameAndRoleNames("fredflintstone", "CAVEMAN", "HUSBAND");
+
+ // when
+ val userMemento2 = userMemento.withMultiTenancyToken("/ITA");
+
+ // then copy created
+ Assertions.assertThat(userMemento2).isNotSameAs(userMemento);
+
+ // then copy correct
+ Assertions.assertThat(userMemento2.getMultiTenancyToken()).isEqualTo("/ITA");
+
+ // then original unchanged
+ Assertions.assertThat(userMemento.getMultiTenancyToken()).isNull();
+ }
+ }
+
+ @Nested
class all_the_withers {
@Test
@@ -225,7 +248,9 @@ class UserMemento_Test {
.withRoleAdded("CAVEMAN")
.withRoleAdded("HUSBAND")
.withAvatarUrl(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"))
- .withRealName("Fred Flintstone");
+ .withRealName("Fred Flintstone")
+ .withMultiTenancyToken("/USA/Bedrock")
+ ;
// then
Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
@@ -250,6 +275,7 @@ class UserMemento_Test {
Assertions.assertThat(userMemento2.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
Assertions.assertThat(userMemento2.getRealName()).isEqualTo("Fred Flintstone");
Assertions.assertThat(userMemento2.isImpersonating()).isTrue();
+ Assertions.assertThat(userMemento2.getMultiTenancyToken()).isEqualTo("/USA/Bedrock");
// then original unchanged
Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
@@ -259,6 +285,7 @@ class UserMemento_Test {
Assertions.assertThat(userMemento.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
Assertions.assertThat(userMemento.getRealName()).isEqualTo("Fred Flintstone");
Assertions.assertThat(userMemento.isImpersonating()).isFalse();
+ Assertions.assertThat(userMemento.getMultiTenancyToken()).isEqualTo("/USA/Bedrock");
}
}
[isis] 03/05: ISIS-2728: introduces UserMementoRefiner as a new SPI
Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-2728
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 0f8b5be75b7e5d9f9c51d50aa3134898407ca523
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Jun 29 10:17:43 2021 +0100
ISIS-2728: introduces UserMementoRefiner as a new SPI
to allow secman to be able to add in the multiTenancyToken from the ApplicationUser
(cherry picked from commit e44bebe8a9928f58cc42c1be73c1cd13066801da)
(cherry picked from commit 5536482fd17986686c867418de4615f1f0d8d6a1)
---
.../services/iactnlayer/InteractionContext.java | 35 ++++++++--
.../iactnlayer/InteractionContextUtil.java | 22 ++++++
.../manager/AuthenticationManager.java | 36 ++++++++--
.../authentication/manager/UserMementoRefiner.java | 78 ++++++++++++++++++++++
.../authconverters/AuthenticationConverter.java | 2 +-
5 files changed, 160 insertions(+), 13 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContext.java b/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContext.java
index 1d75cb7..c7d30f9 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContext.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContext.java
@@ -28,10 +28,14 @@ import org.apache.isis.applib.clock.VirtualClock;
import org.apache.isis.applib.services.iactn.Interaction;
import org.apache.isis.applib.services.user.UserMemento;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
import lombok.Builder;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
+import lombok.ToString;
import lombok.With;
/**
@@ -39,7 +43,12 @@ import lombok.With;
*
* @since 2.0 {@index}
*/
-@lombok.Value @Builder
+@Getter
+@lombok.experimental.FieldDefaults(makeFinal=false, level= AccessLevel.PRIVATE)
+@AllArgsConstructor
+@ToString
+@EqualsAndHashCode
+@Builder
@RequiredArgsConstructor
public class InteractionContext implements Serializable {
@@ -66,11 +75,12 @@ public class InteractionContext implements Serializable {
/**
* The (programmatically) simulated (or actual) user.
*
- * @apiNote immutable, allows an {@link Interaction} to (logically) run with its
+ * @apiNote practically immutable, allows an {@link Interaction} to (logically) run with its
* own simulated (or actual) user
+ *
*/
@With @Getter @Builder.Default
- @NonNull UserMemento user = UserMemento.system();
+ @NonNull /*final*/ UserMemento user = UserMemento.system();
/**
* The (programmatically) simulated (or actual) clock.
@@ -79,13 +89,13 @@ public class InteractionContext implements Serializable {
* own simulated (or actual) clock
*/
@With @Getter @Builder.Default
- @NonNull VirtualClock clock = VirtualClock.system();
+ @NonNull final VirtualClock clock = VirtualClock.system();
@With @Getter @Builder.Default
- @NonNull Locale locale = Locale.getDefault();
+ @NonNull final Locale locale = Locale.getDefault();
@With @Getter @Builder.Default
- @NonNull TimeZone timeZone = TimeZone.getDefault();
+ @NonNull final TimeZone timeZone = TimeZone.getDefault();
/**
@@ -146,5 +156,16 @@ public class InteractionContext implements Serializable {
return mappers.reduce(t -> t, (a,b) -> a.andThen(b)::apply);
}
-
+ /**
+ * For internal usage, not API.
+ *
+ * <p>
+ * Instead, use {@link #withUser(UserMemento)}, which honours the value semantics of this class.
+ * </p>
+ *
+ * @param user
+ */
+ void replaceUser(UserMemento user) {
+ this.user = user;
+ }
}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContextUtil.java b/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContextUtil.java
new file mode 100644
index 0000000..4f38b42
--- /dev/null
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContextUtil.java
@@ -0,0 +1,22 @@
+package org.apache.isis.applib.services.iactnlayer;
+
+import org.apache.isis.applib.services.user.UserMemento;
+
+import lombok.experimental.UtilityClass;
+
+
+@UtilityClass
+public class InteractionContextUtil{
+
+ /**
+ * For internal usage, not formal API.
+ *
+ * <p>
+ * Instead, use {@link InteractionContext#withUser(UserMemento)}, which honours the value semantics of this class.
+ * </p>
+ */
+ public static void replaceUserIn(InteractionContext interactionContext, UserMemento userMemento) {
+ interactionContext.replaceUser(userMemento);
+ }
+
+}
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java
index 8f03b81..5457f18 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java
@@ -35,7 +35,9 @@ import org.springframework.transaction.annotation.Transactional;
import org.apache.isis.applib.annotation.PriorityPrecedence;
import org.apache.isis.applib.exceptions.unrecoverable.NoAuthenticatorException;
import org.apache.isis.applib.services.iactnlayer.InteractionContext;
+import org.apache.isis.applib.services.iactnlayer.InteractionContextUtil;
import org.apache.isis.applib.services.iactnlayer.InteractionService;
+import org.apache.isis.applib.services.user.UserMemento;
import org.apache.isis.applib.util.ToString;
import org.apache.isis.commons.collections.Can;
import org.apache.isis.commons.internal.base._Timing;
@@ -61,16 +63,19 @@ public class AuthenticationManager {
private final @NonNull InteractionService interactionService;
private final @NonNull RandomCodeGenerator randomCodeGenerator;
private final @NonNull Can<Registrar> registrars;
+ private final @NonNull List<UserMementoRefiner> userMementoRefiners;
@Inject
public AuthenticationManager(
final List<Authenticator> authenticators,
// needs @Lazy due to circular provisioning dependency
final @Lazy InteractionService anonymousInteractionFactory,
- final RandomCodeGenerator randomCodeGenerator) {
+ final RandomCodeGenerator randomCodeGenerator,
+ final List<UserMementoRefiner> userMementoRefiners) {
this.interactionService = anonymousInteractionFactory;
this.randomCodeGenerator = randomCodeGenerator;
this.authenticators = Can.ofCollection(authenticators);
+ this.userMementoRefiners = userMementoRefiners;
if (this.authenticators.isEmpty()) {
throw new NoAuthenticatorException("No authenticators specified");
}
@@ -102,13 +107,13 @@ public class AuthenticationManager {
return interactionService.callAnonymous(()->{
for (val authenticator : compatibleAuthenticators) {
- val authentication = authenticator.authenticate(request, getUnusedRandomCode());
- if (authentication != null) {
- val userMemento = authentication.getUser();
+ val interactionContext = authenticator.authenticate(request, getUnusedRandomCode());
+ if (interactionContext != null) {
+ val userMemento = refineUserWithin(interactionContext);
userByValidationCode.put(
userMemento.getAuthenticationCode(),
userMemento.getName());
- return authentication;
+ return interactionContext;
}
}
@@ -116,6 +121,27 @@ public class AuthenticationManager {
});
}
+ /**
+ * Iterates over all available {@link UserMementoRefiner}s; if at the end the {@link UserMemento} has been changed,
+ * then replaces (using a private API) the {@link UserMemento} held within {@link InteractionContext}.
+ *
+ * @param interactionContext
+ * @return
+ */
+ @NonNull
+ private UserMemento refineUserWithin(InteractionContext interactionContext) {
+ val userMementoOrig = interactionContext.getUser();
+ UserMemento userMemento = userMementoOrig;
+ for (UserMementoRefiner refiner : userMementoRefiners) {
+ final UserMemento refined = refiner.refine(userMemento);
+ userMemento = refined != null ? refined : userMemento;
+ }
+ if(userMemento != userMementoOrig) {
+ InteractionContextUtil.replaceUserIn(interactionContext, userMemento);
+ }
+ return interactionContext.getUser();
+ }
+
private String getUnusedRandomCode() {
val stopWatch = _Timing.now();
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/UserMementoRefiner.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/UserMementoRefiner.java
new file mode 100644
index 0000000..cdd895f
--- /dev/null
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/UserMementoRefiner.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.core.security.authentication.manager;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import org.apache.isis.applib.annotation.PriorityPrecedence;
+import org.apache.isis.applib.exceptions.unrecoverable.NoAuthenticatorException;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
+import org.apache.isis.applib.services.iactnlayer.InteractionService;
+import org.apache.isis.applib.services.user.UserMemento;
+import org.apache.isis.applib.util.ToString;
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._Timing;
+import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.core.security.authentication.AuthenticationRequest;
+import org.apache.isis.core.security.authentication.Authenticator;
+import org.apache.isis.core.security.authentication.standard.RandomCodeGenerator;
+import org.apache.isis.core.security.authentication.standard.Registrar;
+
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.val;
+
+/**
+ * SPI provided by the internal {@link AuthenticationManager}, allowing the {@link UserMemento} representing an
+ * authenticated (logged in) user to be refined.
+ *
+ * <p>
+ * As {@link UserMemento} is immutable, the implementation must return a new instance. This new instance replaces
+ * the {@link InteractionContext#getUser() user reference held} by {@link InteractionContext}.
+ * </p>
+ *
+ * <p>
+ * Originally introduced to allow SecMan to update the {@link UserMemento#getMultiTenancyToken() multi-tenancy}
+ * token of {@link UserMemento}.
+ * </p>
+ */
+public interface UserMementoRefiner {
+
+ /**
+ * Return either the same (unchanged) or an updated {@link UserMemento} to use instead of the original within the
+ * owning {@link InteractionContext}.
+ *
+ * @param userMemento - to be refined
+ * @return the userMemento that is refined, or else unchanged.
+ */
+ UserMemento refine(final UserMemento userMemento);
+
+}
diff --git a/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverter.java b/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverter.java
index 39efb07..535a3c2 100644
--- a/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverter.java
+++ b/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverter.java
@@ -24,7 +24,7 @@ import org.apache.isis.applib.services.user.UserMemento;
* All known converters are checked one by one, but checking stops once one
* converter has successively converted the {@link Authentication} into a
* {@link UserMemento} (in other words, chain-of-responsibility pattern).
- * Use the {@link org.springframework.core.Ordered} to influence the order
+ * Use the {@link javax.annotation.Priority} annotation to influence the order
* in which converter implementations are checked.
* </p>
*