diff --git a/extensions/common/crypto/ldp-verifiable-credentials/src/main/java/org/eclipse/edc/verifiablecredentials/linkeddata/LdpVerifier.java b/extensions/common/crypto/ldp-verifiable-credentials/src/main/java/org/eclipse/edc/verifiablecredentials/linkeddata/LdpVerifier.java index 46c75375bca..d751137b56a 100644 --- a/extensions/common/crypto/ldp-verifiable-credentials/src/main/java/org/eclipse/edc/verifiablecredentials/linkeddata/LdpVerifier.java +++ b/extensions/common/crypto/ldp-verifiable-credentials/src/main/java/org/eclipse/edc/verifiablecredentials/linkeddata/LdpVerifier.java @@ -30,7 +30,6 @@ import com.apicatalog.ld.signature.VerificationError; import com.apicatalog.ld.signature.VerificationError.Code; import com.apicatalog.ld.signature.key.VerificationKey; -import com.apicatalog.ld.signature.method.DidUrlMethodResolver; import com.apicatalog.ld.signature.method.HttpMethodResolver; import com.apicatalog.ld.signature.method.MethodResolver; import com.apicatalog.ld.signature.method.VerificationMethod; @@ -67,7 +66,7 @@ public class LdpVerifier implements CredentialVerifier { private ObjectMapper jsonLdMapper; private SignatureSuiteProvider suiteProvider; private Map params; - private Collection methodResolvers = new ArrayList<>(List.of(new DidUrlMethodResolver(), new HttpMethodResolver())); + private Collection methodResolvers = new ArrayList<>(List.of(new HttpMethodResolver())); private DocumentLoader loader; private URI base; diff --git a/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java b/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java index e7c9193a369..84b57bff25a 100644 --- a/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java +++ b/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java @@ -22,6 +22,7 @@ import org.eclipse.edc.iam.identitytrust.core.defaults.DefaultCredentialServiceClient; import org.eclipse.edc.iam.identitytrust.validation.SelfIssuedIdTokenValidator; import org.eclipse.edc.iam.identitytrust.verification.MultiFormatPresentationVerifier; +import org.eclipse.edc.identitytrust.AudienceResolver; import org.eclipse.edc.identitytrust.CredentialServiceClient; import org.eclipse.edc.identitytrust.SecureTokenService; import org.eclipse.edc.identitytrust.TrustedIssuerRegistry; @@ -60,10 +61,6 @@ public class IdentityAndTrustExtension implements ServiceExtension { @Inject private SecureTokenService secureTokenService; - - @Inject - private CredentialServiceClient credentialServiceClient; - @Inject private TrustedIssuerRegistry registry; @@ -94,12 +91,15 @@ public class IdentityAndTrustExtension implements ServiceExtension { private JwtValidator jwtValidator; private JwtVerifier jwtVerifier; private PresentationVerifier presentationVerifier; + private CredentialServiceClient credentialServiceClient; + @Inject + private AudienceResolver audienceResolver; @Provider public IdentityService createIdentityService(ServiceExtensionContext context) { var credentialServiceUrlResolver = new DidCredentialServiceUrlResolver(didResolverRegistry); return new IdentityAndTrustService(secureTokenService, getOwnDid(context), context.getParticipantId(), getPresentationVerifier(context), - getCredentialServiceClient(context), getJwtValidator(), getJwtVerifier(), registry, clock, credentialServiceUrlResolver); + getCredentialServiceClient(context), getJwtValidator(), getJwtVerifier(), registry, clock, credentialServiceUrlResolver, audienceResolver); } @Provider diff --git a/extensions/common/iam/identity-trust/identity-trust-service/src/main/java/org/eclipse/edc/iam/identitytrust/IdentityAndTrustService.java b/extensions/common/iam/identity-trust/identity-trust-service/src/main/java/org/eclipse/edc/iam/identitytrust/IdentityAndTrustService.java index b1e607e436a..e478d899b31 100644 --- a/extensions/common/iam/identity-trust/identity-trust-service/src/main/java/org/eclipse/edc/iam/identitytrust/IdentityAndTrustService.java +++ b/extensions/common/iam/identity-trust/identity-trust-service/src/main/java/org/eclipse/edc/iam/identitytrust/IdentityAndTrustService.java @@ -14,10 +14,12 @@ package org.eclipse.edc.iam.identitytrust; +import com.nimbusds.jwt.SignedJWT; import org.eclipse.edc.iam.identitytrust.validation.rules.HasValidIssuer; import org.eclipse.edc.iam.identitytrust.validation.rules.HasValidSubjectIds; import org.eclipse.edc.iam.identitytrust.validation.rules.IsNotExpired; import org.eclipse.edc.iam.identitytrust.validation.rules.IsRevoked; +import org.eclipse.edc.identitytrust.AudienceResolver; import org.eclipse.edc.identitytrust.CredentialServiceClient; import org.eclipse.edc.identitytrust.CredentialServiceUrlResolver; import org.eclipse.edc.identitytrust.SecureTokenService; @@ -35,14 +37,22 @@ import org.eclipse.edc.spi.result.Result; import org.eclipse.edc.util.string.StringUtils; +import java.text.ParseException; import java.time.Clock; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import static com.nimbusds.jwt.JWTClaimNames.AUDIENCE; +import static com.nimbusds.jwt.JWTClaimNames.EXPIRATION_TIME; +import static com.nimbusds.jwt.JWTClaimNames.ISSUED_AT; import static com.nimbusds.jwt.JWTClaimNames.ISSUER; +import static com.nimbusds.jwt.JWTClaimNames.SUBJECT; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.spi.result.Result.failure; import static org.eclipse.edc.spi.result.Result.success; @@ -50,7 +60,7 @@ * Implements an {@link IdentityService}, that: *
    *
  • Obtains an SI token from a SecureTokenService
  • - *
  • Establishes proof-of-original possession, by extracting the access_token, and re-packaging it into a new SI token
  • + *
  • Establishes proof-of-original possession, by extracting the PRESENTATION_ACCESS_TOKEN_CLAIM, and re-packaging it into a new SI token
  • *
  • Performs a presentation request against a CredentialService
  • *
  • Validates and verifies the VerifiablePresentation
  • *
@@ -59,7 +69,6 @@ */ public class IdentityAndTrustService implements IdentityService { private static final String SCOPE_STRING_REGEX = "(.+):(.+):(read|write|\\*)"; - private final SecureTokenService secureTokenService; private final String myOwnDid; private final String participantId; @@ -70,6 +79,7 @@ public class IdentityAndTrustService implements IdentityService { private final TrustedIssuerRegistry trustedIssuerRegistry; private final Clock clock; private final CredentialServiceUrlResolver credentialServiceUrlResolver; + private final AudienceResolver audienceMapper; /** * Constructs a new instance of the {@link IdentityAndTrustService}. @@ -79,7 +89,7 @@ public class IdentityAndTrustService implements IdentityService { */ public IdentityAndTrustService(SecureTokenService secureTokenService, String myOwnDid, String participantId, PresentationVerifier presentationVerifier, CredentialServiceClient credentialServiceClient, - JwtValidator jwtValidator, JwtVerifier jwtVerifier, TrustedIssuerRegistry trustedIssuerRegistry, Clock clock, CredentialServiceUrlResolver csUrlResolver) { + JwtValidator jwtValidator, JwtVerifier jwtVerifier, TrustedIssuerRegistry trustedIssuerRegistry, Clock clock, CredentialServiceUrlResolver csUrlResolver, AudienceResolver audienceMapper) { this.secureTokenService = secureTokenService; this.myOwnDid = myOwnDid; this.participantId = participantId; @@ -90,10 +100,18 @@ public IdentityAndTrustService(SecureTokenService secureTokenService, String myO this.trustedIssuerRegistry = trustedIssuerRegistry; this.clock = clock; this.credentialServiceUrlResolver = csUrlResolver; + this.audienceMapper = audienceMapper; } @Override public Result obtainClientCredentials(TokenParameters parameters) { + var newAud = audienceMapper.resolve(parameters.getAudience()); + parameters = TokenParameters.Builder.newInstance() + .audience(newAud) + .scope(parameters.getScope()) + .additional(parameters.getAdditional()) + .build(); + var scope = parameters.getScope(); var scopeValidationResult = validateScope(scope); @@ -118,19 +136,45 @@ public Result obtainClientCredentials(TokenParameters param public Result verifyJwtToken(TokenRepresentation tokenRepresentation, String audience) { // verify and validate incoming SI Token - var issuerResult = jwtVerifier.verify(tokenRepresentation.getToken(), audience) - .compose(v -> jwtValidator.validateToken(tokenRepresentation, audience)) - .compose(claimToken -> success(claimToken.getStringClaim(ISSUER))); + var claimTokenResult = jwtVerifier.verify(tokenRepresentation.getToken(), participantId) + .compose(v -> jwtValidator.validateToken(tokenRepresentation, participantId)) // audience must be set to my own participant ID + .compose(Result::success); - if (issuerResult.failed()) { - return issuerResult.mapTo(); + if (claimTokenResult.failed()) { + return claimTokenResult.mapTo(); } + // create our own SI token, to request the VPs + var claimToken = claimTokenResult.getContent(); + var accessToken = claimToken.getStringClaim(PRESENTATION_ACCESS_TOKEN_CLAIM); + var issuer = claimToken.getStringClaim(ISSUER); + var intendedAudience = claimToken.getStringClaim("client_id"); + + /* TODO: DEMO the scopes should be extracted elsewhere. replace this section!!############################*/ + var scopes = new ArrayList(); + try { + var scope = SignedJWT.parse(accessToken).getJWTClaimsSet().getStringClaim("scope"); + scopes.add(scope); + } catch (ParseException e) { + throw new RuntimeException(e); + } + /* TODO: END DEMO ########################################################################################*/ + + var siTokenClaims = Map.of(PRESENTATION_ACCESS_TOKEN_CLAIM, accessToken, + ISSUED_AT, Instant.now().toString(), + AUDIENCE, intendedAudience, + ISSUER, myOwnDid, + SUBJECT, myOwnDid, + EXPIRATION_TIME, Instant.now().plus(5, ChronoUnit.MINUTES).toString()); + var siToken = secureTokenService.createToken(siTokenClaims, null); + if (siToken.failed()) { + return siToken.mapTo(); + } + var siTokenString = siToken.getContent().getToken(); // get CS Url, execute VP request - var issuer = issuerResult.getContent(); // the issuer is a DID var vpResponse = credentialServiceUrlResolver.resolve(issuer) - .compose(url -> credentialServiceClient.requestPresentation(url, null, null)); + .compose(url -> credentialServiceClient.requestPresentation(url, siTokenString, scopes)); if (vpResponse.failed()) { return vpResponse.mapTo(); diff --git a/extensions/common/iam/identity-trust/identity-trust-service/src/main/java/org/eclipse/edc/iam/identitytrust/validation/SelfIssuedIdTokenValidator.java b/extensions/common/iam/identity-trust/identity-trust-service/src/main/java/org/eclipse/edc/iam/identitytrust/validation/SelfIssuedIdTokenValidator.java index 4f238c36d4d..60738df19d8 100644 --- a/extensions/common/iam/identity-trust/identity-trust-service/src/main/java/org/eclipse/edc/iam/identitytrust/validation/SelfIssuedIdTokenValidator.java +++ b/extensions/common/iam/identity-trust/identity-trust-service/src/main/java/org/eclipse/edc/iam/identitytrust/validation/SelfIssuedIdTokenValidator.java @@ -24,6 +24,7 @@ import java.util.Objects; import static java.time.Instant.now; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.spi.result.Result.failure; import static org.eclipse.edc.spi.result.Result.success; @@ -78,6 +79,9 @@ public Result validateToken(TokenRepresentation tokenRepresentation, if (exp.toInstant().plusSeconds(EPSILON).isBefore(now())) { return failure("The token must not be expired."); } + if (claims.getClaim(PRESENTATION_ACCESS_TOKEN_CLAIM) == null) { + return failure("The 'access_token' claim is mandatory."); + } var bldr = ClaimToken.Builder.newInstance(); jwt.getJWTClaimsSet().getClaims().forEach(bldr::claim); return success(bldr.build()); diff --git a/extensions/common/iam/identity-trust/identity-trust-service/src/test/java/org/eclipse/edc/iam/identitytrust/service/IdentityAndTrustServiceTest.java b/extensions/common/iam/identity-trust/identity-trust-service/src/test/java/org/eclipse/edc/iam/identitytrust/service/IdentityAndTrustServiceTest.java index 69c9ea8f4ba..bf6fb5e00e3 100644 --- a/extensions/common/iam/identity-trust/identity-trust-service/src/test/java/org/eclipse/edc/iam/identitytrust/service/IdentityAndTrustServiceTest.java +++ b/extensions/common/iam/identity-trust/identity-trust-service/src/test/java/org/eclipse/edc/iam/identitytrust/service/IdentityAndTrustServiceTest.java @@ -15,6 +15,7 @@ package org.eclipse.edc.iam.identitytrust.service; +import com.nimbusds.jwt.JWTClaimsSet; import org.eclipse.edc.iam.identitytrust.IdentityAndTrustService; import org.eclipse.edc.identitytrust.CredentialServiceClient; import org.eclipse.edc.identitytrust.CredentialServiceUrlResolver; @@ -29,6 +30,7 @@ import org.eclipse.edc.identitytrust.verification.PresentationVerifier; import org.eclipse.edc.spi.iam.ClaimToken; import org.eclipse.edc.spi.iam.TokenParameters; +import org.eclipse.edc.spi.iam.TokenRepresentation; import org.eclipse.edc.spi.result.Result; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; @@ -45,6 +47,7 @@ import java.util.List; import java.util.Map; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.identitytrust.TestFunctions.createCredentialBuilder; import static org.eclipse.edc.identitytrust.TestFunctions.createJwt; import static org.eclipse.edc.identitytrust.TestFunctions.createPresentationBuilder; @@ -72,15 +75,20 @@ class IdentityAndTrustServiceTest { private final JwtValidator jwtValidatorMock = mock(); private final JwtVerifier jwtVerfierMock = mock(); private final TrustedIssuerRegistry trustedIssuerRegistryMock = mock(); - private final CredentialServiceUrlResolver resolverMock = mock(); + private final CredentialServiceUrlResolver credentialServiceUrlResolverMock = mock(); private final IdentityAndTrustService service = new IdentityAndTrustService(mockedSts, EXPECTED_OWN_DID, EXPECTED_PARTICIPANT_ID, mockedVerifier, mockedClient, - jwtValidatorMock, jwtVerfierMock, trustedIssuerRegistryMock, Clock.systemUTC(), resolverMock); + jwtValidatorMock, jwtVerfierMock, trustedIssuerRegistryMock, Clock.systemUTC(), credentialServiceUrlResolverMock, i -> i); @BeforeEach void setup() { - when(resolverMock.resolve(any())).thenReturn(success("foobar")); - when(jwtValidatorMock.validateToken(any(), any())).thenReturn(success(ClaimToken.Builder.newInstance().claim("iss", CONSUMER_DID).build())); + when(credentialServiceUrlResolverMock.resolve(any())).thenReturn(success("foobar")); + var jwt = createJwt(new JWTClaimsSet.Builder().claim("scope", "foo-scope").build()); + when(jwtValidatorMock.validateToken(any(), any())).thenReturn(success(ClaimToken.Builder.newInstance() + .claim("iss", CONSUMER_DID) + .claim("client_id", "sender-id") + .claim(PRESENTATION_ACCESS_TOKEN_CLAIM, jwt.getToken()).build())); when(jwtVerfierMock.verify(any(), any())).thenReturn(success()); + when(mockedSts.createToken(any(), any())).thenReturn(success(TokenRepresentation.Builder.newInstance().build())); } @Nested @@ -242,7 +250,7 @@ void jwtTokenNotVerified() { @Test void cannotResolveCredentialServiceUrl() { - when(resolverMock.resolve(any())).thenReturn(Result.failure("test-failure")); + when(credentialServiceUrlResolverMock.resolve(any())).thenReturn(Result.failure("test-failure")); assertThat(service.verifyJwtToken(createJwt(), "test-audience")) .isFailed() .detail() diff --git a/extensions/common/iam/identity-trust/identity-trust-service/src/test/java/org/eclipse/edc/iam/identitytrust/validation/SelfIssuedIdTokenValidatorTest.java b/extensions/common/iam/identity-trust/identity-trust-service/src/test/java/org/eclipse/edc/iam/identitytrust/validation/SelfIssuedIdTokenValidatorTest.java index fbb5609baf5..c7e82c11f28 100644 --- a/extensions/common/iam/identity-trust/identity-trust-service/src/test/java/org/eclipse/edc/iam/identitytrust/validation/SelfIssuedIdTokenValidatorTest.java +++ b/extensions/common/iam/identity-trust/identity-trust-service/src/test/java/org/eclipse/edc/iam/identitytrust/validation/SelfIssuedIdTokenValidatorTest.java @@ -23,6 +23,7 @@ import java.util.Date; import java.util.UUID; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.identitytrust.TestFunctions.createJwt; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; @@ -43,6 +44,7 @@ void success() { .issuer(CONSUMER_DID) .audience(EXPECTED_OWN_DID) .claim("jti", UUID.randomUUID().toString()) + .claim(PRESENTATION_ACCESS_TOKEN_CLAIM, "foobar") .claim("client_id", CONSUMER_DID) .expirationTime(new Date(new Date().getTime() + 60 * 1000)) .build(); @@ -87,7 +89,7 @@ void audNotEqualToOwnDid() { .isFailed() .detail().isEqualTo("The aud claim expected to be %s but was [%s]".formatted(EXPECTED_OWN_DID, "invalid-audience")); } - + @Test void subJwkClaimPresent() { var claimsSet = new JWTClaimsSet.Builder() diff --git a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-core/src/main/java/org/eclipse/edc/iam/identitytrust/sts/core/defaults/service/StsClientTokenGeneratorServiceImpl.java b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-core/src/main/java/org/eclipse/edc/iam/identitytrust/sts/core/defaults/service/StsClientTokenGeneratorServiceImpl.java index 088d59d786f..2e91a94139b 100644 --- a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-core/src/main/java/org/eclipse/edc/iam/identitytrust/sts/core/defaults/service/StsClientTokenGeneratorServiceImpl.java +++ b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-core/src/main/java/org/eclipse/edc/iam/identitytrust/sts/core/defaults/service/StsClientTokenGeneratorServiceImpl.java @@ -29,8 +29,8 @@ import java.util.Optional; import java.util.function.Function; -import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.ACCESS_TOKEN; import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.BEARER_ACCESS_ALIAS; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.CLIENT_ID; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.ISSUER; @@ -39,7 +39,7 @@ public class StsClientTokenGeneratorServiceImpl implements StsClientTokenGeneratorService { private static final Map> CLAIM_MAPPERS = Map.of( - ACCESS_TOKEN, StsClientTokenAdditionalParams::getAccessToken, + PRESENTATION_ACCESS_TOKEN_CLAIM, StsClientTokenAdditionalParams::getAccessToken, BEARER_ACCESS_ALIAS, StsClientTokenAdditionalParams::getBearerAccessAlias); private final long tokenExpiration; diff --git a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-core/src/test/java/org/eclipse/edc/iam/identitytrust/sts/core/defaults/StsClientTokenIssuanceIntegrationTest.java b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-core/src/test/java/org/eclipse/edc/iam/identitytrust/sts/core/defaults/StsClientTokenIssuanceIntegrationTest.java index c3eb718b1c8..52101f95b9a 100644 --- a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-core/src/test/java/org/eclipse/edc/iam/identitytrust/sts/core/defaults/StsClientTokenIssuanceIntegrationTest.java +++ b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-core/src/test/java/org/eclipse/edc/iam/identitytrust/sts/core/defaults/StsClientTokenIssuanceIntegrationTest.java @@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.eclipse.edc.iam.identitytrust.sts.store.fixtures.TestFunctions.createClientBuilder; -import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.ACCESS_TOKEN; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.CLIENT_ID; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.EXPIRATION_TIME; @@ -163,7 +163,7 @@ void authenticateAndGenerateToken_withAccessToken() throws Exception { .containsEntry(SUBJECT, id) .containsEntry(AUDIENCE, List.of(audience)) .containsEntry(CLIENT_ID, clientId) - .containsEntry(ACCESS_TOKEN, accessToken) + .containsEntry(PRESENTATION_ACCESS_TOKEN_CLAIM, accessToken) .containsKeys(JWT_ID, EXPIRATION_TIME, ISSUED_AT); } diff --git a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-embedded/src/main/java/org/eclipse/edc/iam/identitytrust/sts/embedded/EmbeddedSecureTokenService.java b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-embedded/src/main/java/org/eclipse/edc/iam/identitytrust/sts/embedded/EmbeddedSecureTokenService.java index b9f4bcf64e5..a861f9cc4cc 100644 --- a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-embedded/src/main/java/org/eclipse/edc/iam/identitytrust/sts/embedded/EmbeddedSecureTokenService.java +++ b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-embedded/src/main/java/org/eclipse/edc/iam/identitytrust/sts/embedded/EmbeddedSecureTokenService.java @@ -30,8 +30,8 @@ import static java.lang.String.format; import static java.util.Optional.ofNullable; -import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.ACCESS_TOKEN; import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.BEARER_ACCESS_ALIAS; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.ISSUER; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.SCOPE; @@ -69,7 +69,7 @@ public Result createToken(Map claims, @Null private Result createAndAcceptAccessToken(Map claims, String scope, BiConsumer consumer) { return createAccessToken(claims, scope) .compose(tokenRepresentation -> success(tokenRepresentation.getToken())) - .onSuccess(withClaim(ACCESS_TOKEN, consumer)) + .onSuccess(withClaim(PRESENTATION_ACCESS_TOKEN_CLAIM, consumer)) .mapTo(); } diff --git a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-embedded/src/test/java/org/eclipse/edc/iam/identitytrust/sts/embedded/EmbeddedSecureTokenServiceIntegrationTest.java b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-embedded/src/test/java/org/eclipse/edc/iam/identitytrust/sts/embedded/EmbeddedSecureTokenServiceIntegrationTest.java index 38717872f0c..ece004ea184 100644 --- a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-embedded/src/test/java/org/eclipse/edc/iam/identitytrust/sts/embedded/EmbeddedSecureTokenServiceIntegrationTest.java +++ b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-embedded/src/test/java/org/eclipse/edc/iam/identitytrust/sts/embedded/EmbeddedSecureTokenServiceIntegrationTest.java @@ -40,8 +40,8 @@ import static org.assertj.core.api.Assertions.as; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.InstanceOfAssertFactories.STRING; -import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.ACCESS_TOKEN; import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.BEARER_ACCESS_ALIAS; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.EXPIRATION_TIME; @@ -83,7 +83,7 @@ void createToken_withoutBearerAccessScope() { assertThat(jwt.getJWTClaimsSet().getClaims()) .containsEntry(ISSUER, issuer) .containsKeys(JWT_ID, EXPIRATION_TIME, ISSUED_AT) - .doesNotContainKey(ACCESS_TOKEN); + .doesNotContainKey(PRESENTATION_ACCESS_TOKEN_CLAIM); }); } @@ -104,7 +104,7 @@ void createToken_withBearerAccessScope() { assertThat(jwt.getJWTClaimsSet().getClaims()) .containsEntry(ISSUER, issuer) .containsKeys(JWT_ID, EXPIRATION_TIME, ISSUED_AT) - .extractingByKey(ACCESS_TOKEN, as(STRING)) + .extractingByKey(PRESENTATION_ACCESS_TOKEN_CLAIM, as(STRING)) .satisfies(accessToken -> { var accessTokenJwt = SignedJWT.parse(accessToken); assertThat(accessTokenJwt.verify(createVerifier(accessTokenJwt.getHeader(), keyPair.getPublic()))).isTrue(); @@ -135,7 +135,7 @@ void createToken_withBearerAccessAlias() { assertThat(jwt.getJWTClaimsSet().getClaims()) .containsEntry(ISSUER, issuer) .containsKeys(JWT_ID, EXPIRATION_TIME, ISSUED_AT) - .extractingByKey(ACCESS_TOKEN, as(STRING)) + .extractingByKey(PRESENTATION_ACCESS_TOKEN_CLAIM, as(STRING)) .satisfies(accessToken -> { var accessTokenJwt = SignedJWT.parse(accessToken); assertThat(accessTokenJwt.verify(createVerifier(accessTokenJwt.getHeader(), keyPair.getPublic()))).isTrue(); @@ -148,7 +148,7 @@ void createToken_withBearerAccessAlias() { }); }); } - + @ParameterizedTest @ArgumentsSource(ClaimsArguments.class) void createToken_shouldFail_withMissingClaims(Map claims) { diff --git a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-remote/src/main/java/org/eclipse/edc/iam/identitytrust/sts/remote/RemoteSecureTokenService.java b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-remote/src/main/java/org/eclipse/edc/iam/identitytrust/sts/remote/RemoteSecureTokenService.java index cd17f61a46d..f49a8d9e2fa 100644 --- a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-remote/src/main/java/org/eclipse/edc/iam/identitytrust/sts/remote/RemoteSecureTokenService.java +++ b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-remote/src/main/java/org/eclipse/edc/iam/identitytrust/sts/remote/RemoteSecureTokenService.java @@ -26,9 +26,9 @@ import java.util.Map; import java.util.stream.Collectors; -import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.ACCESS_TOKEN; import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.BEARER_ACCESS_ALIAS; import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.BEARER_ACCESS_SCOPE; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; public class RemoteSecureTokenService implements SecureTokenService { @@ -39,7 +39,7 @@ public class RemoteSecureTokenService implements SecureTokenService { private static final Map CLAIM_MAPPING = Map.of( AUDIENCE, AUDIENCE_PARAM, BEARER_ACCESS_ALIAS, BEARER_ACCESS_ALIAS, - ACCESS_TOKEN, ACCESS_TOKEN); + PRESENTATION_ACCESS_TOKEN_CLAIM, PRESENTATION_ACCESS_TOKEN_CLAIM); private final Oauth2Client oauth2Client; private final StsRemoteClientConfiguration configuration; diff --git a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-remote/src/test/java/org/eclipse/edc/iam/identitytrust/sts/remote/RemoteSecureTokenServiceTest.java b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-remote/src/test/java/org/eclipse/edc/iam/identitytrust/sts/remote/RemoteSecureTokenServiceTest.java index e2763173e86..f6063f4581e 100644 --- a/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-remote/src/test/java/org/eclipse/edc/iam/identitytrust/sts/remote/RemoteSecureTokenServiceTest.java +++ b/extensions/common/iam/identity-trust/identity-trust-sts/identity-trust-sts-remote/src/test/java/org/eclipse/edc/iam/identitytrust/sts/remote/RemoteSecureTokenServiceTest.java @@ -27,9 +27,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.eclipse.edc.iam.identitytrust.sts.remote.RemoteSecureTokenService.AUDIENCE_PARAM; import static org.eclipse.edc.iam.identitytrust.sts.remote.RemoteSecureTokenService.GRANT_TYPE; -import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.ACCESS_TOKEN; import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.BEARER_ACCESS_ALIAS; import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.BEARER_ACCESS_SCOPE; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; import static org.mockito.ArgumentMatchers.any; @@ -93,7 +93,7 @@ void createToken_withAccessToken() { var audience = "aud"; var accessToken = "accessToken"; when(oauth2Client.requestToken(any())).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().build())); - assertThat(secureTokenService.createToken(Map.of(AUDIENCE, audience, ACCESS_TOKEN, accessToken), null)).isSucceeded(); + assertThat(secureTokenService.createToken(Map.of(AUDIENCE, audience, PRESENTATION_ACCESS_TOKEN_CLAIM, accessToken), null)).isSucceeded(); var captor = ArgumentCaptor.forClass(SharedSecretOauth2CredentialsRequest.class); verify(oauth2Client).requestToken(captor.capture()); @@ -105,7 +105,7 @@ void createToken_withAccessToken() { assertThat(request.getClientSecret()).isEqualTo(configuration.clientSecret()); assertThat(request.getParams()) .containsEntry(AUDIENCE_PARAM, audience) - .containsEntry(ACCESS_TOKEN, accessToken); + .containsEntry(PRESENTATION_ACCESS_TOKEN_CLAIM, accessToken); }); } diff --git a/spi/common/identity-trust-spi/src/main/java/org/eclipse/edc/identitytrust/SelfIssuedTokenConstants.java b/spi/common/identity-trust-spi/src/main/java/org/eclipse/edc/identitytrust/SelfIssuedTokenConstants.java index 7bfc072e31a..c13fcfae4bd 100644 --- a/spi/common/identity-trust-spi/src/main/java/org/eclipse/edc/identitytrust/SelfIssuedTokenConstants.java +++ b/spi/common/identity-trust-spi/src/main/java/org/eclipse/edc/identitytrust/SelfIssuedTokenConstants.java @@ -22,7 +22,7 @@ public final class SelfIssuedTokenConstants { /** * VP access token claim */ - public static final String ACCESS_TOKEN = "access_token"; + public static final String PRESENTATION_ACCESS_TOKEN_CLAIM = "access_token"; /** * Alias to be used in the sub of the VP access token @@ -33,7 +33,7 @@ public final class SelfIssuedTokenConstants { * Scopes to be encoded in the VP access token */ public static final String BEARER_ACCESS_SCOPE = "bearer_access_scope"; - + private SelfIssuedTokenConstants() { } diff --git a/spi/common/identity-trust-spi/src/testFixtures/java/org/eclipse/edc/identitytrust/TestFunctions.java b/spi/common/identity-trust-spi/src/testFixtures/java/org/eclipse/edc/identitytrust/TestFunctions.java index 6574dbcfa95..119d9cd00bc 100644 --- a/spi/common/identity-trust-spi/src/testFixtures/java/org/eclipse/edc/identitytrust/TestFunctions.java +++ b/spi/common/identity-trust-spi/src/testFixtures/java/org/eclipse/edc/identitytrust/TestFunctions.java @@ -36,6 +36,7 @@ import java.util.Map; import static java.time.Instant.now; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; public class TestFunctions { @@ -78,6 +79,7 @@ public static TokenRepresentation createJwt(String issuer, String subject) { var claimsSet = new JWTClaimsSet.Builder() .subject(subject) .issuer(issuer) + .claim(PRESENTATION_ACCESS_TOKEN_CLAIM, createJwt(new JWTClaimsSet.Builder().claim("scope", "fooscope").build()).getToken()) .expirationTime(new Date(new Date().getTime() + 60 * 1000)) .build(); return createJwt(claimsSet); diff --git a/system-tests/sts-api/sts-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/sts/api/RemoteStsEndToEndTest.java b/system-tests/sts-api/sts-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/sts/api/RemoteStsEndToEndTest.java index 628acdc05df..5a8307f318a 100644 --- a/system-tests/sts-api/sts-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/sts/api/RemoteStsEndToEndTest.java +++ b/system-tests/sts-api/sts-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/sts/api/RemoteStsEndToEndTest.java @@ -31,8 +31,8 @@ import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.ACCESS_TOKEN; import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.BEARER_ACCESS_ALIAS; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; import static org.eclipse.edc.junit.testfixtures.TestUtils.getFreePort; import static org.eclipse.edc.junit.testfixtures.TestUtils.testHttpClient; @@ -64,7 +64,7 @@ public class RemoteStsEndToEndTest extends StsEndToEndTestBase { } ); private final StsRemoteClientConfiguration config = new StsRemoteClientConfiguration(STS_TOKEN_PATH, "client_id", "client_secret"); - + private RemoteSecureTokenService remoteSecureTokenService; @BeforeEach @@ -116,7 +116,7 @@ void requestToken_withBearerScopeAndAlias() { .containsEntry(AUDIENCE, List.of(audience)) .containsEntry(CLIENT_ID, client.getClientId()) .containsKeys(JWT_ID, EXPIRATION_TIME, ISSUED_AT) - .hasEntrySatisfying(ACCESS_TOKEN, (accessToken) -> { + .hasEntrySatisfying(PRESENTATION_ACCESS_TOKEN_CLAIM, (accessToken) -> { assertThat(parseClaims((String) accessToken)) .containsEntry(ISSUER, client.getId()) .containsEntry(SUBJECT, bearerAccessAlias) @@ -134,7 +134,7 @@ void requestToken_withAttachedAccessToken() { var accessToken = "test_token"; var params = Map.of( AUDIENCE, audience, - ACCESS_TOKEN, accessToken); + PRESENTATION_ACCESS_TOKEN_CLAIM, accessToken); var client = initClient(config.clientId(), config.clientSecret()); @@ -147,7 +147,7 @@ void requestToken_withAttachedAccessToken() { .containsEntry(SUBJECT, client.getId()) .containsEntry(AUDIENCE, List.of(audience)) .containsEntry(CLIENT_ID, client.getClientId()) - .containsEntry(ACCESS_TOKEN, accessToken) + .containsEntry(PRESENTATION_ACCESS_TOKEN_CLAIM, accessToken) .containsKeys(JWT_ID, EXPIRATION_TIME, ISSUED_AT); }); } diff --git a/system-tests/sts-api/sts-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/sts/api/StsApiEndToEndTest.java b/system-tests/sts-api/sts-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/sts/api/StsApiEndToEndTest.java index 229f637dc62..6cffd9b7553 100644 --- a/system-tests/sts-api/sts-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/sts/api/StsApiEndToEndTest.java +++ b/system-tests/sts-api/sts-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/sts/api/StsApiEndToEndTest.java @@ -30,7 +30,7 @@ import static io.restassured.RestAssured.given; import static io.restassured.http.ContentType.JSON; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.ACCESS_TOKEN; +import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM; import static org.eclipse.edc.junit.testfixtures.TestUtils.getFreePort; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.CLIENT_ID; @@ -126,7 +126,7 @@ void requestToken_withBearerScope() throws ParseException { .containsEntry(AUDIENCE, List.of(audience)) .containsEntry(CLIENT_ID, client.getClientId()) .containsKeys(JWT_ID, EXPIRATION_TIME, ISSUED_AT) - .hasEntrySatisfying(ACCESS_TOKEN, (accessToken) -> { + .hasEntrySatisfying(PRESENTATION_ACCESS_TOKEN_CLAIM, (accessToken) -> { assertThat(parseClaims((String) accessToken)) .containsEntry(ISSUER, client.getId()) .containsEntry(SUBJECT, audience) @@ -159,13 +159,13 @@ void requestToken_withAttachedAccessScope() throws IOException, ParseException { .body() .jsonPath().getString("access_token"); - + assertThat(parseClaims(token)) .containsEntry(ISSUER, client.getId()) .containsEntry(SUBJECT, client.getId()) .containsEntry(AUDIENCE, List.of(audience)) .containsEntry(CLIENT_ID, client.getClientId()) - .containsEntry(ACCESS_TOKEN, accessToken) + .containsEntry(PRESENTATION_ACCESS_TOKEN_CLAIM, accessToken) .containsKeys(JWT_ID, EXPIRATION_TIME, ISSUED_AT); }