diff --git a/oxd-common/src/main/java/org/gluu/oxd/common/ErrorResponseCode.java b/oxd-common/src/main/java/org/gluu/oxd/common/ErrorResponseCode.java index c8a17bbb0..45c4066fc 100644 --- a/oxd-common/src/main/java/org/gluu/oxd/common/ErrorResponseCode.java +++ b/oxd-common/src/main/java/org/gluu/oxd/common/ErrorResponseCode.java @@ -92,7 +92,9 @@ public enum ErrorResponseCode { KEY_ID_NOT_FOUND(500, "key_id_not_found", "`kid` is missing in `ID_TOKEN`. Unable to find matching key out of the Issuer's published set."), NO_SUBJECT_IDENTIFIER(500, "no_subject_identifier", "ID Token is missing `sub` value."), ID_TOKEN_WITHOUT_SIGNATURE_NOT_ALLOWED(400, "id_token_without_signature_not_allowed", "`ID_TOKEN` without signature is not allowed. To allow `ID_TOKEN` without signature set `accept_id_token_without_signature` field to 'true' in oxd-server.yml."), - INVALID_ID_TOKEN_ISSUED_AT(500, "invalid_id_token_issued_at", "`ISSUED_AT` date is either invalid or missing from `ID_TOKEN`."); + INVALID_ID_TOKEN_ISSUED_AT(500, "invalid_id_token_issued_at", "`ISSUED_AT` date is either invalid or missing from `ID_TOKEN`."), + INVALID_SUBJECT_IDENTIFIER(500, "invalid_subject_identifier", "UserInfo `sub` value does not matches with `sub` value of ID_TOKEN."), + FAILED_TO_VERIFY_SUBJECT_IDENTIFIER(500, "failed_to_verify_subject_identifier", "Failed to verify subject identifier (`sub`) of UserInfo response. See oxd-server logs for details."); private final int httpStatus; private final String code; diff --git a/oxd-server/src/main/java/org/gluu/oxd/server/op/GetUserInfoOperation.java b/oxd-server/src/main/java/org/gluu/oxd/server/op/GetUserInfoOperation.java index 0f25a7fb9..b09f934b5 100644 --- a/oxd-server/src/main/java/org/gluu/oxd/server/op/GetUserInfoOperation.java +++ b/oxd-server/src/main/java/org/gluu/oxd/server/op/GetUserInfoOperation.java @@ -4,11 +4,18 @@ import org.gluu.oxauth.client.UserInfoClient; import org.gluu.oxauth.client.UserInfoRequest; import org.gluu.oxauth.client.UserInfoResponse; +import org.gluu.oxauth.model.jwt.Jwt; +import org.gluu.oxauth.model.jwt.JwtClaimName; import org.gluu.oxd.common.Command; +import org.gluu.oxd.common.ErrorResponseCode; import org.gluu.oxd.common.Jackson2; import org.gluu.oxd.common.params.GetUserInfoParams; import org.gluu.oxd.common.response.IOpResponse; import org.gluu.oxd.common.response.POJOResponse; +import org.gluu.oxd.server.HttpException; +import org.gluu.oxd.server.service.Rp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; @@ -19,7 +26,7 @@ public class GetUserInfoOperation extends BaseOperation { -// private static final Logger LOG = LoggerFactory.getLogger(GetUserInfoOperation.class); + private static final Logger LOG = LoggerFactory.getLogger(GetUserInfoOperation.class); /** * Base constructor @@ -39,6 +46,27 @@ public IOpResponse execute(GetUserInfoParams params) throws IOException { client.setRequest(new UserInfoRequest(params.getAccessToken())); final UserInfoResponse response = client.exec(); + + final Rp rp = getRp(); + validateSubjectIdentifier(rp.getIdToken(), response); + + return new POJOResponse(Jackson2.createJsonMapper().readTree(response.getEntity())); } + + public void validateSubjectIdentifier(String idToken, UserInfoResponse response) { + try { + String subjectIdentifier = response.getClaims().get("sub").get(0); + final Jwt jwtIdToken = Jwt.parse(idToken); + if (!jwtIdToken.getClaims().getClaimAsString(JwtClaimName.SUBJECT_IDENTIFIER).equals(subjectIdentifier)) { + LOG.error("UserInfo `sub` value does not matches with `sub` value of ID_TOKEN."); + throw new HttpException(ErrorResponseCode.INVALID_SUBJECT_IDENTIFIER); + } + } catch (HttpException e) { + throw e; + } catch (Exception e) { + LOG.error("Error in matching `sub` value of UserInfo with `sub` value of ID_TOKEN.", e); + throw new HttpException(ErrorResponseCode.FAILED_TO_VERIFY_SUBJECT_IDENTIFIER); + } + } }