From 89b82145124c3d27e6e6d9e82eb9c0621123fa3b Mon Sep 17 00:00:00 2001 From: Markus Perndorfer Date: Fri, 24 Oct 2025 16:17:12 +0200 Subject: [PATCH 1/2] feat: support provider:client for IAS app-to-app SAP-internal: https://github.wdf.sap.corp/pages/CPSecurity/sci-dev-guide/docs/Authentication/Exposing-APIs#consumer-consuming-apis --- .../connectivity/BtpServiceOptions.java | 61 ++++++++++++++++--- .../BtpServicePropertySuppliers.java | 9 +++ .../BtpServicePropertySuppliersTest.java | 60 ++++++++++++++++++ 3 files changed, 123 insertions(+), 7 deletions(-) diff --git a/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java b/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java index 3d06f4cc5..85a3ad177 100644 --- a/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java +++ b/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java @@ -211,21 +211,64 @@ public static OptionsEnhancer withoutTokenForTechnicalProviderUser() } /** - * Creates an {@link OptionsEnhancer} that instructs an IAS-based destination to use the given application - * provider name when performing token retrievals. This is needed in App-To-App communication scenarios. + * Creates an {@link OptionsEnhancer} that instructs an IAS-based destination to use the given "Dependency Name" + * when performing token retrievals. This is needed in App-To-App communication scenarios. *

