Skip to content

Commit

Permalink
fix: do not run IDP Userinfo mapper for other than bcsc idps
Browse files Browse the repository at this point in the history
  • Loading branch information
NithinKuruba committed Dec 5, 2024
1 parent 99d3f72 commit 545f100
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
import java.util.List;
import java.util.Map;

import javax.management.RuntimeErrorException;

/** @author <a href="mailto:[email protected]">Junmin Ahn</a> */
public class IDPUserinfoMapper extends AbstractOIDCProtocolMapper
implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
Expand Down Expand Up @@ -124,100 +122,104 @@ protected void setClaim(
JsonNode userInfo;
JWSInput jws;

if (identityProviderConfig.isStoreToken()) {
IdentityProviderModel identityProviderModel = keycloakSession.identityProviders().getByAlias(idp);
String userInfoUrl = identityProviderModel.getConfig().get("userInfoUrl");

if (userInfoUrl != null) {
FederatedIdentityModel identity = keycloakSession.users().getFederatedIdentity(realm, userSession.getUser(),
idp);
String brokerToken = identity.getToken();
AccessTokenResponse brokerAccessToken = parseTokenString(brokerToken);
String userinfoResponse;

try {
userinfoResponse = callUserInfo(userInfoUrl, brokerAccessToken.getToken());
} catch (IOException e) {
throw new IdentityBrokerException("Failed to call userinfo endpoint");
}
// if the identity provider alias is the same as the client id
if (identityProviderConfig.getAlias().equals(clientSessionCtx.getClientSession().getClient().getClientId())) {
if (identityProviderConfig.isStoreToken()) {
IdentityProviderModel identityProviderModel = keycloakSession.identityProviders().getByAlias(idp);
String userInfoUrl = identityProviderModel.getConfig().get("userInfoUrl");

Boolean encryptionExpected = Boolean.parseBoolean(mappingModel.getConfig().get(ENCRYPTION_EXPECTED));
if (userInfoUrl != null) {
FederatedIdentityModel identity = keycloakSession.users().getFederatedIdentity(realm, userSession.getUser(),
idp);
String brokerToken = identity.getToken();
AccessTokenResponse brokerAccessToken = parseTokenString(brokerToken);
String userinfoResponse;

if (encryptionExpected) {
JOSE joseToken = JOSEParser.parse(userinfoResponse);
if (joseToken instanceof JWE) {
// encrypted JWE token
JWE jwe = (JWE) joseToken;
try {
KeyWrapper key;
if (jwe.getHeader().getKeyId() == null) {
key = keycloakSession.keys().getActiveKey(keycloakSession.getContext().getRealm(), KeyUse.ENC,
jwe.getHeader().getRawAlgorithm());
} else {
key = keycloakSession.keys().getKey(keycloakSession.getContext().getRealm(), jwe.getHeader().getKeyId(),
KeyUse.ENC,
jwe.getHeader().getRawAlgorithm());
}
if (key == null || key.getPrivateKey() == null) {
throw new IdentityBrokerException("Private key not found in the realm to decrypt token algorithm "
+ jwe.getHeader().getRawAlgorithm());
}
try {
userinfoResponse = callUserInfo(userInfoUrl, brokerAccessToken.getToken());
} catch (IOException e) {
throw new IdentityBrokerException("Failed to call userinfo endpoint");
}

jwe.getKeyStorage().setDecryptionKey(key.getPrivateKey());
jwe.verifyAndDecodeJwe();
userinfoResponse = new String(jwe.getContent(), StandardCharsets.UTF_8);
} catch (JWEException e) {
throw new IdentityBrokerException("Failed to decrypt userinfo JWT", e);
Boolean encryptionExpected = Boolean.parseBoolean(mappingModel.getConfig().get(ENCRYPTION_EXPECTED));

if (encryptionExpected) {
JOSE joseToken = JOSEParser.parse(userinfoResponse);
if (joseToken instanceof JWE) {
// encrypted JWE token
JWE jwe = (JWE) joseToken;
try {
KeyWrapper key;
if (jwe.getHeader().getKeyId() == null) {
key = keycloakSession.keys().getActiveKey(keycloakSession.getContext().getRealm(), KeyUse.ENC,
jwe.getHeader().getRawAlgorithm());
} else {
key = keycloakSession.keys().getKey(keycloakSession.getContext().getRealm(),
jwe.getHeader().getKeyId(),
KeyUse.ENC,
jwe.getHeader().getRawAlgorithm());
}
if (key == null || key.getPrivateKey() == null) {
throw new IdentityBrokerException("Private key not found in the realm to decrypt token algorithm "
+ jwe.getHeader().getRawAlgorithm());
}

jwe.getKeyStorage().setDecryptionKey(key.getPrivateKey());
jwe.verifyAndDecodeJwe();
userinfoResponse = new String(jwe.getContent(), StandardCharsets.UTF_8);
} catch (JWEException e) {
throw new IdentityBrokerException("Failed to decrypt userinfo JWT", e);
}
}
}
}

Boolean signatureExpected = Boolean.parseBoolean(mappingModel.getConfig().get(SIGNATURE_EXPECTED));
Boolean signatureExpected = Boolean.parseBoolean(mappingModel.getConfig().get(SIGNATURE_EXPECTED));

if (signatureExpected) {
if (signatureExpected) {

OIDCIdentityProviderConfig oidcIdpConfig = new OIDCIdentityProviderConfig(identityProviderConfig);
OIDCIdentityProviderConfig oidcIdpConfig = new OIDCIdentityProviderConfig(identityProviderConfig);

JOSE joseToken = JOSEParser.parse(userinfoResponse);
JOSE joseToken = JOSEParser.parse(userinfoResponse);

// common signed JWS token
jws = (JWSInput) joseToken;
// common signed JWS token
jws = (JWSInput) joseToken;

// verify signature of the JWS
if (!verify(keycloakSession, oidcIdpConfig, jws)) {
throw new IdentityBrokerException("Failed to verify userinfo JWT signature");
}
// verify signature of the JWS
if (!verify(keycloakSession, oidcIdpConfig, jws)) {
throw new IdentityBrokerException("Failed to verify userinfo JWT signature");
}

try {
userInfo = JsonSerialization.readValue(new String(jws.getContent(), StandardCharsets.UTF_8),
JsonNode.class);
} catch (IOException e) {
throw new IdentityBrokerException("Failed to parse userinfo JWT", e);
try {
userInfo = JsonSerialization.readValue(new String(jws.getContent(), StandardCharsets.UTF_8),
JsonNode.class);
} catch (IOException e) {
throw new IdentityBrokerException("Failed to parse userinfo JWT", e);
}
} else {
userInfo = parseJson(userinfoResponse);
}
} else {
userInfo = parseJson(userinfoResponse);
}

if (userInfo != null) {
// process string value of user attributes
String userAttributes = mappingModel.getConfig().get(USER_ATTRIBUTES);
String[] userAttributesArr = userAttributes == null ? new String[0] : userAttributes.split(",");
if (userInfo != null) {
// process string value of user attributes
String userAttributes = mappingModel.getConfig().get(USER_ATTRIBUTES);
String[] userAttributesArr = userAttributes == null ? new String[0] : userAttributes.split(",");

if (userAttributesArr.length > 0) {
Map<String, Object> otherClaims = token.getOtherClaims();
for (String userAttribute : userAttributesArr) {
otherClaims.put(userAttribute.trim(), userInfo.get(userAttribute.trim()));
if (userAttributesArr.length > 0) {
Map<String, Object> otherClaims = token.getOtherClaims();
for (String userAttribute : userAttributesArr) {
otherClaims.put(userAttribute.trim(), userInfo.get(userAttribute.trim()));
}
}
} else {
logger.error("The payload received from userinfo is null");
}

} else {
logger.error("The payload received from userinfo is null");
logger.error("Identity Provider [" + idp + "] does not have userinfo URL.");
}

} else {
logger.error("Identity Provider [" + idp + "] does not have userinfo URL.");
logger.error("Identity Provider [" + idp + "] does not store tokens.");
}
} else {
logger.error("Identity Provider [" + idp + "] does not store tokens.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,106 +143,109 @@ public void transformAttributeStatement(AttributeStatementType attributeStatemen
JsonNode userInfo;
JWSInput jws;

if (identityProviderConfig.isStoreToken()) {
IdentityProviderModel identityProviderModel = keycloakSession.identityProviders().getByAlias(idp);
String userInfoUrl = identityProviderModel.getConfig().get("userInfoUrl");

if (userInfoUrl != null) {
FederatedIdentityModel identity = keycloakSession.users().getFederatedIdentity(realm, userSession.getUser(),
idp);
String brokerToken = identity.getToken();
AccessTokenResponse brokerAccessToken = parseTokenString(brokerToken);
String userinfoResponse;

try {
userinfoResponse = callUserInfo(userInfoUrl, brokerAccessToken.getToken());
} catch (IOException e) {
throw new IdentityBrokerException("Failed to call userinfo endpoint");
}
if (identityProviderConfig.getAlias().equals(clientSession.getClient().getClientId())) {
if (identityProviderConfig.isStoreToken()) {
IdentityProviderModel identityProviderModel = keycloakSession.identityProviders().getByAlias(idp);
String userInfoUrl = identityProviderModel.getConfig().get("userInfoUrl");

if (userInfoUrl != null) {
FederatedIdentityModel identity = keycloakSession.users().getFederatedIdentity(realm, userSession.getUser(),
idp);
String brokerToken = identity.getToken();
AccessTokenResponse brokerAccessToken = parseTokenString(brokerToken);
String userinfoResponse;

Boolean encryptionExpected = Boolean.parseBoolean(mappingModel.getConfig().get(ENCRYPTION_EXPECTED));
try {
userinfoResponse = callUserInfo(userInfoUrl, brokerAccessToken.getToken());
} catch (IOException e) {
throw new IdentityBrokerException("Failed to call userinfo endpoint");
}

if (encryptionExpected) {
JOSE joseToken = JOSEParser.parse(userinfoResponse);
if (joseToken instanceof JWE) {
// encrypted JWE token
JWE jwe = (JWE) joseToken;
try {
KeyWrapper key;
if (jwe.getHeader().getKeyId() == null) {
key = keycloakSession.keys().getActiveKey(keycloakSession.getContext().getRealm(), KeyUse.ENC,
jwe.getHeader().getRawAlgorithm());
} else {
key = keycloakSession.keys().getKey(keycloakSession.getContext().getRealm(), jwe.getHeader().getKeyId(),
KeyUse.ENC,
jwe.getHeader().getRawAlgorithm());
Boolean encryptionExpected = Boolean.parseBoolean(mappingModel.getConfig().get(ENCRYPTION_EXPECTED));

if (encryptionExpected) {
JOSE joseToken = JOSEParser.parse(userinfoResponse);
if (joseToken instanceof JWE) {
// encrypted JWE token
JWE jwe = (JWE) joseToken;
try {
KeyWrapper key;
if (jwe.getHeader().getKeyId() == null) {
key = keycloakSession.keys().getActiveKey(keycloakSession.getContext().getRealm(), KeyUse.ENC,
jwe.getHeader().getRawAlgorithm());
} else {
key = keycloakSession.keys().getKey(keycloakSession.getContext().getRealm(),
jwe.getHeader().getKeyId(),
KeyUse.ENC,
jwe.getHeader().getRawAlgorithm());
}
if (key == null || key.getPrivateKey() == null) {
throw new IdentityBrokerException("Private key not found in the realm to decrypt token algorithm "
+ jwe.getHeader().getRawAlgorithm());
}

jwe.getKeyStorage().setDecryptionKey(key.getPrivateKey());
jwe.verifyAndDecodeJwe();
userinfoResponse = new String(jwe.getContent(), StandardCharsets.UTF_8);
} catch (JWEException e) {
throw new IdentityBrokerException("Failed to decrypt userinfo JWT", e);
}
if (key == null || key.getPrivateKey() == null) {
throw new IdentityBrokerException("Private key not found in the realm to decrypt token algorithm "
+ jwe.getHeader().getRawAlgorithm());
}

jwe.getKeyStorage().setDecryptionKey(key.getPrivateKey());
jwe.verifyAndDecodeJwe();
userinfoResponse = new String(jwe.getContent(), StandardCharsets.UTF_8);
} catch (JWEException e) {
throw new IdentityBrokerException("Failed to decrypt userinfo JWT", e);
}
}
}

Boolean signatureExpected = Boolean.parseBoolean(mappingModel.getConfig().get(SIGNATURE_EXPECTED));
Boolean signatureExpected = Boolean.parseBoolean(mappingModel.getConfig().get(SIGNATURE_EXPECTED));

if (signatureExpected) {
if (signatureExpected) {

OIDCIdentityProviderConfig oidcIdpConfig = new OIDCIdentityProviderConfig(identityProviderConfig);
OIDCIdentityProviderConfig oidcIdpConfig = new OIDCIdentityProviderConfig(identityProviderConfig);

JOSE joseToken = JOSEParser.parse(userinfoResponse);
JOSE joseToken = JOSEParser.parse(userinfoResponse);

// common signed JWS token
jws = (JWSInput) joseToken;
// common signed JWS token
jws = (JWSInput) joseToken;

// verify signature of the JWS
if (!verify(keycloakSession, oidcIdpConfig, jws)) {
throw new IdentityBrokerException("Failed to verify userinfo JWT signature");
}
// verify signature of the JWS
if (!verify(keycloakSession, oidcIdpConfig, jws)) {
throw new IdentityBrokerException("Failed to verify userinfo JWT signature");
}

try {
userInfo = JsonSerialization.readValue(new String(jws.getContent(), StandardCharsets.UTF_8),
JsonNode.class);
} catch (IOException e) {
throw new IdentityBrokerException("Failed to parse userinfo JWT", e);
try {
userInfo = JsonSerialization.readValue(new String(jws.getContent(), StandardCharsets.UTF_8),
JsonNode.class);
} catch (IOException e) {
throw new IdentityBrokerException("Failed to parse userinfo JWT", e);
}
} else {
userInfo = parseJson(userinfoResponse);
}
} else {
userInfo = parseJson(userinfoResponse);
}

if (userInfo != null) {
// process string value of user attributes
String userAttributes = mappingModel.getConfig().get(USER_ATTRIBUTES);
String[] userAttributesArr = userAttributes == null ? new String[0] : userAttributes.split(",");

if (userAttributesArr.length > 0) {
for (String userAttribute : userAttributesArr) {
AttributeType attribute = new AttributeType(userAttribute.trim());
attribute.setNameFormat(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get());
JsonNode attributeValue = deepFetchAttributes(userInfo, userAttribute, attributeStatement);
if (attributeValue != null) {
if (userInfo != null) {
// process string value of user attributes
String userAttributes = mappingModel.getConfig().get(USER_ATTRIBUTES);
String[] userAttributesArr = userAttributes == null ? new String[0] : userAttributes.split(",");

if (userAttributesArr.length > 0) {
for (String userAttribute : userAttributesArr) {
AttributeType attribute = new AttributeType(userAttribute.trim());
attribute.setNameFormat(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get());
attribute.addAttributeValue(attributeValue.asText());
attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attribute));
JsonNode attributeValue = deepFetchAttributes(userInfo, userAttribute, attributeStatement);
if (attributeValue != null) {
attribute.setNameFormat(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get());
attribute.addAttributeValue(attributeValue.asText());
attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attribute));
}
}
}
} else {
logger.error("The payload received from userinfo is null");
}

} else {
logger.error("The payload received from userinfo is null");
logger.error("Identity Provider [" + idp + "] does not have userinfo URL.");
}

} else {
logger.error("Identity Provider [" + idp + "] does not have userinfo URL.");
logger.error("Identity Provider [" + idp + "] does not store tokens.");
}
} else {
logger.error("Identity Provider [" + idp + "] does not store tokens.");
}
}

Expand Down

0 comments on commit 545f100

Please sign in to comment.