Skip to content

Commit

Permalink
Add scim_id attribute for oidc tokens (#1010)
Browse files Browse the repository at this point in the history
  • Loading branch information
liga-oz authored Nov 3, 2022
1 parent 0b0aeef commit ab971c3
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 23 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
## 2.13.4
- [spring-xsuaa][spring-security]
- Patches [CVE-2022-31692](https://nvd.nist.gov/vuln/detail/CVE-2022-31692) vulnerability in spring security dependency.
- [java-security-test]
- `scim_id` added as default attribute for identity token Jwt generator

#### Dependency upgrades
* Bump spring.security.version from 5.7.3 to 5.7.5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ private TokenClaims() {
* true if the user physically exists in the IAS user store and IAS is not a
* pure proxy which simply forwards all information from the corporate IdP.
*/
public static final String SAP_GLOBAL_SCIM_ID = "scim_id";
public static final String SAP_GLOBAL_USER_ID = "user_uuid";
public static final String SAP_GLOBAL_ZONE_ID = "zone_uuid"; // tenant GUID
public static final String GROUPS = "groups"; // scim groups
Expand Down Expand Up @@ -70,9 +71,4 @@ private XSUAA() {
public static final String TRUSTED_CLIENT_ID_SUFFIX = "trustedclientidsuffix";
}

// SAP User token
/*
* public final class SAP_ID { private SAP_ID() { } // service_instance_id }
*/

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public class JwtGenerator {
private final JSONObject jsonHeader = new JSONObject();
private final JSONObject jsonPayload = new JSONObject();

private SignatureCalculator signatureCalculator;
private Service service;
private final SignatureCalculator signatureCalculator;
private final Service service;

private JwtSignatureAlgorithm signatureAlgorithm;
private PrivateKey privateKey = RSAKeys.generate().getPrivate();
Expand Down Expand Up @@ -149,9 +149,10 @@ private void setDefaultsForNewToken(String azp) {
jsonPayload.put(TokenClaims.AUDIENCE, azp);
jsonPayload.put(TokenClaims.SAP_GLOBAL_ZONE_ID, DEFAULT_ZONE_ID);
jsonPayload.put(TokenClaims.SAP_GLOBAL_USER_ID, DEFAULT_USER_ID);
jsonPayload.put(TokenClaims.SAP_GLOBAL_SCIM_ID, DEFAULT_USER_ID);
} else {
withClaimValue(TokenClaims.XSUAA.CLIENT_ID, azp); // Client Id left for backward compatibility
jsonPayload.put(TokenClaims.AUDIENCE, Arrays.asList(azp));
jsonPayload.put(TokenClaims.AUDIENCE, Collections.singletonList(azp));
jsonPayload.put(TokenClaims.XSUAA.ZONE_ID, DEFAULT_ZONE_ID);
jsonPayload.put(TokenClaims.XSUAA.EXTERNAL_ATTRIBUTE, createJsonObject("{\"enhancer\" : \"XSUAA\"} "));
}
Expand Down Expand Up @@ -266,14 +267,14 @@ public JwtGenerator withClaimValues(String claimName, String... values) {
*
* @throws JsonParsingException
* if the file does not contain a valid json object.
* @throws IOException
* @throws IllegalArgumentException
* when the file cannot be read or does not exist.
* @param claimsJsonResource
* the resource path to the file containing the claims in json
* format, e.g. "/claims.json"
* @return the builder object.
*/
public JwtGenerator withClaimsFromFile(String claimsJsonResource) throws IOException {
public JwtGenerator withClaimsFromFile(String claimsJsonResource) throws IllegalArgumentException {
String claimsJson = read(claimsJsonResource);
JSONObject jsonObject = createJsonObject(claimsJson);
copyJsonProperties(jsonObject, jsonPayload);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public void createIasToken_isNotNull() {
.withClaimValue("last_name", "doe")
.withClaimValue("email", "[email protected]")
.withClaimValue(SAP_GLOBAL_USER_ID, "1234567890")
.withClaimValue(SAP_GLOBAL_SCIM_ID, "scim-1234567890")
.withPrivateKey(keys.getPrivate());
Token token = cut.createToken();

Expand All @@ -100,6 +101,7 @@ public void createIasToken_isNotNull() {
assertThat(token.getClientId()).isEqualTo("T000310");
assertThat(token.getExpiration()).isEqualTo(JwtGenerator.NO_EXPIRE_DATE);
assertThat(token.getClaimAsString(SAP_GLOBAL_USER_ID)).isEqualTo("1234567890");
assertThat(token.getClaimAsString(SAP_GLOBAL_SCIM_ID)).isEqualTo("scim-1234567890");
assertThat(token.getPrincipal().getName()).isEqualTo("1234567890");
String encodedModulusN = Base64.getUrlEncoder()
.encodeToString(((RSAPublicKey) keys.getPublic()).getModulus().toByteArray());
Expand Down Expand Up @@ -297,7 +299,7 @@ public void loadClaimsFromFile_doesNotContainValidJson_throwsException() throws
}

@Test
public void loadClaimsFromFile_containsStringClaims() throws IOException {
public void loadClaimsFromFile_containsStringClaims() {
final Token token = cut.withClaimsFromFile("/claims.json").createToken();

assertThat(token.getClaimAsString(EMAIL)).isEqualTo("[email protected]");
Expand All @@ -306,14 +308,14 @@ public void loadClaimsFromFile_containsStringClaims() throws IOException {
}

@Test
public void loadClaimsFromFile_containsExpirationClaim() throws IOException {
public void loadClaimsFromFile_containsExpirationClaim() {
final Token token = cut.withClaimsFromFile("/claims.json").createToken();

assertThat(token.getExpiration()).isEqualTo(Instant.ofEpochSecond(1542416800));
}

@Test
public void loadClaimsFromFile_containsJsonObjectClaims() throws IOException {
public void loadClaimsFromFile_containsJsonObjectClaims() {
final Token token = cut.withClaimsFromFile("/claims.json").createToken();

JsonObject externalAttributes = token.getClaimAsJsonObject("ext_attr");
Expand All @@ -324,7 +326,7 @@ public void loadClaimsFromFile_containsJsonObjectClaims() throws IOException {
}

@Test
public void loadClaimsFromFile_containsListClaims() throws IOException {
public void loadClaimsFromFile_containsListClaims() {
final Token token = cut.withClaimsFromFile("/claims.json").createToken();

assertThat(token.getClaimAsStringList(TokenClaims.XSUAA.SCOPES))
Expand All @@ -333,7 +335,7 @@ public void loadClaimsFromFile_containsListClaims() throws IOException {
}

@Test
public void getInstanceFromFile_overridesTokenPropertiesForTesting() throws IOException {
public void getInstanceFromFile_overridesTokenPropertiesForTesting() {
Token token = JwtGenerator.getInstanceFromFile(XSUAA, "/token.json")
.createToken();

Expand All @@ -342,7 +344,7 @@ public void getInstanceFromFile_overridesTokenPropertiesForTesting() throws IOEx
}

@Test
public void getInstanceFromFile_loadsJsonData() throws IOException {
public void getInstanceFromFile_loadsJsonData() {
Token token = JwtGenerator.getInstanceFromFile(XSUAA, "/token.json")
.createToken();

Expand All @@ -355,15 +357,15 @@ public void getInstanceFromFile_loadsJsonData() throws IOException {
}

@Test
public void getInstanceFromFile_noHeader_noErrorAndReadsPayload() throws IOException {
public void getInstanceFromFile_noHeader_noErrorAndReadsPayload() {
Token token = JwtGenerator.getInstanceFromFile(XSUAA, "/token_no_header.json")
.createToken();

assertThat(token.getClaimAsString(TokenClaims.XSUAA.ZONE_ID)).isEqualTo("zone-id");
}

@Test
public void getInstanceFromFile_invalidAlg_throwsException() throws IOException {
public void getInstanceFromFile_invalidAlg_throwsException() {
assertThatThrownBy(() -> JwtGenerator.getInstanceFromFile(XSUAA, "/token_invalid_alg.json"))
.isInstanceOf(UnsupportedOperationException.class);
}
Expand All @@ -385,23 +387,23 @@ public void createToken_signatureCalculation_NoSuchAlgorithmExceptionTurnedIntoR
JwtGenerator instance = JwtGenerator.getInstance(XSUAA, (key, alg, data) -> {
throw new NoSuchAlgorithmException();
});
assertThatThrownBy(() -> instance.createToken()).isInstanceOf(RuntimeException.class);
assertThatThrownBy(instance::createToken).isInstanceOf(RuntimeException.class);
}

@Test
public void createToken_signatureCalculation_SignatureExceptionTurnedIntoRuntimeException() {
JwtGenerator instance = JwtGenerator.getInstance(XSUAA, (key, alg, data) -> {
throw new SignatureException();
});
assertThatThrownBy(() -> instance.createToken()).isInstanceOf(RuntimeException.class);
assertThatThrownBy(instance::createToken).isInstanceOf(RuntimeException.class);
}

@Test
public void createToken_signatureCalculation_InvalidKeyExceptionTurnedIntoRuntimeException() {
JwtGenerator instance = JwtGenerator.getInstance(XSUAA, (key, alg, data) -> {
throw new InvalidKeyException();
});
assertThatThrownBy(() -> instance.createToken()).isInstanceOf(RuntimeException.class);
assertThatThrownBy(instance::createToken).isInstanceOf(RuntimeException.class);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void parseJwt() {
Jwt jwt = HybridJwtDecoder.parseJwt(jwtGenerator.createToken());

assertEquals(2, jwt.getHeaders().size());
assertEquals(6, jwt.getClaims().size());
assertEquals(7, jwt.getClaims().size());
assertEquals(1, jwt.getExpiresAt().compareTo(Instant.now()));
assertEquals("theClientId", jwt.getClaim(TokenClaims.AUTHORIZATION_PARTY));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void parseJwt() {
Jwt jwt = IasJwtDecoder.parseJwt(jwtGenerator.createToken());

assertEquals(2, jwt.getHeaders().size());
assertEquals(6, jwt.getClaims().size());
assertEquals(7, jwt.getClaims().size());
assertEquals(1, jwt.getExpiresAt().compareTo(Instant.now()));
assertEquals("theClientId", jwt.getClaim(TokenClaims.AUTHORIZATION_PARTY));
}
Expand Down

0 comments on commit ab971c3

Please sign in to comment.