Skip to content

Commit

Permalink
support getting caller and group information from multiple tokens- id…
Browse files Browse the repository at this point in the history
… token, access token, user info

address review comments

social - OidcLoginConfigImpl update

Fix the groupId / aud retrieval issue

configuration update

configuration update and add implementation to OidcLoginConfigImpl

Update to ignore the exception from finding userinfo and continue with the other 2 tokens

Update to use space instead of "," to fix the configuration issue
  • Loading branch information
onlinefw authored and arunavemulapalli committed Oct 25, 2023
1 parent 5703b1a commit 88c6bc8
Show file tree
Hide file tree
Showing 11 changed files with 486 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@
<Option label="%pkceCodeChallengeMethod.S256" value="S256" />
</AD>
<AD id="tokenRequestOriginHeader" name="%tokenRequestOriginHeader" description="%tokenRequestOriginHeader.desc" required="false" type="String" />
<AD id="tokenOrderToFetchCallerClaims" type="String" required="false" name="%tokenOrder" description="%tokenOrder.desc" default="IDToken" ibm:beta="true">
<Option label="%tokenOrder.one" value="IDToken" />
<Option label="%tokenOrder.two" value="AccessToken IDToken Userinfo" />
</AD>
</OCD>

<Designate factoryPid="com.ibm.ws.security.openidconnect.client.oidcClientConfig">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.net.ssl.SSLSocketFactory;

