diff --git a/celements-spring-security/pom.xml b/celements-spring-security/pom.xml
index ec5d68e..03baf07 100644
--- a/celements-spring-security/pom.xml
+++ b/celements-spring-security/pom.xml
@@ -36,6 +36,11 @@
celements-servlet
provided
+
+ com.celements
+ celements-user-manager
+ provided
+
com.celements
celements-reference
@@ -144,6 +149,11 @@
celements-shared-tests
test
+
+ com.celements
+ celements-core
+ test
+
com.celements
celements-subsystem-migration-manager
diff --git a/celements-spring-security/src/main/java/com/celements/spring/security/CelSecurityFilterChainConfig.java b/celements-spring-security/src/main/java/com/celements/spring/security/CelSecurityFilterChainConfig.java
index 7f4ef34..917d521 100644
--- a/celements-spring-security/src/main/java/com/celements/spring/security/CelSecurityFilterChainConfig.java
+++ b/celements-spring-security/src/main/java/com/celements/spring/security/CelSecurityFilterChainConfig.java
@@ -30,6 +30,7 @@
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
import org.xwiki.context.Execution;
+import com.celements.auth.MainAdminConfig;
import com.celements.auth.user.UserService;
import com.celements.spring.security.oauth2.IdentityService;
import com.celements.spring.security.oauth2.cookietoken.CompositeBearerTokenResolver;
@@ -53,6 +54,7 @@ public class CelSecurityFilterChainConfig {
private final AuthenticationManagerResolver authManagerResolver;
private final UserService userService;
private final CookieTokenService tokenService;
+ private final MainAdminConfig mainAdminConfig;
private final Execution execution;
@Inject
@@ -61,11 +63,13 @@ public CelSecurityFilterChainConfig(
AuthenticationManagerResolver authManagerResolver,
UserService userService,
CookieTokenService tokenService,
+ MainAdminConfig mainAdminConfig,
Execution execution) {
this.identityService = identityService;
this.authManagerResolver = authManagerResolver;
this.userService = userService;
this.tokenService = tokenService;
+ this.mainAdminConfig = mainAdminConfig;
this.execution = execution;
}
@@ -102,7 +106,7 @@ public SecurityFilterChain loginFilterChain(
new TokenRefreshFilter(tokenService),
BearerTokenAuthenticationFilter.class)
.addFilterAfter(
- new ExecutionContextAuthenticationFilter(userService, execution),
+ new ExecutionContextAuthenticationFilter(userService, mainAdminConfig, execution),
BearerTokenAuthenticationFilter.class)
.addFilterAfter(
new HeaderToCookieAccessTokenFilter(tokenService),
@@ -144,7 +148,7 @@ public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
new TokenRefreshFilter(tokenService),
BearerTokenAuthenticationFilter.class)
.addFilterAfter(
- new ExecutionContextAuthenticationFilter(userService, execution),
+ new ExecutionContextAuthenticationFilter(userService, mainAdminConfig, execution),
BearerTokenAuthenticationFilter.class)
.addFilterAfter(
new HeaderToCookieAccessTokenFilter(tokenService),
diff --git a/celements-spring-security/src/main/java/com/celements/spring/security/oauth2/filter/ExecutionContextAuthenticationFilter.java b/celements-spring-security/src/main/java/com/celements/spring/security/oauth2/filter/ExecutionContextAuthenticationFilter.java
index 0826c04..d4a4ef7 100644
--- a/celements-spring-security/src/main/java/com/celements/spring/security/oauth2/filter/ExecutionContextAuthenticationFilter.java
+++ b/celements-spring-security/src/main/java/com/celements/spring/security/oauth2/filter/ExecutionContextAuthenticationFilter.java
@@ -1,6 +1,7 @@
package com.celements.spring.security.oauth2.filter;
import java.io.IOException;
+import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -11,7 +12,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
@@ -20,32 +23,47 @@
import org.springframework.web.filter.OncePerRequestFilter;
import org.xwiki.context.Execution;
+import com.celements.auth.MainAdminConfig;
import com.celements.auth.user.User;
+import com.celements.auth.user.UserInstantiationException;
import com.celements.auth.user.UserService;
import com.celements.execution.XWikiExecutionProp;
+import com.xpn.xwiki.user.api.XWikiUser;
public class ExecutionContextAuthenticationFilter extends OncePerRequestFilter {
private static final Logger LOGGER = LoggerFactory
.getLogger(ExecutionContextAuthenticationFilter.class);
- private final Execution execution;
private final UserService userService;
+ private final MainAdminConfig mainAdminConfig;
+ private final Execution execution;
- public ExecutionContextAuthenticationFilter(UserService userService, Execution execution) {
+ public ExecutionContextAuthenticationFilter(
+ UserService userService,
+ MainAdminConfig mainAdminConfig,
+ Execution execution) {
this.userService = userService;
+ this.mainAdminConfig = mainAdminConfig;
this.execution = execution;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
- Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+ var securityContext = SecurityContextHolder.getContext();
+ autoLogin(securityContext)
+ .or(() -> processAuthentication(securityContext))
+ .ifPresent(user -> execution.getContext().set(XWikiExecutionProp.XWIKI_USER, user));
+ filterChain.doFilter(request, response);
+ }
+
+ private Optional processAuthentication(SecurityContext securityContext) {
+ Authentication auth = securityContext.getAuthentication();
if ((auth != null) && auth.isAuthenticated()) {
String userId = auth.getName(); // the Keycloak GUID (sub)
String username;
String email;
-
if (auth instanceof JwtAuthenticationToken) {
JwtAuthenticationToken jwtAuth = (JwtAuthenticationToken) auth;
Jwt jwt = jwtAuth.getToken();
@@ -70,7 +88,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
User user = userOpt.get();
LOGGER.debug("setting xwiki isGlobal='{}', username='{}', email='{}'", user.isGlobal(),
user.asXWikiUser().getUser(), user.email());
- execution.getContext().set(XWikiExecutionProp.XWIKI_USER, user.asXWikiUser());
+ return Optional.of(user.asXWikiUser());
} else {
LOGGER.info("no celements user found for email='{}'", email);
}
@@ -81,7 +99,17 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
} else {
LOGGER.info("is NOT authenticated with user '{}'", "null");
}
- filterChain.doFilter(request, response);
+ return Optional.empty();
+ }
+
+ private Optional autoLogin(SecurityContext securityContext) {
+ if (!mainAdminConfig.isAutoLoginEnabled()) {
+ return Optional.empty();
+ }
+ var xwikiUser = mainAdminConfig.getXWikiUser();
+ var auth = new UsernamePasswordAuthenticationToken(xwikiUser.getUser(), null, List.of());
+ securityContext.setAuthentication(auth);
+ return Optional.of(xwikiUser);
}
}
diff --git a/celements-spring-security/src/test/java/com/celements/spring/security/oauth2/filter/ExecutionContextAuthenticationFilterTest.java b/celements-spring-security/src/test/java/com/celements/spring/security/oauth2/filter/ExecutionContextAuthenticationFilterTest.java
new file mode 100644
index 0000000..0acafa8
--- /dev/null
+++ b/celements-spring-security/src/test/java/com/celements/spring/security/oauth2/filter/ExecutionContextAuthenticationFilterTest.java
@@ -0,0 +1,77 @@
+package com.celements.spring.security.oauth2.filter;
+
+import static com.celements.execution.XWikiExecutionProp.*;
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import javax.servlet.FilterChain;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.xwiki.context.Execution;
+
+import com.celements.auth.MainAdminConfig;
+import com.celements.auth.user.UserService;
+import com.celements.common.test.AbstractComponentTest;
+import com.xpn.xwiki.user.api.XWikiUser;
+
+public class ExecutionContextAuthenticationFilterTest extends AbstractComponentTest {
+
+ private ExecutionContextAuthenticationFilter filter;
+ private UserService userService;
+ private MainAdminConfig mainAdminConfig;
+
+ @Before
+ public void prepareTest() throws Exception {
+ userService = createDefaultMock(UserService.class);
+ mainAdminConfig = createDefaultMock(MainAdminConfig.class);
+ filter = new ExecutionContextAuthenticationFilter(userService, mainAdminConfig,
+ getBeanFactory().getBean(Execution.class));
+ }
+
+ @After
+ public void clearSecurityContext() {
+ SecurityContextHolder.clearContext();
+ }
+
+ @Test
+ public void test_doFilterInternal_autoLoginAdmin() throws Exception {
+ HttpServletRequest request = createDefaultMock(HttpServletRequest.class);
+ HttpServletResponse response = createDefaultMock(HttpServletResponse.class);
+ FilterChain chain = createDefaultMock(FilterChain.class);
+ XWikiUser xwikiUser = new XWikiUser("xwiki:XWiki.Admin", true);
+ expect(mainAdminConfig.isAutoLoginEnabled()).andReturn(true);
+ expect(mainAdminConfig.getXWikiUser()).andReturn(xwikiUser);
+ chain.doFilter(request, response);
+ replayDefault();
+
+ filter.doFilterInternal(request, response, chain);
+
+ verifyDefault();
+ assertEquals("xwiki:XWiki.Admin",
+ SecurityContextHolder.getContext().getAuthentication().getName());
+ assertTrue(SecurityContextHolder.getContext().getAuthentication().isAuthenticated());
+ assertSame(xwikiUser, getBeanFactory().getBean(Execution.class).getContext()
+ .get(XWIKI_USER).orElseThrow());
+ }
+
+ @Test
+ public void test_doFilterInternal_autoLoginDisabled() throws Exception {
+ HttpServletRequest request = createDefaultMock(HttpServletRequest.class);
+ HttpServletResponse response = createDefaultMock(HttpServletResponse.class);
+ FilterChain chain = createDefaultMock(FilterChain.class);
+ expect(mainAdminConfig.isAutoLoginEnabled()).andReturn(false);
+ chain.doFilter(request, response);
+ replayDefault();
+
+ filter.doFilterInternal(request, response, chain);
+
+ verifyDefault();
+ assertNull(SecurityContextHolder.getContext().getAuthentication());
+ }
+
+}