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

Ignore claims outside request object #2160

Merged
merged 14 commits into from
Oct 10, 2023
Merged
Changes from 1 commit
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 @@ -2479,6 +2479,13 @@ private void handleOIDCRequestObject(OAuthMessage oAuthMessage, OAuthAuthzReques
} else if (isRequestParameter(oauthRequest)) {
requestObjValue = oauthRequest.getParam(REQUEST);
}
// Mandate request object for FAPI requests
RivinduM marked this conversation as resolved.
Show resolved Hide resolved
janakamarasena marked this conversation as resolved.
Show resolved Hide resolved
if (isFapiConformant(oAuthMessage.getClientId())) {
if (StringUtils.isBlank(oauthRequest.getParam(REQUEST))) {
throw new InvalidRequestException("Request Object is mandatory for FAPI Conformant Applications.",
OAuth2ErrorCodes.INVALID_REQUEST, "Request object is missing.");
}
}

if (StringUtils.isNotEmpty(requestObjValue)) {
handleRequestObject(oAuthMessage, oauthRequest, parameters);
Expand Down Expand Up @@ -2524,8 +2531,10 @@ private void handleRequestObject(OAuthMessage oAuthMessage, OAuthAuthzRequest oa
When the request parameter is used, the OpenID Connect request parameter values contained in the JWT
supersede those passed using the OAuth 2.0 request syntax
*/
boolean isFapiConformant = isFapiConformant(oAuthMessage.getClientId());
// If FAPI conformant, claims outside request object should be ignored.
overrideAuthzParameters(oAuthMessage, parameters, oauthRequest.getParam(REQUEST),
oauthRequest.getParam(REQUEST_URI), requestObject);
oauthRequest.getParam(REQUEST_URI), requestObject, isFapiConformant);

// If the redirect uri was not given in auth request the registered redirect uri will be available here,
// so validating if the registered redirect uri is a single uri that can be properly redirected.
Expand All @@ -2548,17 +2557,18 @@ private void handleRequestObject(OAuthMessage oAuthMessage, OAuthAuthzRequest oa

private void overrideAuthzParameters(OAuthMessage oAuthMessage, OAuth2Parameters params,
String requestParameterValue,
String requestURIParameterValue, RequestObject requestObject) {
String requestURIParameterValue, RequestObject requestObject,
boolean ignoreClaimsOutsideRequestObject) {

if (StringUtils.isNotBlank(requestParameterValue) || StringUtils.isNotBlank(requestURIParameterValue)) {
replaceIfPresent(requestObject, REDIRECT_URI, params::setRedirectURI);
replaceIfPresent(requestObject, NONCE, params::setNonce);
replaceIfPresent(requestObject, STATE, params::setState);
replaceIfPresent(requestObject, DISPLAY, params::setDisplay);
replaceIfPresent(requestObject, RESPONSE_MODE, params::setResponseMode);
replaceIfPresent(requestObject, LOGIN_HINT, params::setLoginHint);
replaceIfPresent(requestObject, ID_TOKEN_HINT, params::setIDTokenHint);
replaceIfPresent(requestObject, PROMPT, params::setPrompt);
replaceIfPresent(requestObject, REDIRECT_URI, params::setRedirectURI, ignoreClaimsOutsideRequestObject);
replaceIfPresent(requestObject, NONCE, params::setNonce, ignoreClaimsOutsideRequestObject);
replaceIfPresent(requestObject, STATE, params::setState, ignoreClaimsOutsideRequestObject);
replaceIfPresent(requestObject, DISPLAY, params::setDisplay, ignoreClaimsOutsideRequestObject);
replaceIfPresent(requestObject, RESPONSE_MODE, params::setResponseMode, ignoreClaimsOutsideRequestObject);
replaceIfPresent(requestObject, LOGIN_HINT, params::setLoginHint, ignoreClaimsOutsideRequestObject);
replaceIfPresent(requestObject, ID_TOKEN_HINT, params::setIDTokenHint, ignoreClaimsOutsideRequestObject);
replaceIfPresent(requestObject, PROMPT, params::setPrompt, ignoreClaimsOutsideRequestObject);

if (requestObject.getClaim(CLAIMS) instanceof net.minidev.json.JSONObject) {
// Claims in the request object is in the type of net.minidev.json.JSONObject,
Expand All @@ -2570,8 +2580,10 @@ private void overrideAuthzParameters(OAuthMessage oAuthMessage, OAuth2Parameters
if (isPkceSupportEnabled()) {
// If code_challenge and code_challenge_method is sent inside the request object then add them to
// Oauth2 parameters.
replaceIfPresent(requestObject, CODE_CHALLENGE, params::setPkceCodeChallenge);
replaceIfPresent(requestObject, CODE_CHALLENGE_METHOD, params::setPkceCodeChallengeMethod);
replaceIfPresent(requestObject, CODE_CHALLENGE, params::setPkceCodeChallenge,
ignoreClaimsOutsideRequestObject);
replaceIfPresent(requestObject, CODE_CHALLENGE_METHOD, params::setPkceCodeChallengeMethod,
ignoreClaimsOutsideRequestObject);
}

if (StringUtils.isNotEmpty(requestObject.getClaimValue(SCOPE))) {
Expand Down Expand Up @@ -2635,11 +2647,14 @@ private List<String> getAcrValues(RequestObject requestObject) {
return acrRequestedValues;
}

private void replaceIfPresent(RequestObject requestObject, String claim, Consumer<String> consumer) {
private void replaceIfPresent(RequestObject requestObject, String claim, Consumer<String> consumer,
boolean ignoreClaimsOutsideRequestObject) {

String claimValue = requestObject.getClaimValue(claim);
if (StringUtils.isNotEmpty(claimValue)) {
consumer.accept(claimValue);
} else if (ignoreClaimsOutsideRequestObject) {
consumer.accept(null);
}
}

Expand Down Expand Up @@ -4069,15 +4084,17 @@ private OAuth2Parameters getOAuth2ParamsFromOAuthMessage(OAuthMessage oAuthMessa
* @param params OAuth2 Parameters
* @return PKCE code challenge. Priority will be given to the value inside the OAuth2Parameters.
*/
private String getPkceCodeChallenge(OAuthMessage oAuthMessage, OAuth2Parameters params) {
private String getPkceCodeChallenge(OAuthMessage oAuthMessage, OAuth2Parameters params)
throws InvalidRequestException {

String pkceChallengeCode;
String pkceChallengeCode = null;
boolean isFapiConformantApp = isFapiConformant(params.getClientId());
// If the code_challenge is in the request object, then it is added to Oauth2 params before this point.
if (params.getPkceCodeChallenge() != null) {
// If Oauth2 params contains code_challenge get value from Oauth2 params.
pkceChallengeCode = params.getPkceCodeChallenge();
} else {
// Else retrieve from request query params.
} else if (!isFapiConformantApp) {
RivinduM marked this conversation as resolved.
Show resolved Hide resolved
// Else retrieve from request query params if application is not FAPI compliant.
pkceChallengeCode = oAuthMessage.getOauthPKCECodeChallenge();
}

Expand All @@ -4093,15 +4110,17 @@ private String getPkceCodeChallenge(OAuthMessage oAuthMessage, OAuth2Parameters
* @param params OAuth2 Parameters
* @return PKCE code challenge method. Priority will be given to the value inside the OAuth2Parameters.
*/
private String getPkceCodeChallengeMethod(OAuthMessage oAuthMessage, OAuth2Parameters params) {
private String getPkceCodeChallengeMethod(OAuthMessage oAuthMessage, OAuth2Parameters params)
throws InvalidRequestException {

String pkceChallengeMethod;
String pkceChallengeMethod = null;
boolean isFapiConformantApp = isFapiConformant(params.getClientId());
// If the code_challenge_method is in the request object, then it is added to Oauth2 params before this point.
if (params.getPkceCodeChallengeMethod() != null) {
// If Oauth2 params contains code_challenge_method get value from Oauth2 params.
pkceChallengeMethod = params.getPkceCodeChallengeMethod();
} else {
// Else retrieve from request query params.
} else if (!isFapiConformantApp) {
// Else retrieve from request query params if application is not FAPI compliant.
pkceChallengeMethod = oAuthMessage.getOauthPKCECodeChallengeMethod();
}

Expand Down Expand Up @@ -4129,4 +4148,12 @@ private boolean isPromptSelectAccount(OAuth2Parameters oauth2Params) {

return OAuthConstants.Prompt.SELECT_ACCOUNT.equals(oauth2Params.getPrompt());
}

private boolean isFapiConformant(String clientId) throws InvalidRequestException {
try {
janakamarasena marked this conversation as resolved.
Show resolved Hide resolved
return OAuth2Util.isFapiConformantApp(clientId);
} catch (IdentityOAuth2Exception e) {
throw new InvalidRequestException(e.getMessage(), e.getErrorCode());
}
}
}