diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/AuthenticatedActionsHandler.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/AuthenticatedActionsHandler.java index d754642db8..8197c38a92 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/AuthenticatedActionsHandler.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/AuthenticatedActionsHandler.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source. - * Copyright 2021 Red Hat, Inc., and individual contributors + * Copyright 2024 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/AuthenticationError.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/AuthenticationError.java index cc99a48d12..789e1f4b4d 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/AuthenticationError.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/AuthenticationError.java @@ -36,7 +36,9 @@ public enum Reason { INVALID_TOKEN, STALE_TOKEN, NO_AUTHORIZATION_HEADER, - NO_QUERY_PARAMETER_ACCESS_TOKEN + NO_QUERY_PARAMETER_ACCESS_TOKEN, + NO_SESSION_ID, + METHOD_NOT_ALLOWED } private Reason reason; diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/ElytronMessages.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/ElytronMessages.java index e836cc3b46..ce3d976dcd 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/ElytronMessages.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/ElytronMessages.java @@ -278,5 +278,12 @@ interface ElytronMessages extends BasicLogger { @Message(id = 23070, value = "Authentication request format must be one of the following: oauth2, request, request_uri.") RuntimeException invalidAuthenticationRequestFormat(); + + @Message(id = 23071, value = "%s is not a valid value for %s") + RuntimeException invalidLogoutPath(String pathValue, String pathName); + + @Message(id = 23072, value = "The end substring of %s: %s can not be identical to %s: %s") + RuntimeException invalidLogoutCallbackPath(String callbackPathTitle, String callbacPathkValue, + String logoutPathTitle, String logoutPathValue); } diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/LogoutHandler.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/LogoutHandler.java index 68ae38f7ac..cda713dc61 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/LogoutHandler.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/LogoutHandler.java @@ -29,6 +29,8 @@ import org.apache.http.client.utils.URIBuilder; import org.jose4j.jwt.JwtClaims; import org.wildfly.security.http.HttpConstants; +import org.wildfly.security.http.HttpScope; +import org.wildfly.security.http.Scope; import org.wildfly.security.http.oidc.OidcHttpFacade.Request; /** @@ -36,12 +38,13 @@ */ final class LogoutHandler { - private static final String POST_LOGOUT_REDIRECT_URI_PARAM = "post_logout_redirect_uri"; - private static final String ID_TOKEN_HINT_PARAM = "id_token_hint"; + public static final String POST_LOGOUT_REDIRECT_URI_PARAM = "post_logout_redirect_uri"; + public static final String ID_TOKEN_HINT_PARAM = "id_token_hint"; private static final String LOGOUT_TOKEN_PARAM = "logout_token"; private static final String LOGOUT_TOKEN_TYPE = "Logout"; - private static final String SID = "sid"; - private static final String ISS = "iss"; + private static final String CLIENT_ID_SID_SEPARATOR = "-"; + public static final String SID = "sid"; + public static final String ISS = "iss"; /** * A bounded map to store sessions marked for invalidation after receiving logout requests through the back-channel @@ -60,27 +63,24 @@ protected boolean removeEldestEntry(Map.Entry e }); boolean tryLogout(OidcHttpFacade facade) { + log.trace("tryLogout entered"); RefreshableOidcSecurityContext securityContext = getSecurityContext(facade); - if (securityContext == null) { // no active session + log.trace("tryLogout securityContext == null"); return false; } - if (isSessionMarkedForInvalidation(facade)) { - // session marked for invalidation, invalidate it - log.debug("Invalidating pending logout session"); - facade.getTokenStore().logout(false); - return true; - } - - if (isRpInitiatedLogoutUri(facade)) { + if (isRpInitiatedLogoutPath(facade)) { + log.trace("isRpInitiatedLogoutPath"); redirectEndSessionEndpoint(facade); return true; } - if (isLogoutCallbackUri(facade)) { + if (isLogoutCallbackPath(facade)) { + log.trace("isLogoutCallbackPath"); if (isFrontChannel(facade)) { + log.trace("isFrontChannel"); handleFrontChannelLogoutRequest(facade); return true; } else { @@ -89,50 +89,41 @@ boolean tryLogout(OidcHttpFacade facade) { facade.authenticationFailed(); } } - return false; } - boolean tryBackChannelLogout(OidcHttpFacade facade) { - if (isLogoutCallbackUri(facade)) { - if (isBackChannel(facade)) { - handleBackChannelLogoutRequest(facade); - return true; - } else { - // no active session, should have received a POST logout request - facade.getResponse().setStatus(HttpStatus.SC_METHOD_NOT_ALLOWED); - facade.authenticationFailed(); - } + boolean isSessionMarkedForInvalidation(OidcHttpFacade facade) { + HttpScope session = facade.getScope(Scope.SESSION); + if (session == null || ! session.exists()) return false; + RefreshableOidcSecurityContext securityContext = (RefreshableOidcSecurityContext) session.getAttachment(OidcSecurityContext.class.getName()); + if (securityContext == null) { + return false; } - return false; - } - - private boolean isSessionMarkedForInvalidation(OidcHttpFacade facade) { - RefreshableOidcSecurityContext securityContext = getSecurityContext(facade); IDToken idToken = securityContext.getIDToken(); if (idToken == null) { return false; } - - return sessionsMarkedForInvalidation.remove(idToken.getSid()) != null; + return sessionsMarkedForInvalidation.remove(getSessionKey(facade, idToken.getSid())) != null; } private void redirectEndSessionEndpoint(OidcHttpFacade facade) { RefreshableOidcSecurityContext securityContext = getSecurityContext(facade); OidcClientConfiguration clientConfiguration = securityContext.getOidcClientConfiguration(); + String logoutUri; try { URIBuilder redirectUriBuilder = new URIBuilder(clientConfiguration.getEndSessionEndpointUrl()) .addParameter(ID_TOKEN_HINT_PARAM, securityContext.getIDTokenString()); - String postLogoutUri = clientConfiguration.getPostLogoutUri(); - - if (postLogoutUri != null) { - redirectUriBuilder.addParameter(POST_LOGOUT_REDIRECT_URI_PARAM, getRedirectUri(facade) + postLogoutUri); + String postLogoutPath = clientConfiguration.getPostLogoutPath(); + if (postLogoutPath != null) { + redirectUriBuilder.addParameter(POST_LOGOUT_REDIRECT_URI_PARAM, + getRedirectUri(facade) + postLogoutPath); } logoutUri = redirectUriBuilder.build().toString(); + log.trace("redirectEndSessionEndpoint path: " + redirectUriBuilder.toString()); } catch (URISyntaxException e) { throw new RuntimeException(e); } @@ -142,6 +133,19 @@ private void redirectEndSessionEndpoint(OidcHttpFacade facade) { facade.getResponse().setHeader(HttpConstants.LOCATION, logoutUri); } + boolean tryBackChannelLogout(OidcHttpFacade facade) { + log.trace("tryBackChannelLogout entered"); + if (isLogoutCallbackPath(facade)) { + log.trace("isLogoutCallbackPath"); + if (isBackChannel(facade)) { + log.trace("isBackChannel"); + handleBackChannelLogoutRequest(facade); + return true; + } + } + return false; + } + private void handleBackChannelLogoutRequest(OidcHttpFacade facade) { String logoutToken = facade.getRequest().getFirstParam(LOGOUT_TOKEN_PARAM); TokenValidator tokenValidator = TokenValidator.builder(facade.getOidcClientConfiguration()) @@ -175,7 +179,11 @@ private void handleBackChannelLogoutRequest(OidcHttpFacade facade) { } log.debug("Marking session for invalidation during back-channel logout"); - sessionsMarkedForInvalidation.put(sessionId, facade.getOidcClientConfiguration()); + sessionsMarkedForInvalidation.put(getSessionKey(facade, sessionId), facade.getOidcClientConfiguration()); + } + + private String getSessionKey(OidcHttpFacade facade, String sessionId) { + return facade.getOidcClientConfiguration().getClientId() + CLIENT_ID_SID_SEPARATOR + sessionId; } private void handleFrontChannelLogoutRequest(OidcHttpFacade facade) { @@ -210,8 +218,7 @@ private String getRedirectUri(OidcHttpFacade facade) { if (uri.indexOf('?') != -1) { uri = uri.substring(0, uri.indexOf('?')); } - - int logoutPathIndex = uri.indexOf(getLogoutUri(facade)); + int logoutPathIndex = uri.indexOf(getLogoutPath(facade)); if (logoutPathIndex != -1) { uri = uri.substring(0, logoutPathIndex); @@ -220,14 +227,14 @@ private String getRedirectUri(OidcHttpFacade facade) { return uri; } - private boolean isLogoutCallbackUri(OidcHttpFacade facade) { + private boolean isLogoutCallbackPath(OidcHttpFacade facade) { String path = facade.getRequest().getRelativePath(); - return path.endsWith(getLogoutCallbackUri(facade)); + return path.endsWith(getLogoutCallbackPath(facade)); } - private boolean isRpInitiatedLogoutUri(OidcHttpFacade facade) { + private boolean isRpInitiatedLogoutPath(OidcHttpFacade facade) { String path = facade.getRequest().getRelativePath(); - return path.endsWith(getLogoutUri(facade)); + return path.endsWith(getLogoutPath(facade)); } private boolean isSessionRequiredOnLogout(OidcHttpFacade facade) { @@ -246,12 +253,11 @@ private RefreshableOidcSecurityContext getSecurityContext(OidcHttpFacade facade) return securityContext; } - private String getLogoutUri(OidcHttpFacade facade) { - return facade.getOidcClientConfiguration().getLogoutUrl(); + private String getLogoutPath(OidcHttpFacade facade) { + return facade.getOidcClientConfiguration().getLogoutPath(); } - - private String getLogoutCallbackUri(OidcHttpFacade facade) { - return facade.getOidcClientConfiguration().getLogoutCallbackUrl(); + private String getLogoutCallbackPath(OidcHttpFacade facade) { + return facade.getOidcClientConfiguration().getLogoutCallbackPath(); } private boolean isBackChannel(OidcHttpFacade facade) { diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/Oidc.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/Oidc.java index c6b38c9ef4..cbff772366 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/Oidc.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/Oidc.java @@ -173,6 +173,10 @@ public class Oidc { public static final String CONFIDENTIAL_PORT = "confidential-port"; public static final String ENABLE_BASIC_AUTH = "enable-basic-auth"; public static final String PROVIDER_URL = "provider-url"; + public static final String LOGOUT_PATH = "logout-path"; + public static final String LOGOUT_CALLBACK_PATH = "logout-callback-path"; + public static final String POST_LOGOUT_PATH = "post-logout-path"; + public static final String LOGOUT_SESSION_REQUIRED = "logout-session-required"; /** * Bearer token pattern. diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcAuthenticationMechanism.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcAuthenticationMechanism.java index 602cf23d3b..a33d6b261d 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcAuthenticationMechanism.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcAuthenticationMechanism.java @@ -42,6 +42,7 @@ final class OidcAuthenticationMechanism implements HttpServerAuthenticationMechanism { private static LogoutHandler logoutHandler = new LogoutHandler(); + private final Map properties; private final CallbackHandler callbackHandler; private final OidcClientContext oidcClientContext; @@ -59,6 +60,7 @@ public String getMechanismName() { @Override public void evaluateRequest(HttpServerRequest request) throws HttpAuthenticationException { + log.debug("evaluateRequest uri: " + request.getRequestURI().toString()); OidcClientContext oidcClientContext = getOidcClientContext(request); if (oidcClientContext == null) { log.debugf("Ignoring request for path [%s] from mechanism [%s]. No client configuration context found.", request.getRequestURI(), getMechanismName()); @@ -74,6 +76,11 @@ public void evaluateRequest(HttpServerRequest request) throws HttpAuthentication } RequestAuthenticator authenticator = createRequestAuthenticator(httpFacade, oidcClientConfiguration); + if (logoutHandler.isSessionMarkedForInvalidation(httpFacade)) { + // session marked for invalidation, invalidate it + log.debug("Invalidating pending logout session"); + httpFacade.getTokenStore().logout(false); + } httpFacade.getTokenStore().checkCurrentToken(); if ((oidcClientConfiguration.getAuthServerBaseUrl() != null && keycloakPreActions(httpFacade, oidcClientConfiguration)) || preflightCors(httpFacade, oidcClientConfiguration)) { @@ -84,7 +91,8 @@ public void evaluateRequest(HttpServerRequest request) throws HttpAuthentication AuthOutcome outcome = authenticator.authenticate(); if (AuthOutcome.AUTHENTICATED.equals(outcome)) { - if (new AuthenticatedActionsHandler(oidcClientConfiguration, httpFacade).handledRequest() || logoutHandler.tryLogout(httpFacade)) { + if (new AuthenticatedActionsHandler(oidcClientConfiguration, httpFacade).handledRequest() + || logoutHandler.tryLogout(httpFacade)) { httpFacade.authenticationInProgress(); } else { httpFacade.authenticationComplete(); diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfiguration.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfiguration.java index e7bc0943ec..0fc0334107 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfiguration.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfiguration.java @@ -143,14 +143,12 @@ public enum RelativeUrlsUsed { protected String requestObjectSigningKeyAlias; protected String requestObjectSigningKeyStoreType; protected JWKEncPublicKeyLocator encryptionPublicKeyLocator; + private boolean logoutSessionRequired = true; - private String postLogoutUri; - + private String postLogoutPath; private boolean sessionRequiredOnLogout = true; - - private String logoutUrl = "/logout"; - - private String logoutCallbackUrl = "/logout/callback"; + private String logoutPath = "/logout"; + private String logoutCallbackPath = "/logout/callback"; private int logoutSessionWaitingLimit = 100; @@ -338,6 +336,10 @@ public String getEndSessionEndpointUrl() { return endSessionEndpointUrl; } + public String getLogoutPath() { + return logoutPath; + } + public String getAccountUrl() { resolveUrls(); return accountUrl; @@ -702,14 +704,6 @@ public String getTokenSignatureAlgorithm() { return tokenSignatureAlgorithm; } - public void setPostLogoutUri(String postLogoutUri) { - this.postLogoutUri = postLogoutUri; - } - - public String getPostLogoutUri() { - return postLogoutUri; - } - public boolean isSessionRequiredOnLogout() { return sessionRequiredOnLogout; } @@ -718,21 +712,6 @@ public void setSessionRequiredOnLogout(boolean sessionRequiredOnLogout) { this.sessionRequiredOnLogout = sessionRequiredOnLogout; } - public String getLogoutUrl() { - return logoutUrl; - } - - public void setLogoutUrl(String logoutUrl) { - this.logoutUrl = logoutUrl; - } - - public String getLogoutCallbackUrl() { - return logoutCallbackUrl; - } - - public void setLogoutCallbackUrl(String logoutCallbackUrl) { - this.logoutCallbackUrl = logoutCallbackUrl; - } public int getLogoutSessionWaitingLimit() { return logoutSessionWaitingLimit; } @@ -828,4 +807,32 @@ public void setEncryptionPublicKeyLocator(JWKEncPublicKeyLocator publicKeySetExt public JWKEncPublicKeyLocator getEncryptionPublicKeyLocator() { return this.encryptionPublicKeyLocator; } + + public void setPostLogoutPath(String postLogoutPath) { + this.postLogoutPath = postLogoutPath; + } + + public String getPostLogoutPath() { + return postLogoutPath; + } + + public boolean isLogoutSessionRequired() { + return logoutSessionRequired; + } + + public void setLogoutSessionRequired(boolean logoutSessionRequired) { + this.logoutSessionRequired = logoutSessionRequired; + } + + public void setLogoutPath(String logoutPath) { + this.logoutPath = logoutPath; + } + + public String getLogoutCallbackPath() { + return logoutCallbackPath; + } + + public void setLogoutCallbackPath(String logoutCallbackPath) { + this.logoutCallbackPath = logoutCallbackPath; + } } diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfigurationBuilder.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfigurationBuilder.java index 43bebace9f..52d59e1381 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfigurationBuilder.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfigurationBuilder.java @@ -25,6 +25,10 @@ import static org.wildfly.security.http.oidc.Oidc.AuthenticationRequestFormat.REQUEST_URI; import static org.wildfly.security.http.oidc.Oidc.SSLRequired; import static org.wildfly.security.http.oidc.Oidc.TokenStore; +import static org.wildfly.security.http.oidc.Oidc.LOGOUT_PATH; +import static org.wildfly.security.http.oidc.Oidc.LOGOUT_CALLBACK_PATH; +import static org.wildfly.security.http.oidc.Oidc.POST_LOGOUT_PATH; +import static org.wildfly.security.http.oidc.Oidc.LOGOUT_SESSION_REQUIRED; import java.io.IOException; import java.io.InputStream; @@ -195,6 +199,49 @@ protected OidcClientConfiguration internalBuild(final OidcJsonConfiguration oidc oidcClientConfiguration.setTokenSignatureAlgorithm(oidcJsonConfiguration.getTokenSignatureAlgorithm()); + String tmpLogoutPath = System.getProperty(LOGOUT_PATH); + log.debug("sysProp LOGOUT_PATH: " + (tmpLogoutPath == null ? "NULL" : tmpLogoutPath)); + if (tmpLogoutPath != null) { + if (isValidPath(tmpLogoutPath)) { + oidcClientConfiguration.setLogoutPath(tmpLogoutPath); + } else { + throw log.invalidLogoutPath(tmpLogoutPath, LOGOUT_PATH); + } + } + + + String tmpLogoutCallbackPath = System.getProperty(LOGOUT_CALLBACK_PATH); + log.debug("sysProp LOGOUT_CALLBACK_PATH: " + (tmpLogoutCallbackPath == null ? "NULL" : tmpLogoutCallbackPath)); + if (tmpLogoutCallbackPath != null) { + if (isValidPath(tmpLogoutCallbackPath) + && !tmpLogoutCallbackPath.endsWith(oidcClientConfiguration.getLogoutPath())) { + oidcClientConfiguration.setLogoutCallbackPath(tmpLogoutCallbackPath); + } else { + if (!isValidPath(tmpLogoutCallbackPath)) { + throw log.invalidLogoutPath(tmpLogoutPath, LOGOUT_CALLBACK_PATH); + } else { + throw log.invalidLogoutCallbackPath(LOGOUT_CALLBACK_PATH, tmpLogoutCallbackPath, + LOGOUT_PATH, oidcClientConfiguration.getLogoutPath()); + } + } + } + + String tmpPostLogoutPath = System.getProperty(POST_LOGOUT_PATH); + log.debug("sysProp POST_LOGOUT_PATH: " + (tmpPostLogoutPath == null ? "NULL" : tmpPostLogoutPath)); + if (tmpPostLogoutPath != null) { + if (isValidPath(tmpPostLogoutPath)) { + oidcClientConfiguration.setPostLogoutPath(tmpPostLogoutPath); + } else { + throw log.invalidLogoutPath(tmpLogoutPath, POST_LOGOUT_PATH); + } + } + + String tmpLogoutSessionRequired = System.getProperty(LOGOUT_SESSION_REQUIRED); + if (tmpLogoutSessionRequired != null) { + oidcClientConfiguration.setLogoutSessionRequired( + Boolean.valueOf(tmpLogoutSessionRequired)); + } + return oidcClientConfiguration; } @@ -236,4 +283,11 @@ public static OidcClientConfiguration build(OidcJsonConfiguration oidcJsonConfig return new OidcClientConfigurationBuilder().internalBuild(oidcJsonConfiguration); } + private boolean isValidPath(String path) { + String tmpPath = path.trim(); + if (tmpPath.length() > 1 && tmpPath.startsWith("/")) { + return true; + } + return false; + } } diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcHttpFacade.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcHttpFacade.java index 1c6f03fa7a..45def472a8 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcHttpFacade.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcHttpFacade.java @@ -550,4 +550,21 @@ public String getPath() { return path; } } + + // rls debug only + public String rlsGetSessionIds() { + Collection sessions = request.getScopeIds(Scope.SESSION); + if (sessions == null) { + return "## OidcHttpFacade Scope.SESSION sessionIds is null."; + } else if (sessions.isEmpty()){ + return "Scope.SESSION sessionIds is empty."; + } + StringBuffer sb = new StringBuffer(); + sb.append("Scope.SESSION sessionIds: ["); + for (String s : sessions) { + sb.append(s + ", "); + } + sb.append("]\n"); + return sb.toString(); + } } diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcRequestAuthenticator.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcRequestAuthenticator.java index 5ef5c26122..0588c16568 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcRequestAuthenticator.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcRequestAuthenticator.java @@ -184,7 +184,6 @@ protected String getCode() { protected String getRedirectUri(String state) { String url = getRequestUrl(); log.debugf("callback uri: %s", url); - try { if (! facade.getRequest().isSecure() && deployment.getSSLRequired().isRequired(facade.getRequest().getRemoteAddr())) { int port = getSSLRedirectPort(); diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcSessionTokenStore.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcSessionTokenStore.java index cb6206177c..6762afc0f4 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcSessionTokenStore.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcSessionTokenStore.java @@ -45,21 +45,29 @@ public OidcSessionTokenStore(OidcHttpFacade httpFacade) { @Override public void checkCurrentToken() { HttpScope session = httpFacade.getScope(Scope.SESSION); - if (session == null || ! session.exists()) return; + if (session == null || ! session.exists()) { + return; + } RefreshableOidcSecurityContext securityContext = (RefreshableOidcSecurityContext) session.getAttachment(OidcSecurityContext.class.getName()); - if (securityContext == null) return; + if (securityContext == null) { + return; + } // just in case session got serialized if (securityContext.getOidcClientConfiguration() == null) { securityContext.setCurrentRequestInfo(httpFacade.getOidcClientConfiguration(), this); } - if (securityContext.isActive() && ! securityContext.getOidcClientConfiguration().isAlwaysRefreshToken()) return; + if (securityContext.isActive() && ! securityContext.getOidcClientConfiguration().isAlwaysRefreshToken()) { + return; + } // FYI: A refresh requires same scope, so same roles will be set. Otherwise, refresh will fail and token will // not be updated boolean success = securityContext.refreshToken(false); - if (success && securityContext.isActive()) return; + if (success && securityContext.isActive()) { + return; + } // Refresh failed, so user is already logged out from keycloak. Cleanup and expire our session session.setAttachment(OidcSecurityContext.class.getName(), null); @@ -132,7 +140,6 @@ public void saveAccountInfo(OidcAccount account) { } }); } - session.setAttachment(OidcAccount.class.getName(), account); session.setAttachment(OidcSecurityContext.class.getName(), account.getOidcSecurityContext()); diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/RequestAuthenticator.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/RequestAuthenticator.java index 87b18e0abe..f635b7e79a 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/RequestAuthenticator.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/RequestAuthenticator.java @@ -55,6 +55,7 @@ public RequestAuthenticator(OidcHttpFacade facade, OidcClientConfiguration deplo public AuthOutcome authenticate() { AuthOutcome authenticate = doAuthenticate(); if (AuthOutcome.AUTHENTICATED.equals(authenticate) && !facade.isAuthorized()) { + log.trace("## RequestAutenticator.authenticate AUTHENTICATED but NOT Autorized"); return AuthOutcome.FAILED; } return authenticate; diff --git a/http/oidc/src/test/java/org/wildfly/security/http/oidc/AbstractLogoutTest.java b/http/oidc/src/test/java/org/wildfly/security/http/oidc/AbstractLogoutTest.java index fc139a4a2b..85a270cfd8 100644 --- a/http/oidc/src/test/java/org/wildfly/security/http/oidc/AbstractLogoutTest.java +++ b/http/oidc/src/test/java/org/wildfly/security/http/oidc/AbstractLogoutTest.java @@ -7,15 +7,14 @@ * 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 + * 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. + * 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.wildfly.security.http.oidc; import static org.junit.Assert.assertNotNull; @@ -54,8 +53,6 @@ public abstract class AbstractLogoutTest extends OidcBaseTest { private ElytronDispatcher dispatcher; private OidcClientConfiguration clientConfig; - static boolean IS_BACK_CHANNEL_TEST = false; - static final String BACK_CHANNEL_LOGOUT_URL = "/logout/callback"; @BeforeClass public static void onBeforeClass() { @@ -76,11 +73,13 @@ public static void generalCleanup() { } @Before - public void onBefore() throws IOException { + public void onBefore() throws Exception { OidcBaseTest.client = new MockWebServer(); OidcBaseTest.client.start(new InetSocketAddress(0).getAddress(), CLIENT_PORT); configureDispatcher(); - RealmRepresentation realm = KeycloakConfiguration.getRealmRepresentation(TEST_REALM, CLIENT_ID, CLIENT_SECRET, CLIENT_HOST_NAME, CLIENT_PORT, CLIENT_APP, CONFIGURE_CLIENT_SCOPES); + RealmRepresentation realm = KeycloakConfiguration.getRealmRepresentation( + TEST_REALM, CLIENT_ID, CLIENT_SECRET, CLIENT_HOST_NAME, CLIENT_PORT, + CLIENT_APP, false); realm.setAccessTokenLifespan(100); realm.setSsoSessionMaxLifespan(100); @@ -164,7 +163,6 @@ public ElytronDispatcher(HttpServerAuthenticationMechanism mechanism, Dispatcher public MockResponse dispatch(RecordedRequest serverRequest) throws InterruptedException { if (beforeDispatcher != null) { MockResponse response = beforeDispatcher.dispatch(serverRequest); - if (response != null) { return response; } @@ -173,11 +171,7 @@ public MockResponse dispatch(RecordedRequest serverRequest) throws InterruptedEx MockResponse mockResponse = new MockResponse(); try { - if (IS_BACK_CHANNEL_TEST && serverRequest.getRequestUrl().toString().endsWith(BACK_CHANNEL_LOGOUT_URL)) { - currentRequest = new TestingHttpServerRequest(serverRequest, null); - } else { - currentRequest = new TestingHttpServerRequest(serverRequest, sessionScope); - } + currentRequest = new TestingHttpServerRequest(serverRequest, sessionScope); mechanism.evaluateRequest(currentRequest); @@ -232,7 +226,7 @@ protected void configureDispatcher(OidcClientConfiguration clientConfig, Dispatc } protected void assertUserNotAuthenticated() { - assertNull(getCurrentSession().getAttachment(OidcAccount.class.getName())); + assertNull(getCurrentSession()); } protected void assertUserAuthenticated() { diff --git a/http/oidc/src/test/java/org/wildfly/security/http/oidc/BackChannelLogoutTest.java b/http/oidc/src/test/java/org/wildfly/security/http/oidc/BackChannelLogoutTest.java index 8540209498..d39e5af418 100644 --- a/http/oidc/src/test/java/org/wildfly/security/http/oidc/BackChannelLogoutTest.java +++ b/http/oidc/src/test/java/org/wildfly/security/http/oidc/BackChannelLogoutTest.java @@ -29,25 +29,21 @@ import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebClient; import org.apache.http.HttpStatus; -import org.junit.BeforeClass; import org.junit.Test; import org.keycloak.representations.idm.ClientRepresentation; public class BackChannelLogoutTest extends AbstractLogoutTest { - @BeforeClass - public static void setUp() { - IS_BACK_CHANNEL_TEST = true; - } - @Override protected void doConfigureClient(ClientRepresentation client) { List redirectUris = client.getRedirectUris(); String redirectUri = redirectUris.get(0); + OidcClientConfiguration config = new OidcClientConfiguration(); client.setFrontchannelLogout(false); client.getAttributes().put("backchannel.logout.session.required", "true"); - client.getAttributes().put("backchannel.logout.url", rewriteHost(redirectUri) + BACK_CHANNEL_LOGOUT_URL); + client.getAttributes().put("backchannel.logout.url", rewriteHost(redirectUri) + + config.getLogoutCallbackPath()); } private static String rewriteHost(String redirectUri) { @@ -59,9 +55,10 @@ private static String rewriteHost(String redirectUri) { } @Test - public void testRPInitiatedLogout() throws Exception { + public void testBackChannelLogout() throws Exception { URI requestUri = new URI(getClientUrl()); WebClient webClient = getWebClient(); + webClient.getPage(getClientUrl()); TestingHttpServerResponse response = getCurrentResponse(); assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getStatusCode()); @@ -76,9 +73,7 @@ public void testRPInitiatedLogout() throws Exception { // logged out after finishing the redirections during frontchannel logout assertUserAuthenticated(); - webClient.getPage(getClientUrl() + "/logout"); - //assertUserAuthenticated(); - webClient.getPage(getClientUrl()); + webClient.getPage(getClientUrl() + getClientConfig().getLogoutPath()); assertUserNotAuthenticated(); } -} \ No newline at end of file +} diff --git a/http/oidc/src/test/java/org/wildfly/security/http/oidc/FrontChannelLogoutTest.java b/http/oidc/src/test/java/org/wildfly/security/http/oidc/FrontChannelLogoutTest.java index dd4ca58c74..ec4eeff3c5 100644 --- a/http/oidc/src/test/java/org/wildfly/security/http/oidc/FrontChannelLogoutTest.java +++ b/http/oidc/src/test/java/org/wildfly/security/http/oidc/FrontChannelLogoutTest.java @@ -49,8 +49,9 @@ protected void doConfigureClient(ClientRepresentation client) { client.setFrontchannelLogout(true); List redirectUris = client.getRedirectUris(); String redirectUri = redirectUris.get(0); - - client.getAttributes().put("frontchannel.logout.url", redirectUri + "/logout/callback"); + OidcClientConfiguration config = new OidcClientConfiguration(); + client.getAttributes().put("frontchannel.logout.url", redirectUri + + config.getLogoutCallbackPath()); } @Test @@ -71,14 +72,14 @@ public void testRPInitiatedLogout() throws Exception { // logged out after finishing the redirections during frontchannel logout assertUserAuthenticated(); - webClient.getPage(getClientUrl() + "/logout"); + webClient.getPage(getClientUrl() + getClientConfig().getLogoutPath()); assertUserNotAuthenticated(); } @Test public void testRPInitiatedLogoutWithPostLogoutUri() throws Exception { OidcClientConfiguration oidcClientConfiguration = getClientConfig(); - oidcClientConfiguration.setPostLogoutUri("/post-logout"); + oidcClientConfiguration.setPostLogoutPath("/post-logout"); configureDispatcher(oidcClientConfiguration, new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest request) { @@ -99,7 +100,7 @@ public MockResponse dispatch(RecordedRequest request) { assertTrue(page.getWebResponse().getContentAsString().contains("Welcome, authenticated user")); assertUserAuthenticated(); - HtmlPage continueLogout = webClient.getPage(getClientUrl() + "/logout"); + HtmlPage continueLogout = webClient.getPage(getClientUrl() + getClientConfig().getLogoutPath()); page = continueLogout.getElementById("continue").click(); assertUserNotAuthenticated(); assertTrue(page.getWebResponse().getContentAsString().contains("you are logged out from app")); @@ -124,4 +125,4 @@ public void testFrontChannelLogout() throws Exception { client.setDispatcher(new QueueDispatcher()); } } -} \ No newline at end of file +} diff --git a/http/oidc/src/test/java/org/wildfly/security/http/oidc/LogoutConfigurationOptionsTest.java b/http/oidc/src/test/java/org/wildfly/security/http/oidc/LogoutConfigurationOptionsTest.java new file mode 100644 index 0000000000..c6fb24cf75 --- /dev/null +++ b/http/oidc/src/test/java/org/wildfly/security/http/oidc/LogoutConfigurationOptionsTest.java @@ -0,0 +1,118 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2024 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed 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.wildfly.security.http.oidc; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/* + Verify that invalid logout config options values are flagged. + */ +public class LogoutConfigurationOptionsTest { + private OidcJsonConfiguration oidcJsonConfiguration; + + @Before + public void before() { + oidcJsonConfiguration = new OidcJsonConfiguration(); + // minimum required options + oidcJsonConfiguration.setRealm("realm"); + oidcJsonConfiguration.setResource("resource"); + oidcJsonConfiguration.setClientId("clientId"); + oidcJsonConfiguration.setAuthServerUrl("AuthServerUrl"); + } + + @After + public void after() { + System.clearProperty(Oidc.LOGOUT_PATH); + System.clearProperty(Oidc.LOGOUT_CALLBACK_PATH); + System.clearProperty(Oidc.POST_LOGOUT_PATH); + } + + @Test + public void testLogoutPath() { + + try { + System.setProperty(Oidc.LOGOUT_PATH, " "); + OidcClientConfigurationBuilder.build(oidcJsonConfiguration); + fail("Empty " +Oidc.LOGOUT_PATH+ " is invalid"); + } catch (Exception e) { + assertTrue(e.getMessage().endsWith(Oidc.LOGOUT_PATH)); + } + + try { + System.setProperty(Oidc.LOGOUT_PATH, "/"); + OidcClientConfigurationBuilder.build(oidcJsonConfiguration); + fail("/ in " +Oidc.LOGOUT_PATH+ " is invalid"); + } catch (Exception e) { + assertTrue(e.getMessage().endsWith(Oidc.LOGOUT_PATH)); + } + } + + @Test + public void testCallbackLogoutPath() { + + try { + System.setProperty(Oidc.LOGOUT_CALLBACK_PATH, " "); + OidcClientConfigurationBuilder.build(oidcJsonConfiguration); + fail("Empty " + Oidc.LOGOUT_CALLBACK_PATH + " is invalid"); + } catch (Exception e) { + assertTrue(e.getMessage().endsWith(Oidc.LOGOUT_CALLBACK_PATH)); + } + + try { + System.setProperty(Oidc.LOGOUT_CALLBACK_PATH, "/"); + OidcClientConfigurationBuilder.build(oidcJsonConfiguration); + fail("/ in " + Oidc.LOGOUT_CALLBACK_PATH + " is invalid"); + } catch (Exception e) { + assertTrue(e.getMessage().endsWith(Oidc.LOGOUT_CALLBACK_PATH)); + } + + try { + System.setProperty(Oidc.LOGOUT_PATH, "/mylogout"); + System.setProperty(Oidc.LOGOUT_CALLBACK_PATH, "/more/mylogout"); + OidcClientConfigurationBuilder.build(oidcJsonConfiguration); + fail("Identical paths is invalid"); + } catch (Exception e) { + assertTrue(e.getMessage().contains("ELY23072")); + } + } + + @Test + public void testPostLogoutPath() { + + try { + System.setProperty(Oidc.POST_LOGOUT_PATH, " "); + OidcClientConfigurationBuilder.build(oidcJsonConfiguration); + fail("Empty " +Oidc.POST_LOGOUT_PATH+ " is invalid"); + } catch (Exception e) { + assertTrue(e.getMessage().endsWith(Oidc.POST_LOGOUT_PATH)); + } + + try { + System.setProperty(Oidc.POST_LOGOUT_PATH, "/"); + OidcClientConfigurationBuilder.build(oidcJsonConfiguration); + fail("/ in " + Oidc.POST_LOGOUT_PATH + " is invalid"); + } catch (Exception e) { + assertTrue(e.getMessage().endsWith(Oidc.POST_LOGOUT_PATH)); + } + } +} diff --git a/http/oidc/src/test/java/org/wildfly/security/http/oidc/OidcBaseTest.java b/http/oidc/src/test/java/org/wildfly/security/http/oidc/OidcBaseTest.java index b8a14b0d98..4f1028f829 100644 --- a/http/oidc/src/test/java/org/wildfly/security/http/oidc/OidcBaseTest.java +++ b/http/oidc/src/test/java/org/wildfly/security/http/oidc/OidcBaseTest.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source. - * Copyright 2022 Red Hat, Inc., and individual contributors + * Copyright 2024 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -212,7 +212,7 @@ public MockResponse dispatch(RecordedRequest recordedRequest) throws Interrupted } protected static Dispatcher createAppResponse(HttpServerAuthenticationMechanism mechanism, int expectedStatusCode, String expectedLocation, String clientPageText, - Map attachments) { + Map sessionScopeAttachments) { return new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest recordedRequest) throws InterruptedException { @@ -225,8 +225,8 @@ public MockResponse dispatch(RecordedRequest recordedRequest) throws Interrupted TestingHttpServerResponse response = request.getResponse(); assertEquals(expectedStatusCode, response.getStatusCode()); assertEquals(expectedLocation, response.getLocation()); - for (String key : request.getAttachments().keySet()) { - attachments.put(key, request.getAttachments().get(key)); + for (String key : request.getSessionScopeAttachments().keySet()) { + sessionScopeAttachments.put(key, request.getSessionScopeAttachments().get(key)); } return new MockResponse().setBody(clientPageText); } catch (Exception e) { @@ -240,7 +240,7 @@ public MockResponse dispatch(RecordedRequest recordedRequest) throws Interrupted } protected static Dispatcher createAppResponse(HttpServerAuthenticationMechanism mechanism, String clientPageText, - Map attachments, String tenant, boolean sameTenant) { + Map sessionScopeAttachments, String tenant, boolean sameTenant) { return new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest recordedRequest) throws InterruptedException { @@ -248,7 +248,7 @@ public MockResponse dispatch(RecordedRequest recordedRequest) throws Interrupted if (path.contains("/" + CLIENT_APP + "/" + tenant)) { try { TestingHttpServerRequest request = new TestingHttpServerRequest(new String[0], - new URI(recordedRequest.getRequestUrl().toString()), attachments); + new URI(recordedRequest.getRequestUrl().toString()), sessionScopeAttachments); mechanism.evaluateRequest(request); TestingHttpServerResponse response = request.getResponse(); if (sameTenant) { @@ -279,6 +279,7 @@ static WebClient getWebClient() { WebClient webClient = new WebClient(); webClient.setCssErrorHandler(new SilentCssErrorHandler()); webClient.setJavaScriptErrorListener(new SilentJavaScriptErrorListener()); + webClient.getOptions().setMaxInMemory(50000 * 1024); return webClient; } diff --git a/tests/base/src/test/java/org/wildfly/security/http/impl/AbstractBaseHttpTest.java b/tests/base/src/test/java/org/wildfly/security/http/impl/AbstractBaseHttpTest.java index 9fe171c921..0938a6297e 100644 --- a/tests/base/src/test/java/org/wildfly/security/http/impl/AbstractBaseHttpTest.java +++ b/tests/base/src/test/java/org/wildfly/security/http/impl/AbstractBaseHttpTest.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source. - * Copyright 2017 Red Hat, Inc., and individual contributors + * Copyright 2024 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,9 +27,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; -import java.net.MalformedURLException; import java.net.URI; -import java.net.URISyntaxException; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.security.cert.Certificate; @@ -157,10 +155,9 @@ protected static class TestingHttpServerRequest implements HttpServerRequest { private List cookies; private String requestMethod = "GET"; private Map> requestHeaders = new HashMap<>(); - private Map attachments = new HashMap<>(); - private Map scopes = new HashMap<>(); - private HttpScope sessionScope; private X500Principal testPrincipal = null; + private Map sessionScopeAttachments = new HashMap<>(); + private HttpScope sessionScope; public TestingHttpServerRequest(String[] authorization) { if (authorization != null) { @@ -188,14 +185,14 @@ public TestingHttpServerRequest(String[] authorization, URI requestURI) { this.cookies = new ArrayList<>(); } - public TestingHttpServerRequest(String[] authorization, URI requestURI, Map attachments) { + public TestingHttpServerRequest(String[] authorization, URI requestURI, Map sessionScopeAttachments) { if (authorization != null) { requestHeaders.put(AUTHORIZATION, Arrays.asList(authorization)); } this.remoteUser = null; this.requestURI = requestURI; this.cookies = new ArrayList<>(); - this.attachments = attachments; + this.sessionScopeAttachments = sessionScopeAttachments; } public TestingHttpServerRequest(String[] authorization, URI requestURI, List cookies) { @@ -216,10 +213,6 @@ public TestingHttpServerRequest(Map> requestHeaders, URI re } public TestingHttpServerRequest(String[] authorization, URI requestURI, String cookie) { - this(authorization, requestURI, cookie, null); - } - - public TestingHttpServerRequest(String[] authorization, URI requestURI, String cookie, HttpScope sessionScope) { if (authorization != null) { requestHeaders.put(AUTHORIZATION, Arrays.asList(authorization)); } @@ -231,14 +224,14 @@ public TestingHttpServerRequest(String[] authorization, URI requestURI, String c final String cookieValue = cookie.substring(cookie.indexOf('=') + 1); cookies.add(HttpServerCookie.getInstance(cookieName, cookieValue, null, -1, "/", false, 0, true)); } - this.sessionScope = sessionScope; } - public TestingHttpServerRequest(RecordedRequest serverRequest, HttpScope sessionScope) throws URISyntaxException { - this(new String[0], new URI(serverRequest.getRequestUrl().toString()), serverRequest.getHeader("Cookie"), sessionScope); - this.requestMethod = serverRequest.getMethod(); - this.body = serverRequest.getBody().readUtf8(); - this.contentType = serverRequest.getHeader("Content-Type"); + public TestingHttpServerRequest(RecordedRequest request, HttpScope sessionScope) { + this(new String[0], request.getRequestUrl().uri(), request.getHeader("Cookie")); + this.requestMethod = request.getMethod(); + this.body = request.getBody().readUtf8(); + this.contentType = request.getHeader("Content-Type"); + this.sessionScope = sessionScope; } public Status getResult() { @@ -312,11 +305,7 @@ public URI getRequestURI() { } public String getRequestPath() { - try { - return requestURI.toURL().getPath(); - } catch (MalformedURLException cause) { - throw new RuntimeException("Mal-formed request URL", cause); - } + return requestURI.getPath(); } public Map> getParameters() { @@ -369,54 +358,53 @@ public boolean resumeRequest() { } public HttpScope getScope(Scope scope) { - if (scope.equals(Scope.SSL_SESSION)) { + if (requestURI != null && "/clientApp/logout/callback".equals(requestURI.getPath())){ return null; } - - if (Scope.SESSION.equals(scope) && sessionScope != null) { + if (scope.equals(Scope.SSL_SESSION)) { + return null; + } else if (sessionScope != null) { return sessionScope; } - HttpScope httpScope = scopes.get(scope); - - if (httpScope == null) { - return new HttpScope() { + return new HttpScope() { - @Override - public boolean exists() { - return true; - } + @Override + public boolean exists() { + return true; + } - @Override - public boolean create() { - return false; - } + @Override + public boolean create() { + return false; + } - @Override - public boolean supportsAttachments() { - return true; - } + @Override + public boolean supportsAttachments() { + return true; + } - @Override - public boolean supportsInvalidation() { - return true; - } + @Override + public boolean supportsInvalidation() { + return false; + } - @Override - public void setAttachment(String key, Object value) { - attachments.put(key, value); + @Override + public void setAttachment(String key, Object value) { + if (scope.equals(Scope.SESSION)) { + sessionScopeAttachments.put(key, value); } + } - @Override - public Object getAttachment(String key) { - return attachments.get(key); + @Override + public Object getAttachment(String key) { + if (scope.equals(Scope.SESSION)) { + return sessionScopeAttachments.get(key); + } else { + return null; } - - }; - } - scopes.put(scope, httpScope); - - return httpScope; + } + }; } public Collection getScopeIds(Scope scope) { @@ -424,10 +412,7 @@ public Collection getScopeIds(Scope scope) { } public HttpScope getScope(Scope scope, String id) { - if (Scope.SESSION.equals(scope) && sessionScope != null) { - return sessionScope; - } - return scopes.get(scope); + throw new IllegalStateException(); } public void setRemoteUser(String remoteUser) { @@ -439,8 +424,8 @@ public String getRemoteUser() { return remoteUser; } - public Map getAttachments() { - return attachments; + public Map getSessionScopeAttachments() { + return sessionScopeAttachments; } }