From 09909808389e5161012975488c182be38adbd3d3 Mon Sep 17 00:00:00 2001 From: Jan Fyrbach Date: Fri, 7 Jun 2024 00:17:48 +0200 Subject: [PATCH 1/2] Fix CREST action authorization The token ID can be retrieved from HTTP header or cookie for authorization verification of CREST action. This fixes an issue when requesting of the session info without token ID in URL was forbidden - requests ended with HTTP status 403. --- .../session/SessionResourceAuthzModule.java | 3 +- .../rest/session/SessionResourceUtil.java | 82 ++++++++++++-- .../rest/session/TokenOwnerAuthzModule.java | 16 +-- .../rest/session/SessionResourceUtilTest.java | 107 ++++++++++++++++++ .../session/TokenOwnerAuthzModuleTest.java | 31 ++--- 5 files changed, 204 insertions(+), 35 deletions(-) create mode 100644 openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/SessionResourceUtilTest.java diff --git a/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceAuthzModule.java b/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceAuthzModule.java index ae67658ff2..ec87ae1a27 100644 --- a/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceAuthzModule.java +++ b/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceAuthzModule.java @@ -12,6 +12,7 @@ * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2016 ForgeRock AS. + * Portions copyright 2024 Wren Security. */ package org.forgerock.openam.core.rest.session; @@ -39,7 +40,7 @@ public class SessionResourceAuthzModule extends TokenOwnerAuthzModule { @Inject public SessionResourceAuthzModule(SSOTokenManager ssoTokenManager) { - super("tokenId", ssoTokenManager, + super(ssoTokenManager, SessionResource.DELETE_PROPERTY_ACTION_ID, SessionResource.GET_PROPERTY_ACTION_ID, SessionResource.GET_PROPERTY_NAMES_ACTION_ID, SessionResource.SET_PROPERTY_ACTION_ID, SessionResource.GET_TIME_LEFT_ACTION_ID, SessionResource.GET_MAX_IDLE_ACTION_ID, diff --git a/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceUtil.java b/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceUtil.java index 48763ec33c..fa264829cd 100644 --- a/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceUtil.java +++ b/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceUtil.java @@ -12,18 +12,17 @@ * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2016 ForgeRock AS. + * Portions copyright 2024 Wren Security. */ package org.forgerock.openam.core.rest.session; -import static org.forgerock.json.JsonValue.*; - -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.TimeUnit; +import static org.forgerock.json.JsonValue.field; +import static org.forgerock.json.JsonValue.json; +import static org.forgerock.json.JsonValue.object; import com.google.inject.Inject; +import com.iplanet.am.util.SystemProperties; import com.iplanet.dpro.session.share.SessionInfo; import com.iplanet.services.naming.WebtopNamingQuery; import com.iplanet.sso.SSOException; @@ -31,9 +30,17 @@ import com.iplanet.sso.SSOTokenManager; import com.sun.identity.idm.AMIdentity; import com.sun.identity.idm.IdRepoException; +import com.sun.identity.shared.Constants; import com.sun.identity.shared.debug.Debug; import com.sun.identity.sm.DNMapper; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.forgerock.http.header.CookieHeader; +import org.forgerock.http.protocol.Cookie; import org.forgerock.json.JsonValue; +import org.forgerock.json.resource.Request; +import org.forgerock.json.resource.http.HttpContext; import org.forgerock.openam.core.rest.session.query.SessionQueryManager; import org.forgerock.openam.session.SessionConstants; import org.forgerock.openam.utils.StringUtils; @@ -76,6 +83,67 @@ public SessionResourceUtil(final SSOTokenManager ssoTokenManager, this.webtopNamingQuery = webtopNamingQuery; } + /** + * Retrieves the token ID from the given context and request. The method attempts to extract the token ID + * from various sources in the following order: + *
    + *
  1. Path of the request
  2. + *
  3. URL parameters of the request
  4. + *
  5. Cookies
  6. + *
  7. HTTP headers
  8. + *
+ * If the token ID is not found in any of these sources, the method returns {@code null}. + * + * @return The token ID if found; {@code null} otherwise. + */ + static String getTokenId(HttpContext context, Request request) { + String cookieName = SystemProperties.get(Constants.AM_COOKIE_NAME, "iPlanetDirectoryPro"); + + String tokenId = getTokenIdFromPath(request); + + if (StringUtils.isEmpty(tokenId)) { + tokenId = getTokenIdFromUrlParam(request); + } + + if (StringUtils.isEmpty(tokenId)) { + tokenId = getTokenIdFromCookie(context, cookieName); + } + + if (StringUtils.isEmpty(tokenId)) { + tokenId = getTokenIdFromHeader(context, cookieName); + } + + return StringUtils.isEmpty(tokenId) ? null : tokenId; + } + + private static String getTokenIdFromPath(Request request) { + return request.getResourcePath(); + } + + private static String getTokenIdFromUrlParam(Request request) { + return request.getAdditionalParameter("tokenId"); + } + + private static String getTokenIdFromCookie(HttpContext context, String cookieName) { + final List headers = context.getHeader("cookie"); + for (String header : headers) { + for (Cookie cookie : CookieHeader.valueOf(header).getCookies()) { + if (cookie.getName().equalsIgnoreCase(cookieName)) { + return cookie.getValue(); + } + } + } + return null; + } + + private static String getTokenIdFromHeader(HttpContext context, String headerName) { + final List header = context.getHeader(headerName); + if (!header.isEmpty()) { + return header.get(0); + } + return null; + } + /** * tokenId may, or may not, specify a valid token. If it does, retrieve it and the carefully refresh it so * as not to alter its idle time setting. If it does not exist, or is invalid, throw an SSOException. @@ -124,7 +192,7 @@ public Collection getAllServerIds() { * @return A non null collection of SessionInfos from the named server. */ public Collection generateNamedServerSession(String serverId) { - List serverList = Arrays.asList(new String[]{serverId}); + List serverList = List.of(serverId); Collection sessions = queryManager.getAllSessions(serverList); if (LOGGER.messageEnabled()) { LOGGER.message("SessionResource.generateNmaedServerSession :: retrieved session list for server, " + diff --git a/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/TokenOwnerAuthzModule.java b/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/TokenOwnerAuthzModule.java index 48c3f4f36a..65015797b5 100644 --- a/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/TokenOwnerAuthzModule.java +++ b/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/TokenOwnerAuthzModule.java @@ -12,6 +12,7 @@ * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2015-2016 ForgeRock AS. + * Portions copyright 2024 Wren Security. */ package org.forgerock.openam.core.rest.session; @@ -24,7 +25,6 @@ import com.iplanet.sso.SSOToken; import com.iplanet.sso.SSOTokenManager; import com.sun.identity.shared.Constants; -import org.apache.commons.lang.StringUtils; import org.forgerock.authz.filter.api.AuthorizationResult; import org.forgerock.authz.filter.crest.api.CrestAuthorizationModule; import org.forgerock.json.resource.ActionRequest; @@ -37,6 +37,7 @@ import org.forgerock.json.resource.Request; import org.forgerock.json.resource.ResourceException; import org.forgerock.json.resource.UpdateRequest; +import org.forgerock.json.resource.http.HttpContext; import org.forgerock.openam.rest.resource.SSOTokenContext; import org.forgerock.services.context.Context; import org.forgerock.util.Reject; @@ -64,23 +65,19 @@ public class TokenOwnerAuthzModule implements CrestAuthorizationModule { private final SSOTokenManager ssoTokenManager; private final Set allowedActions; - private final String tokenIdParameter; /** * Creates an authz module that will verify that a tokenId provided by the user (via query params) * is the same user (via universal identifier) as the user requesting the action. * - * @param tokenIdParameter The tokenId query parameter. May not be null. * @param ssoTokenManager An instance of the SSOTokenManager. * @param allowedActions A list of allowed actions. Will be matched ignoring case. */ - public TokenOwnerAuthzModule(String tokenIdParameter, SSOTokenManager ssoTokenManager, String... allowedActions) { + public TokenOwnerAuthzModule(SSOTokenManager ssoTokenManager, String... allowedActions) { Reject.ifNull(allowedActions); - Reject.ifTrue(StringUtils.isEmpty(tokenIdParameter)); this.ssoTokenManager = ssoTokenManager; this.allowedActions = new HashSet<>(Arrays.asList(allowedActions)); - this.tokenIdParameter = tokenIdParameter; } @Override @@ -136,12 +133,7 @@ public Promise authorizeQuery(Context co boolean isTokenOwner(Context context, Request request) throws ResourceException, SSOException { String loggedInUserId = getUserId(context); - - String tokenId = request.getResourcePath(); // infer from the token from resource path - if (StringUtils.isEmpty(tokenId)) { - //if there's no tokenId then is it supplied as additional parameter - tokenId = request.getAdditionalParameter(tokenIdParameter); - } + String tokenId = SessionResourceUtil.getTokenId(context.asContext(HttpContext.class), request); final String queryUsername = ssoTokenManager.createSSOToken(tokenId).getProperty(Constants.UNIVERSAL_IDENTIFIER); return queryUsername.equalsIgnoreCase(loggedInUserId); diff --git a/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/SessionResourceUtilTest.java b/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/SessionResourceUtilTest.java new file mode 100644 index 0000000000..baf19240ad --- /dev/null +++ b/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/SessionResourceUtilTest.java @@ -0,0 +1,107 @@ +/* + * The contents of this file are subject to the terms of the Common Development and + * Distribution License (the License). You may not use this file except in compliance with the + * License. + * + * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the + * specific language governing permission and limitations under the License. + * + * When distributing Covered Software, include this CDDL Header Notice in each file and include + * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL + * Header, with the fields enclosed by brackets [] replaced by your own identifying + * information: "Portions copyright [year] [name of copyright owner]". + * + * Copyright 2024 Wren Security. + */ + +package org.forgerock.openam.core.rest.session; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +import java.util.Collections; +import java.util.List; +import org.forgerock.json.resource.Request; +import org.forgerock.json.resource.http.HttpContext; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class SessionResourceUtilTest { + + private HttpContext context; + private Request request; + + @BeforeMethod + public void setUp() { + context = mock(HttpContext.class); + request = mock(Request.class); + } + + @Test + public void testGetTokenIdFromPath() { + when(request.getResourcePath()).thenReturn("tokenIdFromPath"); + + String tokenId = SessionResourceUtil.getTokenId(context, request); + + assertEquals(tokenId, "tokenIdFromPath"); + } + + @Test + public void testGetTokenIdFromUrlParam() { + when(request.getAdditionalParameter("tokenId")).thenReturn("tokenIdFromUrlParam"); + + String tokenId = SessionResourceUtil.getTokenId(context, request); + + assertEquals(tokenId, "tokenIdFromUrlParam"); + } + + @Test + public void testGetTokenIdFromCookie() { + when(context.getHeader("cookie")).thenReturn(List.of("iPlanetDirectoryPro=tokenIdFromCookie")); + + String tokenId = SessionResourceUtil.getTokenId(context, request); + + assertEquals(tokenId, "tokenIdFromCookie"); + } + + @Test + public void testGetTokenIdFromHeader() { + when(context.getHeader("iPlanetDirectoryPro")).thenReturn(Collections.singletonList("tokenIdFromHeader")); + + String tokenId = SessionResourceUtil.getTokenId(context, request); + + assertEquals(tokenId, "tokenIdFromHeader"); + } + + @Test + public void testGetTokenIdNotFound() { + String tokenId = SessionResourceUtil.getTokenId(context, request); + + assertNull(tokenId); + } + + @Test(dataProvider = "tokenDataProvider") + public void testGetTokenIdPreferredSource(String pathToken, String urlParamToken, String cookieToken, String headerToken, String expectedToken) { + when(request.getResourcePath()).thenReturn(pathToken); + when(request.getAdditionalParameter("tokenId")).thenReturn(urlParamToken); + when(context.getHeader("cookie")).thenReturn(Collections.singletonList("iPlanetDirectoryPro=" + cookieToken)); + when(context.getHeader("iPlanetDirectoryPro")).thenReturn(Collections.singletonList(headerToken)); + + String tokenId = SessionResourceUtil.getTokenId(context, request); + + assertEquals(tokenId, expectedToken); + } + + @DataProvider(name = "tokenDataProvider") + public String[][] tokenDataProvider() { + return new String[][] { + {"tokenIdFromPath", "tokenIdFromUrlParam", "tokenIdFromCookie", "tokenIdFromHeader", "tokenIdFromPath"}, + {"", "tokenIdFromUrlParam", "tokenIdFromCookie", "tokenIdFromHeader", "tokenIdFromUrlParam"}, + {"", "", "tokenIdFromCookie", "tokenIdFromHeader", "tokenIdFromCookie"}, + {"", "", "", "tokenIdFromHeader", "tokenIdFromHeader"} + }; + } +} diff --git a/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/TokenOwnerAuthzModuleTest.java b/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/TokenOwnerAuthzModuleTest.java index aba2dc1c72..ffa381deae 100644 --- a/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/TokenOwnerAuthzModuleTest.java +++ b/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/TokenOwnerAuthzModuleTest.java @@ -1,18 +1,19 @@ /* -* The contents of this file are subject to the terms of the Common Development and -* Distribution License (the License). You may not use this file except in compliance with the -* License. -* -* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the -* specific language governing permission and limitations under the License. -* -* When distributing Covered Software, include this CDDL Header Notice in each file and include -* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL -* Header, with the fields enclosed by brackets [] replaced by your own identifying -* information: "Portions copyright [year] [name of copyright owner]". -* -* Copyright 2015-2016 ForgeRock AS. -*/ + * The contents of this file are subject to the terms of the Common Development and + * Distribution License (the License). You may not use this file except in compliance with the + * License. + * + * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the + * specific language governing permission and limitations under the License. + * + * When distributing Covered Software, include this CDDL Header Notice in each file and include + * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL + * Header, with the fields enclosed by brackets [] replaced by your own identifying + * information: "Portions copyright [year] [name of copyright owner]". + * + * Copyright 2015-2016 ForgeRock AS. + * Portions copyright 2024 Wren Security. + */ package org.forgerock.openam.core.rest.session; import static org.forgerock.util.test.assertj.AssertJPromiseAssert.*; @@ -64,7 +65,7 @@ public void theSetUp() throws SSOException { given(mockConfig.get()).willReturn(mockService); mockContext = setupUser("universal_id"); - testModule = new TokenOwnerAuthzModule("tokenId", mockTokenManager, "deleteProperty"); + testModule = new TokenOwnerAuthzModule(mockTokenManager, "deleteProperty"); } @Test From 1eb243aa3888d3043702c1daa1f2452f1e64d561 Mon Sep 17 00:00:00 2001 From: Jan Fyrbach Date: Fri, 7 Jun 2024 09:15:35 +0200 Subject: [PATCH 2/2] Reduce duplicate code --- .../core/rest/session/SessionResource.java | 57 +++---------------- .../core/rest/session/SessionResourceV2.java | 48 +--------------- .../rest/session/SessionResourceTest.java | 51 +++++------------ 3 files changed, 23 insertions(+), 133 deletions(-) diff --git a/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResource.java b/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResource.java index 370401612a..1ac821bedb 100644 --- a/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResource.java +++ b/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResource.java @@ -12,6 +12,7 @@ * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2013-2016 ForgeRock AS. + * Portions copyright 2024 Wren Security. */ package org.forgerock.openam.core.rest.session; @@ -32,12 +33,14 @@ import static org.forgerock.openam.utils.Time.currentTimeMillis; import static org.forgerock.util.promise.Promises.newResultPromise; +import com.iplanet.dpro.session.share.SessionInfo; +import com.iplanet.services.naming.WebtopNaming; +import com.iplanet.sso.SSOTokenManager; +import com.sun.identity.common.CaseInsensitiveHashMap; +import com.sun.identity.shared.debug.Debug; import java.util.Collection; -import java.util.List; import java.util.Map; - import javax.inject.Inject; - import org.forgerock.api.annotations.Action; import org.forgerock.api.annotations.Actions; import org.forgerock.api.annotations.ApiError; @@ -49,7 +52,6 @@ import org.forgerock.api.annotations.Query; import org.forgerock.api.annotations.Schema; import org.forgerock.api.enums.QueryType; -import org.forgerock.http.header.CookieHeader; import org.forgerock.json.JsonValue; import org.forgerock.json.resource.ActionRequest; import org.forgerock.json.resource.ActionResponse; @@ -86,14 +88,6 @@ import org.forgerock.services.context.Context; import org.forgerock.util.promise.Promise; -import com.iplanet.am.util.SystemProperties; -import com.iplanet.dpro.session.share.SessionInfo; -import com.iplanet.services.naming.WebtopNaming; -import com.iplanet.sso.SSOTokenManager; -import com.sun.identity.common.CaseInsensitiveHashMap; -import com.sun.identity.shared.Constants; -import com.sun.identity.shared.debug.Debug; - /** * Represents Sessions that can queried via a REST interface. * @@ -416,20 +410,8 @@ public Collection getAllServerIds() { ) }) public Promise actionCollection(Context context, ActionRequest request) { - final String cookieName = SystemProperties.get(Constants.AM_COOKIE_NAME, "iPlanetDirectoryPro"); - - String tokenId = getTokenIdFromUrlParam(request); + String tokenId = SessionResourceUtil.getTokenId(context.asContext(HttpContext.class), request); - if (tokenId == null) { - tokenId = getTokenIdFromHeader(context, cookieName); - } - - if (tokenId == null) { - tokenId = getTokenIdFromCookie(context, cookieName); - } - - // Should any of these actions in the future be allowed to function without an SSO token, this - // code will have to be moved/changed. if (tokenId == null) { final BadRequestException e = new BadRequestException("iPlanetDirectoryCookie not set on request"); LOGGER.message("SessionResource.handleNullSSOToken :: iPlanetDirectoryCookie not set on request", e); @@ -439,31 +421,6 @@ public Promise actionCollection(Context conte return internalHandleAction(tokenId, context, request); } - protected String getTokenIdFromUrlParam(ActionRequest request) { - return request.getAdditionalParameter("tokenId"); - } - - protected String getTokenIdFromCookie(Context context, String cookieName) { - final List header = context.asContext(HttpContext.class).getHeader(cookieName.toLowerCase()); - if (!header.isEmpty()) { - return header.get(0); - } - return null; - } - - protected String getTokenIdFromHeader(Context context, String cookieName) { - final List headers = context.asContext(HttpContext.class).getHeader("cookie"); - - for (String header : headers) { - for (org.forgerock.http.protocol.Cookie cookie : CookieHeader.valueOf(header).getCookies()) { - if (cookie.getName().equalsIgnoreCase(cookieName)) { - return cookie.getValue(); - } - } - } - return null; - } - /** * Actions supported are: *
    diff --git a/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceV2.java b/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceV2.java index 26221628a4..8cf175b176 100644 --- a/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceV2.java +++ b/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/session/SessionResourceV2.java @@ -12,6 +12,7 @@ * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2016 ForgeRock AS. + * Portions copyright 2024 Wren Security. */ package org.forgerock.openam.core.rest.session; @@ -24,15 +25,12 @@ import javax.inject.Inject; import java.util.Collection; -import java.util.List; import java.util.Map; -import com.iplanet.am.util.SystemProperties; import com.iplanet.dpro.session.SessionException; import com.iplanet.dpro.session.service.SessionService; import com.iplanet.sso.SSOTokenManager; import com.sun.identity.common.CaseInsensitiveHashMap; -import com.sun.identity.shared.Constants; import com.sun.identity.shared.debug.Debug; import org.forgerock.api.annotations.Action; import org.forgerock.api.annotations.Actions; @@ -45,7 +43,6 @@ import org.forgerock.api.annotations.Schema; import org.forgerock.api.enums.ParameterSource; import org.forgerock.api.enums.QueryType; -import org.forgerock.http.header.CookieHeader; import org.forgerock.json.resource.ActionRequest; import org.forgerock.json.resource.ActionResponse; import org.forgerock.json.resource.BadRequestException; @@ -120,10 +117,7 @@ public class SessionResourceV2 implements CollectionResourceProvider { public static final String UPDATE_SESSION_PROPERTIES_ACTION_ID = "updateSessionProperties"; public static final String LOGOUT_BY_HANDLE_ACTION_ID = "logoutByHandle"; - private final SessionPropertyWhitelist sessionPropertyWhitelist; - private final Map actionHandlers; - private final SessionResourceUtil sessionResourceUtil; private final SessionService sessionService; /** @@ -138,8 +132,6 @@ public class SessionResourceV2 implements CollectionResourceProvider { public SessionResourceV2(final SSOTokenManager ssoTokenManager, AuthUtilsWrapper authUtilsWrapper, final SessionResourceUtil sessionResourceUtil, SessionPropertyWhitelist sessionPropertyWhitelist, SessionService sessionService, PartialSessionFactory partialSessionFactory) { - this.sessionResourceUtil = sessionResourceUtil; - this.sessionPropertyWhitelist = sessionPropertyWhitelist; this.sessionService = sessionService; actionHandlers = new CaseInsensitiveHashMap<>(); actionHandlers.put(REFRESH_ACTION_ID, @@ -265,19 +257,8 @@ public SessionResourceV2(final SSOTokenManager ssoTokenManager, AuthUtilsWrapper }) @Override public Promise actionCollection(Context context, ActionRequest request) { - final String cookieName = SystemProperties.get(Constants.AM_COOKIE_NAME, "iPlanetDirectoryPro"); - String tokenId = getTokenIdFromUrlParam(request); + String tokenId = SessionResourceUtil.getTokenId(context.asContext(HttpContext.class), request); - if (tokenId == null) { - tokenId = getTokenIdFromHeader(context, cookieName); - } - - if (tokenId == null) { - tokenId = getTokenIdFromCookie(context, cookieName); - } - - // Should any of these actions in the future be allowed to function without an SSO token, this - // code will have to be moved/changed. if (tokenId == null) { final BadRequestException e = new BadRequestException("iPlanetDirectoryCookie not set on request"); LOGGER.message("SessionResource.handleNullSSOToken :: iPlanetDirectoryCookie not set on request", e); @@ -287,31 +268,6 @@ public Promise actionCollection(Context conte return internalHandleAction(tokenId, context, request); } - protected String getTokenIdFromUrlParam(ActionRequest request) { - return request.getAdditionalParameter("tokenId"); - } - - protected String getTokenIdFromCookie(Context context, String cookieName) { - final List header = context.asContext(HttpContext.class).getHeader(cookieName.toLowerCase()); - if (!header.isEmpty()) { - return header.get(0); - } - return null; - } - - protected String getTokenIdFromHeader(Context context, String cookieName) { - final List headers = context.asContext(HttpContext.class).getHeader("cookie"); - - for (String header : headers) { - for (org.forgerock.http.protocol.Cookie cookie : CookieHeader.valueOf(header).getCookies()) { - if (cookie.getName().equalsIgnoreCase(cookieName)) { - return cookie.getValue(); - } - } - } - return null; - } - /** * Handle the action specified by the user (i.e. one of those in the validActions set). * @param tokenId The id of the token. diff --git a/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/SessionResourceTest.java b/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/SessionResourceTest.java index de84b404f5..915cb64d34 100644 --- a/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/SessionResourceTest.java +++ b/openam-core-rest/src/test/java/org/forgerock/openam/core/rest/session/SessionResourceTest.java @@ -12,7 +12,7 @@ * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2013-2015 ForgeRock AS. - * Portions Copyright 2021 Wren Security. + * Portions Copyright 2021-2024 Wren Security. */ package org.forgerock.openam.core.rest.session; @@ -70,6 +70,7 @@ import org.forgerock.json.resource.QueryRequest; import org.forgerock.json.resource.QueryResourceHandler; import org.forgerock.json.resource.ResourceException; +import org.forgerock.json.resource.http.HttpContext; import org.forgerock.openam.authentication.service.AuthUtilsWrapper; import org.forgerock.openam.core.realms.Realm; import org.forgerock.openam.core.realms.RealmTestHelper; @@ -82,7 +83,6 @@ import org.forgerock.services.context.AttributesContext; import org.forgerock.services.context.ClientContext; import org.forgerock.services.context.Context; -import org.forgerock.services.context.RootContext; import org.forgerock.services.context.SecurityContext; import org.forgerock.util.promise.Promise; import org.testng.annotations.AfterMethod; @@ -115,12 +115,6 @@ public class SessionResourceTest { private AMIdentity amIdentity; - private String headerResponse; - private String urlResponse; - private String cookieResponse; - - - @BeforeMethod public void setUp() throws Exception { SessionQueryManager sessionQueryManager = mock(SessionQueryManager.class); @@ -128,9 +122,6 @@ public void setUp() throws Exception { authUtilsWrapper = mock(AuthUtilsWrapper.class); propertyWhitelist = mock(SessionPropertyWhitelist.class); webtopNamingQuery = mock(WebtopNamingQuery.class); - headerResponse = null; - urlResponse = null; - cookieResponse = null; given(mockContext.getCallerSSOToken()).willReturn(ssoToken); @@ -164,25 +155,7 @@ public String convertDNToRealm(String dn) { } }); - sessionResource = new SessionResource(ssoTokenManager, authUtilsWrapper, - propertyWhitelist, sessionResourceUtil) { - - @Override - protected String getTokenIdFromHeader(Context context, String cookieName) { - return headerResponse; - } - - @Override - protected String getTokenIdFromUrlParam(ActionRequest request) { - return urlResponse; - } - - @Override - protected String getTokenIdFromCookie(Context context, String cookieName) { - return cookieResponse; - } - - }; + sessionResource = new SessionResource(ssoTokenManager, authUtilsWrapper, propertyWhitelist, sessionResourceUtil); } @AfterMethod @@ -251,10 +224,11 @@ public void shouldQueryNamedServerInServerMode() { @Test public void actionCollectionShouldFailToValidateSessionWhenSSOTokenIdNotSet() { //Given - final SSOTokenContext tokenContext = mock(SSOTokenContext.class); - final Context context = ClientContext.newInternalClientContext(tokenContext); + final HttpContext httpContext = mock(HttpContext.class); + final Context context = mock(ClientContext.class); final ActionRequest request = mock(ActionRequest.class); + given(context.asContext(HttpContext.class)).willReturn(httpContext); given(request.getAction()).willReturn(VALIDATE_ACTION_ID); //When @@ -267,13 +241,15 @@ public void actionCollectionShouldFailToValidateSessionWhenSSOTokenIdNotSet() { @Test public void actionCollectionShouldValidateSessionAndReturnTrueWhenSSOTokenValid() throws SSOException { //Given - cookieResponse = "SSO_TOKEN_ID"; final SSOTokenContext tokenContext = mock(SSOTokenContext.class); - final Context context = ClientContext.newInternalClientContext(tokenContext); + final HttpContext httpContext = mock(HttpContext.class); + final Context context = mock(ClientContext.class); final ActionRequest request = mock(ActionRequest.class); final SSOToken ssoToken = mock(SSOToken.class); final SSOTokenID ssoTokenId = mock(SSOTokenID.class); + given(context.asContext(HttpContext.class)).willReturn(httpContext); + given(httpContext.getHeader("cookie")).willReturn(List.of("iPlanetDirectoryPro=SSO_TOKEN_ID")); given(request.getAction()).willReturn(VALIDATE_ACTION_ID); given(tokenContext.getCallerSSOToken()).willReturn(ssoToken); given(ssoTokenManager.isValidToken(ssoToken)).willReturn(true); @@ -294,14 +270,15 @@ public void actionCollectionShouldValidateSessionAndReturnTrueWhenSSOTokenValid( @Test public void actionCollectionShouldLogoutSessionAndReturnEmptyJsonObjectWhenSSOTokenValid() throws SSOException { //Given - cookieResponse = "SSO_TOKEN_ID"; - final AttributesContext attrContext = new AttributesContext(new SessionContext(new RootContext(), mock(Session.class))); - final AdviceContext adviceContext = new AdviceContext(attrContext, Collections.emptySet()); + final HttpContext httpContext = mock(HttpContext.class); + final AttributesContext attrContext = new AttributesContext(new SessionContext(httpContext, mock(Session.class))); + final AdviceContext adviceContext = new AdviceContext(attrContext, Collections.emptySet()); final SecurityContext securityContext = new SecurityContext(adviceContext, null, null); final Context context = ClientContext.newInternalClientContext(new SSOTokenContext(mock(Debug.class), null, securityContext)); final ActionRequest request = mock(ActionRequest.class); final SSOTokenID ssoTokenId = mock(SSOTokenID.class); + given(request.getAdditionalParameter("tokenId")).willReturn("SSO_TOKEN_ID"); given(request.getAction()).willReturn(LOGOUT_ACTION_ID); given(authUtilsWrapper.logout(ssoTokenId.toString(), null, null)).willReturn(true);