Expand Down Expand Up @@ -176,6 +177,7 @@ public class OidcClientConfigImpl implements OidcClientConfig {
public static final String CFG_KEY_ACCESS_TOKEN_CACHE_TIMEOUT = "accessTokenCacheTimeout";
public static final String CFG_KEY_PKCE_CODE_CHALLENGE_METHOD = "pkceCodeChallengeMethod";
public static final String CFG_KEY_TOKEN_REQUEST_ORIGIN_HEADER = "tokenRequestOriginHeader";
public static final String CFG_KEY_TOKEN_ORDER_TOFETCH_CALLER_CLAIMS = "tokenOrderToFetchCallerClaims";

public static final String OPDISCOVERY_AUTHZ_EP_URL = "authorization_endpoint";
public static final String OPDISCOVERY_TOKEN_EP_URL = "token_endpoint";
Expand Down Expand Up @@ -308,6 +310,8 @@ public class OidcClientConfigImpl implements OidcClientConfig {
private boolean useSystemPropertiesForHttpClientConnections = false;
private boolean tokenReuse = false;

private List<String> tokenOrderToFetchCallerClaims;

private final OidcSessionCache oidcSessionCache = new InMemoryOidcSessionCache();

// see defect 218708
Expand Down Expand Up @@ -563,6 +567,8 @@ private void processConfigProps(Map<String, Object> props) {

// validateAuthzTokenEndpoints(); //TODO: update tests to expect the error if the validation here fails

tokenOrderToFetchCallerClaims = split(trimIt((String) props.get(CFG_KEY_TOKEN_ORDER_TOFETCH_CALLER_CLAIMS)));

if (discovery) {
logDiscoveryMessage("OIDC_CLIENT_DISCOVERY_COMPLETE");
}
Expand Down Expand Up @@ -637,7 +643,9 @@ private void processConfigProps(Map<String, Object> props) {
Tr.debug(tc, "accessTokenCacheTimeout:" + accessTokenCacheTimeout);
Tr.debug(tc, "pkceCodeChallengeMethod:" + pkceCodeChallengeMethod);
Tr.debug(tc, "tokenRequestOriginHeader:" + tokenRequestOriginHeader);
Tr.debug(tc, "tokenOrderToFetchCallerClaims:" + tokenOrderToFetchCallerClaims);
}

}

private void initializeAccessTokenCache() {
Expand Down Expand Up @@ -1942,4 +1950,28 @@ public String getTokenRequestOriginHeader() {
return tokenRequestOriginHeader;
}

@Override
public List<String> getTokenOrderToFetchCallerClaims() {
return tokenOrderToFetchCallerClaims;
}

static List<String> split(String str) {
List<String> rvalue = new ArrayList<String>();
if (str != null) {
StringTokenizer st = new StringTokenizer(str, ", ");
while (st.hasMoreElements()) {
rvalue.add(st.nextToken());
}
}
return rvalue;
}

public static void main(String[] args) {
String str = "AccessToken, IDToken,Userinfo";
List<String> splitList = split(str);
for (String aStr : splitList) {
System.out.println(aStr);
}
}

}
6 changes: 5 additions & 1 deletion dev/com.ibm.ws.security.openidconnect.clients.common/bnd.bnd
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ Private-Package: \
com.ibm.ws.config;version=latest,\
io.openliberty.security.oidcclientcore.internal;version=latest,\
io.openliberty.security.common.jwt;version=latest,\
com.ibm.ws.security.oauth.2.0;version=latest
com.ibm.ws.security.oauth.2.0;version=latest,\
jakarta.security.enterprise-api,\
jakarta.security.enterprise-api,\
jakarta.security.enterprise-api,\
jakarta.security.enterprise-api

-testpath: \
../build.sharedResources/lib/junit/old/junit.jar;version=file,\
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -358,5 +358,4 @@ public AttributeToSubject(ConvergedClientConfig clientConfig, OidcTokenImplBase
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,18 @@ ProviderAuthenticationResult sendTokenRequestAndValidateResult(OidcClientRequest

oidcClientRequest.setTokenType(ClientConstants.TYPE_ID_TOKEN);

// ----------------------------------------------
// TODO: START: TICKET LIBERTY-i-70: to update to include userinfo in addition on to idToken, accessToken in createResultWithJose4J()
// but still need to update the authentication result to include it

// this has a LOT of dependencies.
ProviderAuthenticationResult oidcResult = jose4jUtil.createResultWithJose4J(responseState, tokens, clientConfig, oidcClientRequest);
ProviderAuthenticationResult oidcResult = jose4jUtil.createResultWithJose4J(responseState, tokens, clientConfig, oidcClientRequest, sslSocketFactory);

//go get the userinfo if configured to do so, and update the authentication result to include it.
new UserInfoHelper(clientConfig, sslSupport).getUserInfoIfPossible(oidcResult, tokens, sslSocketFactory, oidcClientRequest);
//new UserInfoHelper(clientConfig, sslSupport).getUserInfoIfPossible(oidcResult, tokens, sslSocketFactory, oidcClientRequest);

// TODO: END: TICKET LIBERTY-i-70: to update
// ----------------------------------------------

addAuthCodeToUsedList(authzCode);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-2.0/
*
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
Expand Down Expand Up @@ -48,4 +48,5 @@ public class Constants {
public static final String TOKEN_TYPE_ID_TOKEN = "IDToken";
public static final String TOKEN_TYPE_ACCESS_TOKEN = "AccessToken";
public static final String TOKEN_TYPE_JWT = "JsonWebToken";
public static final String TOKEN_TYPE_USER_INFO = "Userinfo"; // added t o support tokenOrderToFetchCallerClaims
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,5 @@ public interface ConvergedClientConfig extends JwtConsumerConfig {

public String getTokenRequestOriginHeader();

public List<String> getTokenOrderToFetchCallerClaims(); // tokenOrderToFetchCallerClaims
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-2.0/
*
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
Expand Down Expand Up @@ -232,11 +232,16 @@ ProviderAuthenticationResult handleImplicitFlowTokens(HttpServletRequest req,

oidcClientRequest.setTokenType(OidcClientRequest.TYPE_ID_TOKEN);

oidcResult = jose4jUtil.createResultWithJose4J(responseState, reqParameters, clientConfig, oidcClientRequest);
// ------------------------------------------------------
// TODO: START: ISSUE #25460
oidcResult = jose4jUtil.createResultWithJose4J(responseState, reqParameters, clientConfig, oidcClientRequest, getSSLSocketFactory(clientConfig));

if (clientConfig.getUserInfoEndpointUrl() != null) {
getUserInfo(clientConfig, reqParameters, oidcClientRequest, oidcResult);
}
// if (clientConfig.getUserInfoEndpointUrl() != null) {
// getUserInfo(clientConfig, reqParameters, oidcClientRequest, oidcResult);
// }

// TODO: END: ISSUE #25460
// ------------------------------------------------------

return oidcResult;
}
Expand All @@ -256,6 +261,25 @@ void getUserInfo(ConvergedClientConfig clientConfig, Hashtable<String, String> r
new UserInfoHelper(clientConfig, sslSupport).getUserInfoIfPossible(oidcResult, reqParameters, sslSocketFactory, oidcClientRequest);
}

// ------------------------------------------------------
// TODO: START: ISSUE #25460
SSLSocketFactory getSSLSocketFactory(ConvergedClientConfig clientConfig) {
SSLSocketFactory sslSocketFactory = null;
try {
sslSocketFactory = new OidcClientHttpUtil().getSSLSocketFactory(clientConfig.getSSLConfigurationName(), sslSupport);
} catch (com.ibm.websphere.ssl.SSLException e) {
Tr.error(tc, "OIDC_CLIENT_HTTPS_WITH_SSLCONTEXT_NULL", new Object[] { e, clientConfig.getClientId() });
} catch (NoSSLSocketFactoryException e) {
boolean needHttps = clientConfig.getUserInfoEndpointUrl().toLowerCase().startsWith("https");
if (needHttps) {
Tr.error(tc, "OIDC_CLIENT_HTTPS_WITH_SSLCONTEXT_NULL", new Object[] { "Null ssl socket factory", clientConfig.getClientId() });
}
}
return sslSocketFactory;
}
// TODO: END: ISSUE #25460
// ------------------------------------------------------

public static boolean checkHttpsRequirement(ConvergedClientConfig clientConfig, String urlStr) {
boolean metHttpsRequirement = true;
if (clientConfig.isHttpsRequired()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-2.0/
*
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
Expand Down Expand Up @@ -126,7 +126,8 @@ protected void updateAuthenticationResultPropertiesWithUserInfo(ProviderAuthenti
}

// per oidc-connect-core-1.0 sec 5.3.2, sub claim of userinfo response must match sub claim in id token.
protected boolean isUserInfoValid(String userInfoStr, String subClaim) {
// protected boolean isUserInfoValid(String userInfoStr, String subClaim) {
public boolean isUserInfoValid(String userInfoStr, String subClaim) {
String userInfoSubClaim = getUserInfoSubClaim(userInfoStr);
if (userInfoSubClaim == null || subClaim == null || userInfoSubClaim.compareTo(subClaim) != 0) {
Tr.error(tc, "USERINFO_INVALID", new Object[] { userInfoStr, subClaim });
Expand Down Expand Up @@ -254,4 +255,26 @@ String extractClaimsFromJwsResponse(String responseString, OidcClientConfig clie
return null;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
* get userinfo from provider's UserInfo Endpoint if configured and active.
*
* @return the user info
*
*/
public String getUserInfoIfPossible(String sub, String accessToken, SSLSocketFactory sslsf, OidcClientRequest oidcClientRequest) {
if (!willRetrieveUserInfo() || accessToken == null) {
return null;
}

if (sub != null) {
String userInfoStr = getUserInfoFromURL(clientConfig, sslsf, accessToken, oidcClientRequest);
if (userInfoStr != null) {
if (isUserInfoValid(userInfoStr, sub))
return userInfoStr;
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.net.ssl.SSLSocketFactory;

Expand Down Expand Up @@ -90,7 +91,7 @@ public class OidcLoginConfigImpl extends Oauth2LoginConfigImpl implements Conver
private String discoveryEndpointUrl = null;
private JSONObject discoveryjson = null;
private boolean discovery = false;

public static final String KEY_DISCOVERY_POLLING_RATE = "discoveryPollingRate";
private long discoveryPollingRate = 5 * 60 * 1000; // 5 minutes in milliseconds
private String discoveryDocumentHash = null;
Expand Down Expand Up @@ -142,6 +143,9 @@ public class OidcLoginConfigImpl extends Oauth2LoginConfigImpl implements Conver
private String tokenEndpointAuthSigningAlgorithm = null;
public static final String CFG_KEY_TOKEN_REQUEST_ORIGIN_HEADER = "tokenRequestOriginHeader";
private String tokenRequestOriginHeader = null;

public static final String CFG_KEY_TOKEN_ORDER_TOFETCH_CALLER_CLAIMS = "tokenOrderToFetchCallerClaims";
private List<String> tokenOrderToFetchCallerClaims;

HttpUtils httputils = new HttpUtils();
ConfigUtils oidcConfigUtils = new ConfigUtils(null);
Expand Down Expand Up @@ -982,4 +986,28 @@ public String getTokenRequestOriginHeader() {
return tokenRequestOriginHeader;
}

@Override
public List<String> getTokenOrderToFetchCallerClaims() {
return tokenOrderToFetchCallerClaims;
}

static List<String> split(String str) {
List<String> rvalue = new ArrayList<String>();
if (str != null) {
StringTokenizer st = new StringTokenizer(str, ", ");
while (st.hasMoreElements()) {
rvalue.add(st.nextToken());
}
}
return rvalue;
}

public static void main(String[] args) {
String str = "AccessToken, IDToken,Userinfo";
List<String> splitList = split(str);
for (String aStr : splitList) {
System.out.println(aStr);
}
}

}

0 comments on commit 88c6bc8

Please sign in to comment.