Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix login broken by insufficient tokenId checking #175

Merged
merged 2 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -416,20 +410,8 @@ public Collection<String> getAllServerIds() {
)
})
public Promise<ActionResponse, ResourceException> 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);
Expand All @@ -439,31 +421,6 @@ public Promise<ActionResponse, ResourceException> 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<String> 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<String> 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:
* <ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,35 @@
* 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;
import com.iplanet.sso.SSOToken;
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;
Expand Down Expand Up @@ -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:
* <ol>
* <li>Path of the request</li>
* <li>URL parameters of the request</li>
* <li>Cookies</li>
* <li>HTTP headers</li>
* </ol>
* 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<String> 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<String> 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.
Expand Down Expand Up @@ -124,7 +192,7 @@ public Collection<String> getAllServerIds() {
* @return A non null collection of SessionInfos from the named server.
*/
public Collection<SessionInfo> generateNamedServerSession(String serverId) {
List<String> serverList = Arrays.asList(new String[]{serverId});
List<String> serverList = List.of(serverId);
Collection<SessionInfo> sessions = queryManager.getAllSessions(serverList);
if (LOGGER.messageEnabled()) {
LOGGER.message("SessionResource.generateNmaedServerSession :: retrieved session list for server, " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<String, ActionHandler> actionHandlers;
private final SessionResourceUtil sessionResourceUtil;
private final SessionService sessionService;

/**
Expand All @@ -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,
Expand Down Expand Up @@ -265,19 +257,8 @@ public SessionResourceV2(final SSOTokenManager ssoTokenManager, AuthUtilsWrapper
})
@Override
public Promise<ActionResponse, ResourceException> 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);
Expand All @@ -287,31 +268,6 @@ public Promise<ActionResponse, ResourceException> 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<String> 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<String> 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.
Expand Down
Loading
Loading