This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push:
new 852405f267 ISIS-3113: code de-duplication around
AuthenticationConverter
852405f267 is described below
commit 852405f267c5394cd841a0886a07a412986eec89
Author: Andi Huber <[email protected]>
AuthorDate: Tue Aug 9 18:12:50 2022 +0200
ISIS-3113: code de-duplication around AuthenticationConverter
---
.../session/InteractionServiceDefault.java | 16 ++++++-----
extensions/pom.xml | 6 ++++
.../oauth2/IsisModuleExtSpringSecurityOAuth2.java | 4 +--
...thenticationConverterOfOAuth2UserPrincipal.java | 23 +++++++--------
.../authconverters/AuthenticationConverter.java | 33 ++++++++++++++++++++--
...nticationConverterOfAuthenticatedPrincipal.java | 21 ++++++++------
.../AuthenticationConverterOfStringPrincipal.java | 24 +++++++++-------
...henticationConverterOfUserDetailsPrincipal.java | 22 ++++++++-------
.../spring/webmodule/SpringSecurityFilter.java | 18 ++++++++++--
9 files changed, 112 insertions(+), 55 deletions(-)
diff --git
a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionServiceDefault.java
b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionServiceDefault.java
index 99010fdf30..a0be50b44d 100644
---
a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionServiceDefault.java
+++
b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionServiceDefault.java
@@ -54,7 +54,6 @@ import org.apache.isis.applib.util.schema.CommandDtoUtils;
import org.apache.isis.applib.util.schema.InteractionDtoUtils;
import org.apache.isis.applib.util.schema.InteractionsDtoUtils;
import org.apache.isis.commons.functional.ThrowingRunnable;
-import org.apache.isis.commons.internal.assertions._Assert;
import org.apache.isis.commons.internal.base._Casts;
import org.apache.isis.commons.internal.concurrent._ConcurrentContext;
import org.apache.isis.commons.internal.concurrent._ConcurrentTaskList;
@@ -348,12 +347,15 @@ implements
private void requestRollback(final Throwable cause) {
val stack = interactionLayerStack.get();
- _Assert.assertFalse(stack.isEmpty(), ()->
- String.format(
- "unexpected state: missing interaction (layer) on
interaction rollback; "
- + "rollback was caused by %s -> %s",
- cause.getClass().getName(),
- cause.getMessage()));
+ if(stack.isEmpty()) {
+ // seeing this code-path, when the corresponding runnable/callable
+ // by itself causes the interaction stack to be closed
+ log.warn("unexpected state: missing interaction (layer) on
interaction rollback; "
+ + "rollback was caused by {} -> {}",
+ cause.getClass().getName(),
+ cause.getMessage());
+ return;
+ }
val interaction =
_Casts.<IsisInteraction>uncheckedCast(stack.get(0).getInteraction());
txBoundaryHandler.requestRollback(interaction);
}
diff --git a/extensions/pom.xml b/extensions/pom.xml
index c5e338ba8b..db3535adfa 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -431,6 +431,12 @@
<artifactId>isis-extensions-cors-impl</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
+
+ <dependency>
+ <groupId>org.apache.isis.extensions</groupId>
+
<artifactId>isis-extensions-spring-security-oauth2</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.isis.extensions</groupId>
diff --git
a/extensions/security/spring-oauth2/src/main/java/org/apache/isis/extensions/spring/security/oauth2/IsisModuleExtSpringSecurityOAuth2.java
b/extensions/security/spring-oauth2/src/main/java/org/apache/isis/extensions/spring/security/oauth2/IsisModuleExtSpringSecurityOAuth2.java
index 5e9e82f627..7933309a3c 100644
---
a/extensions/security/spring-oauth2/src/main/java/org/apache/isis/extensions/spring/security/oauth2/IsisModuleExtSpringSecurityOAuth2.java
+++
b/extensions/security/spring-oauth2/src/main/java/org/apache/isis/extensions/spring/security/oauth2/IsisModuleExtSpringSecurityOAuth2.java
@@ -24,8 +24,6 @@ import org.springframework.context.annotation.Import;
import
org.apache.isis.extensions.spring.security.oauth2.authconverters.AuthenticationConverterOfOAuth2UserPrincipal;
import org.apache.isis.security.spring.IsisModuleSecuritySpring;
-import lombok.extern.log4j.Log4j2;
-
/**
* Configuration Bean to support authentication using Spring Security's
* OAuth2 client.
@@ -41,7 +39,7 @@ import lombok.extern.log4j.Log4j2;
AuthenticationConverterOfOAuth2UserPrincipal.class,
})
-@Log4j2
+//@Log4j2
public class IsisModuleExtSpringSecurityOAuth2 {
}
diff --git
a/extensions/security/spring-oauth2/src/main/java/org/apache/isis/extensions/spring/security/oauth2/authconverters/AuthenticationConverterOfOAuth2UserPrincipal.java
b/extensions/security/spring-oauth2/src/main/java/org/apache/isis/extensions/spring/security/oauth2/authconverters/AuthenticationConverterOfOAuth2UserPrincipal.java
index 00a767ce6b..95f89e6a4b 100644
---
a/extensions/security/spring-oauth2/src/main/java/org/apache/isis/extensions/spring/security/oauth2/authconverters/AuthenticationConverterOfOAuth2UserPrincipal.java
+++
b/extensions/security/spring-oauth2/src/main/java/org/apache/isis/extensions/spring/security/oauth2/authconverters/AuthenticationConverterOfOAuth2UserPrincipal.java
@@ -29,25 +29,26 @@ import org.apache.isis.applib.annotation.PriorityPrecedence;
import org.apache.isis.applib.services.user.UserMemento;
import org.apache.isis.security.spring.authconverters.AuthenticationConverter;
+import lombok.NonNull;
import lombok.val;
/**
- * Interprets an {@link Authentication} as containing an OAuth2 principal.
+ * Applies if {@link Authentication} holds a principal of type {@link
OAuth2User}.
*/
@Component
@javax.annotation.Priority(PriorityPrecedence.LATE - 150)
-public class AuthenticationConverterOfOAuth2UserPrincipal implements
AuthenticationConverter {
+public class AuthenticationConverterOfOAuth2UserPrincipal
+extends AuthenticationConverter.Abstract<OAuth2User> {
+
+ public AuthenticationConverterOfOAuth2UserPrincipal() {
+ super(OAuth2User.class);
+ }
@Override
- public UserMemento convert(final Authentication authentication) {
- val principal = authentication.getPrincipal();
- if (principal instanceof OAuth2User) {
- val oAuth2User = (OAuth2User) principal;
- return UserMemento.ofNameAndRoleNames(usernameFrom(oAuth2User))
- .withAvatarUrl(avatarUrlFrom(oAuth2User))
- .withRealName(realNameFrom(oAuth2User));
- }
- return null;
+ protected UserMemento convertPrincipal(final @NonNull OAuth2User
oAuth2User) {
+ return UserMemento.ofNameAndRoleNames(usernameFrom(oAuth2User))
+ .withAvatarUrl(avatarUrlFrom(oAuth2User))
+ .withRealName(realNameFrom(oAuth2User));
}
protected static String usernameFrom(final OAuth2User oAuth2User) {
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 8ba60ef213..62ef5121e8 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
@@ -21,10 +21,17 @@ package org.apache.isis.security.spring.authconverters;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
+import org.springframework.lang.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import org.apache.isis.applib.services.user.UserMemento;
+import org.apache.isis.commons.internal.base._Casts;
+
+import lombok.AccessLevel;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.val;
/**
* Defines an SPI to attempt to convert a Spring {@link Authentication} into
@@ -61,7 +68,7 @@ public interface AuthenticationConverter {
*
* <p>
* There are many different implementations of {@link Authentication},
- * so the implementation should be targetted at a specific
+ * so the implementation should be targeted at a specific
* implementation.
* </p>
*
@@ -73,5 +80,27 @@ public interface AuthenticationConverter {
* @param authentication to attempt to convert
* @return non-null if could be converted
*/
- UserMemento convert(final Authentication authentication);
+ @Nullable
+ UserMemento convert(@NonNull Authentication authentication);
+
+ // -- BASE CLASS FOR CONVENIENCE
+
+ @RequiredArgsConstructor(access = AccessLevel.PROTECTED)
+ abstract class Abstract<T> implements AuthenticationConverter {
+
+ private final @NonNull Class<T> principalClass;
+
+ @Override
+ public final UserMemento convert(final @NonNull Authentication
authentication) {
+ val principal = authentication.getPrincipal();
+ return _Casts.castTo(principalClass, principal)
+ .map(this::convertPrincipal)
+ .orElse(null);
+ }
+
+ protected abstract UserMemento convertPrincipal(@NonNull T principal);
+
+ }
+
+
}
diff --git
a/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfAuthenticatedPrincipal.java
b/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfAuthenticatedPrincipal.java
index 3c04d7af65..9a83a71b29 100644
---
a/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfAuthenticatedPrincipal.java
+++
b/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfAuthenticatedPrincipal.java
@@ -25,19 +25,22 @@ import org.springframework.stereotype.Component;
import org.apache.isis.applib.annotation.PriorityPrecedence;
import org.apache.isis.applib.services.user.UserMemento;
-import lombok.val;
+import lombok.NonNull;
+/**
+ * Applies if {@link Authentication} holds a principal of type {@link
AuthenticatedPrincipal}.
+ */
@Component
@javax.annotation.Priority(PriorityPrecedence.LATE - 100)
-public class AuthenticationConverterOfAuthenticatedPrincipal implements
AuthenticationConverter {
+public class AuthenticationConverterOfAuthenticatedPrincipal
+extends AuthenticationConverter.Abstract<AuthenticatedPrincipal> {
+
+ public AuthenticationConverterOfAuthenticatedPrincipal() {
+ super(AuthenticatedPrincipal.class);
+ }
@Override
- public UserMemento convert(Authentication authentication) {
- val principal = authentication.getPrincipal();
- if (principal instanceof AuthenticatedPrincipal) {
- val authenticatedPrincipal = (AuthenticatedPrincipal) principal;
- return
UserMemento.ofNameAndRoleNames(authenticatedPrincipal.getName());
- }
- return null;
+ protected UserMemento convertPrincipal(final @NonNull
AuthenticatedPrincipal principal) {
+ return UserMemento.ofNameAndRoleNames(principal.getName());
}
}
diff --git
a/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfStringPrincipal.java
b/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfStringPrincipal.java
index b50970993e..a998928bbb 100644
---
a/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfStringPrincipal.java
+++
b/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfStringPrincipal.java
@@ -24,20 +24,24 @@ import org.springframework.stereotype.Component;
import org.apache.isis.applib.annotation.PriorityPrecedence;
import org.apache.isis.applib.services.user.UserMemento;
-import lombok.val;
+import lombok.NonNull;
+/**
+ * Applies if {@link Authentication} holds a principal of type {@link String}.
+ */
@Component
@javax.annotation.Priority(PriorityPrecedence.LATE + 100)
-public class AuthenticationConverterOfStringPrincipal implements
AuthenticationConverter {
+public class AuthenticationConverterOfStringPrincipal
+extends AuthenticationConverter.Abstract<String> {
+
+ public AuthenticationConverterOfStringPrincipal() {
+ super(String.class);
+ }
@Override
- public UserMemento convert(Authentication authentication) {
- val principal = authentication.getPrincipal();
- if (principal instanceof String) {
- val name = (String) principal;
- return UserMemento.ofNameAndRoleNames(name);
- } else {
- return null;
- }
+ protected UserMemento convertPrincipal(final @NonNull String name) {
+ return name.isEmpty()
+ ? null
+ : UserMemento.ofNameAndRoleNames(name);
}
}
diff --git
a/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfUserDetailsPrincipal.java
b/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfUserDetailsPrincipal.java
index d06b847865..4650ecebfb 100644
---
a/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfUserDetailsPrincipal.java
+++
b/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfUserDetailsPrincipal.java
@@ -25,20 +25,22 @@ import org.springframework.stereotype.Component;
import org.apache.isis.applib.annotation.PriorityPrecedence;
import org.apache.isis.applib.services.user.UserMemento;
-import lombok.val;
+import lombok.NonNull;
+/**
+ * Applies if {@link Authentication} holds a principal of type {@link
UserDetails}.
+ */
@Component
@javax.annotation.Priority(PriorityPrecedence.LATE - 200)
-public class AuthenticationConverterOfUserDetailsPrincipal implements
AuthenticationConverter {
+public class AuthenticationConverterOfUserDetailsPrincipal
+extends AuthenticationConverter.Abstract<UserDetails> {
+
+ protected AuthenticationConverterOfUserDetailsPrincipal() {
+ super(UserDetails.class);
+ }
@Override
- public UserMemento convert(Authentication authentication) {
- val principal = authentication.getPrincipal();
- if (principal instanceof UserDetails) {
- val userDetails = (UserDetails) principal;
- return UserMemento.ofNameAndRoleNames(userDetails.getUsername());
- } else {
- return null;
- }
+ protected UserMemento convertPrincipal(final @NonNull UserDetails
userDetails) {
+ return UserMemento.ofNameAndRoleNames(userDetails.getUsername());
}
}
diff --git
a/security/spring/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java
b/security/spring/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java
index 96f6b8e2fe..405a810152 100644
---
a/security/spring/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java
+++
b/security/spring/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java
@@ -65,20 +65,32 @@ public class SpringSecurityFilter implements Filter {
.orElse(null);
if (userMemento == null) {
- ((HttpServletResponse)
servletResponse).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ setUnauthorized(servletResponse);
return; // either not authenticated or unknown principal type (not
handled)
}
val interactionContext =
InteractionContext.ofUserWithSystemDefaults(userMemento)
.withTimeZoneIfAny(userCurrentSessionTimeZoneHolder.getUserTimeZone());
- interactionService.run(
+ val result = interactionService.runAndCatch(
interactionContext,
()->filterChain.doFilter(servletRequest, servletResponse));
+
+ result.ifFailure(failure->{
+ failure.printStackTrace(); // debug
+ setUnauthorized(servletResponse);
+ });
+
+ // re-throw
+ result.ifFailureFail();
}
// -- HELPER
+ private void setUnauthorized(final ServletResponse servletResponse){
+ ((HttpServletResponse)
servletResponse).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
/**
* Optionally Spring's {@link Authentication}, based on presence
* (no matter whether actually authenticated).
@@ -110,7 +122,7 @@ public class SpringSecurityFilter implements Filter {
.withRoleAdded(UserMemento.AUTHORIZED_USER_ROLE)
.withAuthenticationSource(AuthenticationSource.EXTERNAL));
}
- } catch(final Exception ignored) {
+ } catch(final Throwable ignored) {
}
}
return Optional.empty();