This is an automated email from the ASF dual-hosted git repository.

jungm pushed a commit to branch issue/TOMEE-4591
in repository https://gitbox.apache.org/repos/asf/tomee.git

commit b28bfc0f95ac24ba20f46396b4a6905f7228afc2
Author: Markus Jung <[email protected]>
AuthorDate: Fri Apr 3 21:48:47 2026 +0200

    TOMEE-4591 - OpenIdAuthenticationMechanism redirectToOriginalResource don't 
treat case without stored request as an error
---
 .../cdi/OpenIdAuthenticationMechanism.java         |  32 ++++-
 .../cdi/OpenIdAuthenticationMechanismUnitTest.java | 132 +++++++++++++++++++++
 2 files changed, 158 insertions(+), 6 deletions(-)

diff --git 
a/tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/OpenIdAuthenticationMechanism.java
 
b/tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/OpenIdAuthenticationMechanism.java
index 230194cb44..28cadfb56d 100644
--- 
a/tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/OpenIdAuthenticationMechanism.java
+++ 
b/tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/OpenIdAuthenticationMechanism.java
@@ -243,11 +243,10 @@ public class OpenIdAuthenticationMechanism implements 
HttpAuthenticationMechanis
             }
 
             if (definition.redirectToOriginalResource() && 
!matchesOriginalRequest) {
-                if (originalRequest == null) {
-                    throw new 
IllegalStateException("redirectToOriginalResource=true is configured but no 
original request has been stored before");
+                AuthenticationStatus redirectStatus = 
redirectToStoredOriginalRequest(request, messageContext, originalRequest);
+                if (redirectStatus != null) {
+                    return redirectStatus;
                 }
-
-                return 
messageContext.redirect(appendQueryString(originalRequest, 
request.getQueryString()));
             }
 
             // Callback is okay, continue with (4)
@@ -269,8 +268,7 @@ public class OpenIdAuthenticationMechanism implements 
HttpAuthenticationMechanis
 
                 // We're finished, restore original request now and clean up
                 if (definition.redirectToOriginalResource()) {
-                    String originalRequestJson = storageHandler.get(request, 
response, OpenIdStorageHandler.REQUEST_KEY);
-                    
messageContext.withRequest(SavedRequest.fromJson(originalRequestJson).mask(request));
+                    restoreOriginalRequest(request, response, messageContext);
                 }
 
                 storageHandler.delete(request, response, 
OpenIdStorageHandler.NONCE_KEY);
@@ -284,6 +282,28 @@ public class OpenIdAuthenticationMechanism implements 
HttpAuthenticationMechanis
         return null;
     }
 
+    protected AuthenticationStatus 
redirectToStoredOriginalRequest(HttpServletRequest request, HttpMessageContext 
messageContext,
+                                                                   String 
originalRequest) {
+        if (originalRequest == null) {
+            LOGGER.warning("redirectToOriginalResource=true is configured but 
no original request has been stored before; continuing without redirecting to 
the original resource");
+            return null;
+        }
+
+        return messageContext.redirect(appendQueryString(originalRequest, 
request.getQueryString()));
+    }
+
+    protected void restoreOriginalRequest(HttpServletRequest request, 
HttpServletResponse response, HttpMessageContext messageContext) {
+        String originalRequestJson = storageHandler.get(request, response, 
OpenIdStorageHandler.REQUEST_KEY);
+        if (originalRequestJson == null) {
+            return;
+        }
+
+        SavedRequest savedRequest = SavedRequest.fromJson(originalRequestJson);
+        if (savedRequest != null) {
+            messageContext.withRequest(savedRequest.mask(request));
+        }
+    }
+
     protected AuthenticationStatus handleTokenResponse(TokenResponse 
tokenResponse, HttpMessageContext httpMessageContext) {
         openIdContext.setExpiresIn(tokenResponse.getExpiresIn());
         openIdContext.setTokenType(tokenResponse.getTokenType());
diff --git 
a/tomee/tomee-security/src/test/java/org/apache/tomee/security/cdi/OpenIdAuthenticationMechanismUnitTest.java
 
b/tomee/tomee-security/src/test/java/org/apache/tomee/security/cdi/OpenIdAuthenticationMechanismUnitTest.java
new file mode 100644
index 0000000000..2c3df3989e
--- /dev/null
+++ 
b/tomee/tomee-security/src/test/java/org/apache/tomee/security/cdi/OpenIdAuthenticationMechanismUnitTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.tomee.security.cdi;
+
+import com.sun.net.httpserver.HttpServer;
+import org.apache.openejb.util.reflection.Reflections;
+import org.apache.tomee.security.cdi.openid.TomEEOpenIdContext;
+import org.apache.tomee.security.cdi.openid.storage.OpenIdStorageHandler;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Answers;
+
+import jakarta.security.enterprise.AuthenticationStatus;
+import 
jakarta.security.enterprise.authentication.mechanism.http.HttpMessageContext;
+import 
jakarta.security.enterprise.authentication.mechanism.http.OpenIdAuthenticationMechanismDefinition;
+import 
jakarta.security.enterprise.authentication.mechanism.http.openid.OpenIdConstant;
+import jakarta.security.enterprise.identitystore.CredentialValidationResult;
+import jakarta.security.enterprise.identitystore.IdentityStoreHandler;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class OpenIdAuthenticationMechanismUnitTest {
+    private OpenIdAuthenticationMechanism authenticationMechanism;
+    private OpenIdAuthenticationMechanismDefinition definition;
+    private IdentityStoreHandler identityStoreHandler;
+    private SimpleStorageHandler storageHandler;
+
+    @Before
+    public void setUp() {
+        authenticationMechanism = new OpenIdAuthenticationMechanism();
+        definition = mock(OpenIdAuthenticationMechanismDefinition.class, 
Answers.RETURNS_DEEP_STUBS);
+        identityStoreHandler = mock(IdentityStoreHandler.class);
+        storageHandler = new SimpleStorageHandler();
+
+        Reflections.set(authenticationMechanism, "definition", definition);
+        Reflections.set(authenticationMechanism, "identityStoreHandler", 
identityStoreHandler);
+        Reflections.set(authenticationMechanism, "openIdContext", new 
TomEEOpenIdContext());
+        Reflections.set(authenticationMechanism, "storageHandler", 
storageHandler);
+
+        when(definition.clientId()).thenReturn("tomee-testing");
+        when(definition.clientSecret()).thenReturn("secret");
+        
when(definition.redirectURI()).thenReturn("https://example.com/redirect";);
+        when(definition.redirectToOriginalResource()).thenReturn(true);
+    }
+
+    @Test
+    public void 
callbackWithoutStoredOriginalRequestDoesNotThrowWhenRedirectToOriginalResourceIsEnabled()
 throws Exception {
+        HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
+        server.createContext("/token", exchange -> {
+            byte[] body = 
"{\"token_type\":\"Bearer\",\"access_token\":\"ACCESS\",\"id_token\":\"ID\",\"expires_in\":3600}"
+                    .getBytes(StandardCharsets.UTF_8);
+
+            exchange.getResponseHeaders().set("Content-Type", 
"application/json");
+            exchange.sendResponseHeaders(200, body.length);
+            exchange.getResponseBody().write(body);
+            exchange.close();
+        });
+        server.start();
+
+        try {
+            when(definition.providerMetadata().tokenEndpoint())
+                    .thenReturn("http://127.0.0.1:"; + 
server.getAddress().getPort() + "/token");
+            when(identityStoreHandler.validate(any()))
+                    .thenReturn(new CredentialValidationResult("caller", 
Set.of("users")));
+
+            HttpServletRequest request = mock(HttpServletRequest.class);
+            HttpServletResponse response = mock(HttpServletResponse.class);
+            HttpMessageContext messageContext = mock(HttpMessageContext.class, 
Answers.RETURNS_DEEP_STUBS);
+
+            
when(request.getParameter(OpenIdConstant.STATE)).thenReturn("STATE");
+            when(request.getParameter(OpenIdConstant.CODE)).thenReturn("CODE");
+            when(request.getRequestURL()).thenReturn(new 
StringBuffer("https://example.com/redirect";));
+            
when(messageContext.notifyContainerAboutLogin(any(CredentialValidationResult.class)))
+                    .thenReturn(AuthenticationStatus.SUCCESS);
+
+            storageHandler.set(request, response, 
OpenIdStorageHandler.STATE_KEY, "STATE");
+
+            AuthenticationStatus status = 
authenticationMechanism.performAuthentication(request, response, 
messageContext);
+
+            assertEquals(AuthenticationStatus.SUCCESS, status);
+            verify(messageContext, 
never()).withRequest(any(HttpServletRequest.class));
+        } finally {
+            server.stop(0);
+        }
+    }
+
+    private static class SimpleStorageHandler extends OpenIdStorageHandler {
+        private final Map<String, String> values = new HashMap<>();
+
+        @Override
+        public String get(HttpServletRequest request, HttpServletResponse 
response, String key) {
+            return values.get(key);
+        }
+
+        @Override
+        public void set(HttpServletRequest request, HttpServletResponse 
response, String key, String value) {
+            values.put(key, value);
+        }
+
+        @Override
+        public void delete(HttpServletRequest request, HttpServletResponse 
response, String key) {
+            values.remove(key);
+        }
+    }
+}

Reply via email to