-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: do not run IDP Userinfo mapper for other than bcsc idps
- Loading branch information
1 parent
99d3f72
commit 545f100
Showing
2 changed files
with
158 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 { | ||
|
@@ -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."); | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters