Skip to content

Commit 7a0de2c

Browse files
jungmrzo1
authored andcommitted
Fix OpenID storage selection per mechanism
1 parent 2fd1e04 commit 7a0de2c

5 files changed

Lines changed: 175 additions & 5 deletions

File tree

tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/OpenIdAuthenticationMechanism.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,14 @@ private String redirectPath() {
113113

114114
@Override
115115
public void cleanSubject(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) {
116+
OpenIdStorageHandler.withDefinition(getDefinition(), () -> {
117+
cleanSubjectWithSelectedDefinition(request, response, httpMessageContext);
118+
return null;
119+
});
120+
}
121+
122+
private void cleanSubjectWithSelectedDefinition(final HttpServletRequest request, final HttpServletResponse response,
123+
final HttpMessageContext httpMessageContext) {
116124
String redirectTarget = buildRedirectUri();
117125

118126
HttpSession session = request.getSession(false);
@@ -153,6 +161,13 @@ private String buildRedirectUri()
153161

154162
@Override
155163
public AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthenticationException {
164+
return OpenIdStorageHandler.withDefinition(getDefinition(),
165+
() -> validateRequestWithSelectedDefinition(request, response, httpMessageContext));
166+
}
167+
168+
private AuthenticationStatus validateRequestWithSelectedDefinition(final HttpServletRequest request,
169+
final HttpServletResponse response,
170+
final HttpMessageContext httpMessageContext) {
156171
if (request.getUserPrincipal() != null) {
157172
AuthenticationStatus result = handleExpiredTokens(request, response, httpMessageContext);
158173
if (result != null) {

tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/TomEESecurityExtension.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@
2727
import org.apache.tomee.security.cdi.openid.OpenIdIdentityStore;
2828
import org.apache.tomee.security.cdi.openid.TomEEOpenIdContext;
2929
import org.apache.tomee.security.cdi.openid.storage.OpenIdStorageHandler;
30-
import org.apache.tomee.security.cdi.openid.storage.impl.CookieBasedOpenIdStorageHandler;
31-
import org.apache.tomee.security.cdi.openid.storage.impl.SessionBasedOpenIdStorageHandler;
30+
import org.apache.tomee.security.cdi.openid.storage.impl.DefinitionAwareOpenIdStorageHandler;
3231
import org.apache.tomee.security.http.openid.OpenIdAuthenticationMechanismDefinitionDelegate;
3332
import org.apache.tomee.security.identitystore.TomEEDatabaseIdentityStore;
3433
import org.apache.tomee.security.identitystore.TomEEDefaultIdentityStore;
@@ -420,9 +419,7 @@ void registerAuthenticationMechanism(
420419
OpenIdAuthenticationMechanismDefinition definition = (OpenIdAuthenticationMechanismDefinition)
421420
beanManager.getReference(definitionBean, OpenIdAuthenticationMechanismDefinition.class, creationalContext);
422421

423-
return definition.useSession()
424-
? new SessionBasedOpenIdStorageHandler()
425-
: new CookieBasedOpenIdStorageHandler();
422+
return new DefinitionAwareOpenIdStorageHandler();
426423
});
427424

428425
afterBeanDiscovery.addBean(createBean(TomEEOpenIdContext.class, beanManager));

tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/openid/storage/OpenIdStorageHandler.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,40 @@
1818

1919
import org.apache.commons.lang3.RandomStringUtils;
2020

21+
import jakarta.security.enterprise.authentication.mechanism.http.OpenIdAuthenticationMechanismDefinition;
2122
import jakarta.servlet.http.HttpServletRequest;
2223
import jakarta.servlet.http.HttpServletResponse;
24+
import java.util.function.Supplier;
2325

2426
public abstract class OpenIdStorageHandler {
2527
protected static final String PREFIX = "openid.";
2628

2729
public static final String REQUEST_KEY = "REQUEST";
2830
public static final String STATE_KEY = "STATE";
2931
public static final String NONCE_KEY = "NONCE";
32+
private static final ThreadLocal<OpenIdAuthenticationMechanismDefinition> CURRENT_DEFINITION = new ThreadLocal<>();
33+
34+
public static <T> T withDefinition(final OpenIdAuthenticationMechanismDefinition definition, final Supplier<T> task) {
35+
final OpenIdAuthenticationMechanismDefinition previous = CURRENT_DEFINITION.get();
36+
if (definition == null) {
37+
CURRENT_DEFINITION.remove();
38+
} else {
39+
CURRENT_DEFINITION.set(definition);
40+
}
41+
try {
42+
return task.get();
43+
} finally {
44+
if (previous == null) {
45+
CURRENT_DEFINITION.remove();
46+
} else {
47+
CURRENT_DEFINITION.set(previous);
48+
}
49+
}
50+
}
51+
52+
protected static OpenIdAuthenticationMechanismDefinition currentDefinition() {
53+
return CURRENT_DEFINITION.get();
54+
}
3055

3156
public abstract String get(HttpServletRequest request, HttpServletResponse response, String key);
3257

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.tomee.security.cdi.openid.storage.impl;
18+
19+
import jakarta.security.enterprise.authentication.mechanism.http.OpenIdAuthenticationMechanismDefinition;
20+
import jakarta.servlet.http.HttpServletRequest;
21+
import jakarta.servlet.http.HttpServletResponse;
22+
import org.apache.tomee.security.cdi.openid.storage.OpenIdStorageHandler;
23+
24+
public class DefinitionAwareOpenIdStorageHandler extends OpenIdStorageHandler {
25+
private final OpenIdStorageHandler session = new SessionBasedOpenIdStorageHandler();
26+
private final OpenIdStorageHandler cookie = new CookieBasedOpenIdStorageHandler();
27+
28+
@Override
29+
public String get(final HttpServletRequest request, final HttpServletResponse response, final String key) {
30+
return delegate().get(request, response, key);
31+
}
32+
33+
@Override
34+
public void set(final HttpServletRequest request, final HttpServletResponse response, final String key, final String value) {
35+
delegate().set(request, response, key, value);
36+
}
37+
38+
@Override
39+
public void delete(final HttpServletRequest request, final HttpServletResponse response, final String key) {
40+
delegate().delete(request, response, key);
41+
}
42+
43+
private OpenIdStorageHandler delegate() {
44+
final OpenIdAuthenticationMechanismDefinition definition = currentDefinition();
45+
if (definition == null) {
46+
throw new IllegalStateException("OpenID storage access requires the selected OpenIdAuthenticationMechanismDefinition");
47+
}
48+
return definition.useSession() ? session : cookie;
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.tomee.security.cdi.openid.storage.impl;
18+
19+
import jakarta.security.enterprise.authentication.mechanism.http.OpenIdAuthenticationMechanismDefinition;
20+
import jakarta.servlet.http.Cookie;
21+
import jakarta.servlet.http.HttpServletRequest;
22+
import jakarta.servlet.http.HttpServletResponse;
23+
import jakarta.servlet.http.HttpSession;
24+
import org.apache.tomee.security.cdi.openid.storage.OpenIdStorageHandler;
25+
import org.junit.Test;
26+
27+
import static org.mockito.ArgumentMatchers.any;
28+
import static org.mockito.ArgumentMatchers.eq;
29+
import static org.mockito.Mockito.mock;
30+
import static org.mockito.Mockito.never;
31+
import static org.mockito.Mockito.verify;
32+
import static org.mockito.Mockito.when;
33+
34+
public class DefinitionAwareOpenIdStorageHandlerTest {
35+
@Test
36+
public void usesCurrentDefinitionSessionStorage() {
37+
final DefinitionAwareOpenIdStorageHandler handler = new DefinitionAwareOpenIdStorageHandler();
38+
final OpenIdAuthenticationMechanismDefinition definition = mock(OpenIdAuthenticationMechanismDefinition.class);
39+
final HttpServletRequest request = mock(HttpServletRequest.class);
40+
final HttpServletResponse response = mock(HttpServletResponse.class);
41+
final HttpSession session = mock(HttpSession.class);
42+
43+
when(definition.useSession()).thenReturn(true);
44+
when(request.getSession()).thenReturn(session);
45+
46+
OpenIdStorageHandler.withDefinition(definition, () -> {
47+
handler.set(request, response, OpenIdStorageHandler.STATE_KEY, "state");
48+
return null;
49+
});
50+
51+
verify(session).setAttribute("openid.STATE", "state");
52+
verify(response, never()).addCookie(any(Cookie.class));
53+
}
54+
55+
@Test
56+
public void usesCurrentDefinitionCookieStorage() {
57+
final DefinitionAwareOpenIdStorageHandler handler = new DefinitionAwareOpenIdStorageHandler();
58+
final OpenIdAuthenticationMechanismDefinition definition = mock(OpenIdAuthenticationMechanismDefinition.class);
59+
final HttpServletRequest request = mock(HttpServletRequest.class);
60+
final HttpServletResponse response = mock(HttpServletResponse.class);
61+
final HttpSession session = mock(HttpSession.class);
62+
63+
when(definition.useSession()).thenReturn(false);
64+
when(request.getSession()).thenReturn(session);
65+
66+
OpenIdStorageHandler.withDefinition(definition, () -> {
67+
handler.set(request, response, OpenIdStorageHandler.STATE_KEY, "state");
68+
return null;
69+
});
70+
71+
verify(response).addCookie(any(Cookie.class));
72+
verify(session, never()).setAttribute(eq("openid.STATE"), eq("state"));
73+
}
74+
75+
@Test(expected = IllegalStateException.class)
76+
public void failsWithoutSelectedDefinition() {
77+
final DefinitionAwareOpenIdStorageHandler handler = new DefinitionAwareOpenIdStorageHandler();
78+
final HttpServletRequest request = mock(HttpServletRequest.class);
79+
final HttpServletResponse response = mock(HttpServletResponse.class);
80+
81+
handler.set(request, response, OpenIdStorageHandler.STATE_KEY, "state");
82+
}
83+
}

0 commit comments

Comments
 (0)