* Hint: This option is mutually exclusive with {@link #withConsumerClient(String)}. * * @param applicationName - * The name of the application provider to be used. This is the name that was used to register the - * to-be-called application within the IAS tenant. + * The name of the "Dependency Name" to be used. This is the name that was used to register the + * dependency to an API of a provider application within the IAS tenant. * @return An instance of {@link OptionsEnhancer} that will lead to the given application provider being used * when retrieving an authentication token from the IAS service. + * + * @see Consuming APIs from Other Applications */ @Nonnull public static OptionsEnhancer withApplicationName( @Nonnull final String applicationName ) { - return new IasCommunicationOptions(applicationName, null, null); + return new IasCommunicationOptions(applicationName, null, null, null, null); + } + + /** + * Creates an {@link OptionsEnhancer} that instructs an IAS-based destination to use the given provider client ID + * when performing token retrievals. This is needed in App-To-App communication scenarios. + *

+ * Hint: This option is mutually exclusive with {@link #withConsumerClient(String)}. + * + * @param providerClientId + * Client ID of the provider application + * @return An instance of {@link OptionsEnhancer} that will lead to the given application provider being used + * when retrieving an authentication token from the IAS service. + * + * @see Consuming APIs from Other Applications + */ + @Nonnull + public static OptionsEnhancer withProviderClient( @Nonnull final String providerClientId ) + { + return new IasCommunicationOptions(null, providerClientId, null, null, null); + } + + /** + * Creates an {@link OptionsEnhancer} that instructs an IAS-based destination to use the given provider client ID + * and provider tenant ID when performing token retrievals. This is needed in App-To-App communication scenarios + * when having dependencies to different tenants of the same, multi-tenant provider application (fan-out / 1-N). + *

+ * Hint: This option is mutually exclusive with {@link #withConsumerClient(String)} + * + * @param providerClientId + * Client ID of the provider application + * @param providerTenantId + * Tenant ID of the provider application + * @return An instance of {@link OptionsEnhancer} that will lead to the given application provider being used + * when retrieving an authentication token from the IAS service. + * + * @see Consuming APIs from Other Applications + */ + @Nonnull + public static OptionsEnhancer withProviderClient( @Nonnull final String providerClientId, @Nonnull final String providerTenantId ) + { + return new IasCommunicationOptions(null, providerClientId, providerTenantId, null, null); } /** @@ -243,7 +286,7 @@ public static OptionsEnhancer withApplicationName( @Nonnull final String appl @Nonnull public static OptionsEnhancer withConsumerClient( @Nonnull final String consumerClientId ) { - return new IasCommunicationOptions(null, consumerClientId, null); + return new IasCommunicationOptions(null, null, null, consumerClientId, null); } /** @@ -269,7 +312,7 @@ public static OptionsEnhancer withConsumerClient( @Nonnull final String consu OptionsEnhancer withConsumerClient( @Nonnull final String consumerClientId, @Nonnull final String consumerTenantId ) { - return new IasCommunicationOptions(null, consumerClientId, consumerTenantId); + return new IasCommunicationOptions(null, null, null, consumerClientId, consumerTenantId); } /** @@ -315,6 +358,10 @@ public static class IasCommunicationOptions implements OptionsEnhancer Date: Fri, 24 Oct 2025 16:40:46 +0200 Subject: [PATCH 2/2] fix formatting --- .../connectivity/BtpServiceOptions.java | 27 ++++++++---- .../BtpServicePropertySuppliers.java | 8 ++-- .../BtpServicePropertySuppliersTest.java | 44 +++++++++---------- 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java b/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java index 85a3ad177..daf6edf89 100644 --- a/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java +++ b/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java @@ -222,7 +222,9 @@ public static OptionsEnhancer withoutTokenForTechnicalProviderUser() * @return An instance of {@link OptionsEnhancer} that will lead to the given application provider being used * when retrieving an authentication token from the IAS service. * - * @see Consuming APIs from Other Applications + * @see Consuming + * APIs from Other Applications */ @Nonnull public static OptionsEnhancer withApplicationName( @Nonnull final String applicationName ) @@ -231,8 +233,8 @@ public static OptionsEnhancer withApplicationName( @Nonnull final String appl } /** - * Creates an {@link OptionsEnhancer} that instructs an IAS-based destination to use the given provider client ID - * when performing token retrievals. This is needed in App-To-App communication scenarios. + * Creates an {@link OptionsEnhancer} that instructs an IAS-based destination to use the given provider client + * ID when performing token retrievals. This is needed in App-To-App communication scenarios. *

* Hint: This option is mutually exclusive with {@link #withConsumerClient(String)}. * @@ -241,7 +243,9 @@ public static OptionsEnhancer withApplicationName( @Nonnull final String appl * @return An instance of {@link OptionsEnhancer} that will lead to the given application provider being used * when retrieving an authentication token from the IAS service. * - * @see Consuming APIs from Other Applications + * @see Consuming + * APIs from Other Applications */ @Nonnull public static OptionsEnhancer withProviderClient( @Nonnull final String providerClientId ) @@ -250,9 +254,10 @@ public static OptionsEnhancer withProviderClient( @Nonnull final String provi } /** - * Creates an {@link OptionsEnhancer} that instructs an IAS-based destination to use the given provider client ID - * and provider tenant ID when performing token retrievals. This is needed in App-To-App communication scenarios - * when having dependencies to different tenants of the same, multi-tenant provider application (fan-out / 1-N). + * Creates an {@link OptionsEnhancer} that instructs an IAS-based destination to use the given provider client + * ID and provider tenant ID when performing token retrievals. This is needed in App-To-App communication + * scenarios when having dependencies to different tenants of the same, multi-tenant provider + * application (fan-out / 1-N). *

* Hint: This option is mutually exclusive with {@link #withConsumerClient(String)} * @@ -263,10 +268,14 @@ public static OptionsEnhancer withProviderClient( @Nonnull final String provi * @return An instance of {@link OptionsEnhancer} that will lead to the given application provider being used * when retrieving an authentication token from the IAS service. * - * @see Consuming APIs from Other Applications + * @see Consuming + * APIs from Other Applications */ @Nonnull - public static OptionsEnhancer withProviderClient( @Nonnull final String providerClientId, @Nonnull final String providerTenantId ) + public static + OptionsEnhancer + withProviderClient( @Nonnull final String providerClientId, @Nonnull final String providerTenantId ) { return new IasCommunicationOptions(null, providerClientId, providerTenantId, null, null); } diff --git a/cloudplatform/connectivity-oauth/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java b/cloudplatform/connectivity-oauth/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java index a812f6ffb..2833be740 100644 --- a/cloudplatform/connectivity-oauth/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java +++ b/cloudplatform/connectivity-oauth/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java @@ -210,10 +210,10 @@ private void attachIasCommunicationOptions( @Nonnull final OAuth2Options.Builder return; } - if (o.getProviderClientId() != null) { - String resource = "urn:sap:identity:application:provider:clientid:" + o.getProviderClientId(); - if (o.getProviderTenantId() != null) { - resource += ":apptid:" + o.getProviderTenantId(); + if( o.getProviderClientId() != null ) { + String resource = "urn:sap:identity:application:provider:clientid:" + o.getProviderClientId(); + if( o.getProviderTenantId() != null ) { + resource += ":apptid:" + o.getProviderTenantId(); } optionsBuilder.withTokenRetrievalParameter("resource", resource); return; diff --git a/cloudplatform/connectivity-oauth/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliersTest.java b/cloudplatform/connectivity-oauth/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliersTest.java index da958e1be..b86fde18b 100644 --- a/cloudplatform/connectivity-oauth/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliersTest.java +++ b/cloudplatform/connectivity-oauth/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliersTest.java @@ -594,10 +594,10 @@ void testProviderClientId() { @SuppressWarnings( "deprecation" ) final ServiceBindingDestinationOptions options = - ServiceBindingDestinationOptions - .forService(BINDING) - .withOption(IasOptions.withProviderClient("provider-client-id")) - .build(); + ServiceBindingDestinationOptions + .forService(BINDING) + .withOption(IasOptions.withProviderClient("provider-client-id")) + .build(); final OAuth2PropertySupplier sut = IDENTITY_AUTHENTICATION.resolve(options); @@ -610,13 +610,13 @@ void testProviderClientId() assertThat(oAuth2Options.getClientKeyStore()).isNotNull(); assertThatClientCertificateIsContained(oAuth2Options.getClientKeyStore()); assertThat(oAuth2Options.getAdditionalTokenRetrievalParameters()) - .containsExactlyInAnyOrderEntriesOf( - Map - .of( - "resource", - "urn:sap:identity:application:provider:clientid:provider-client-id", - "app_tid", - PROVIDER_TENANT_ID)); + .containsExactlyInAnyOrderEntriesOf( + Map + .of( + "resource", + "urn:sap:identity:application:provider:clientid:provider-client-id", + "app_tid", + PROVIDER_TENANT_ID)); } @Test @@ -624,10 +624,10 @@ void testProviderClientIdWithTenantId() { @SuppressWarnings( "deprecation" ) final ServiceBindingDestinationOptions options = - ServiceBindingDestinationOptions - .forService(BINDING) - .withOption(IasOptions.withProviderClient("provider-client-id", "provider-tenant-id")) - .build(); + ServiceBindingDestinationOptions + .forService(BINDING) + .withOption(IasOptions.withProviderClient("provider-client-id", "provider-tenant-id")) + .build(); final OAuth2PropertySupplier sut = IDENTITY_AUTHENTICATION.resolve(options); @@ -640,13 +640,13 @@ void testProviderClientIdWithTenantId() assertThat(oAuth2Options.getClientKeyStore()).isNotNull(); assertThatClientCertificateIsContained(oAuth2Options.getClientKeyStore()); assertThat(oAuth2Options.getAdditionalTokenRetrievalParameters()) - .containsExactlyInAnyOrderEntriesOf( - Map - .of( - "resource", - "urn:sap:identity:application:provider:clientid:provider-client-id:apptid:provider-tenant-id", - "app_tid", - PROVIDER_TENANT_ID)); + .containsExactlyInAnyOrderEntriesOf( + Map + .of( + "resource", + "urn:sap:identity:application:provider:clientid:provider-client-id:apptid:provider-tenant-id", + "app_tid", + PROVIDER_TENANT_ID)); } @AllArgsConstructor