Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -211,21 +211,73 @@ 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 <b>App-To-App</b> 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 <b>App-To-App</b> communication scenarios.
* <p>
* <b>Hint:</b> This option is <b>mutually exclusive</b> 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 <a href=
* "https://help.sap.com/docs/cloud-identity-services/cloud-identity-services/consume-apis-from-other-applications?locale=en-US">Consuming
* APIs from Other Applications</a>
*/
@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 <b>App-To-App</b> communication scenarios.
* <p>
* <b>Hint:</b> This option is <b>mutually exclusive</b> 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 <a href=
* "https://help.sap.com/docs/cloud-identity-services/cloud-identity-services/consume-apis-from-other-applications?locale=en-US">Consuming
* APIs from Other Applications</a>
*/
@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 <b>App-To-App</b> communication
* scenarios when having dependencies to <i>different tenants</i> of the <i>same, multi-tenant</i> provider
* application (fan-out / 1-N).
* <p>
* <b>Hint:</b> This option is <b>mutually exclusive</b> 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 <a href=
* "https://help.sap.com/docs/cloud-identity-services/cloud-identity-services/consume-apis-from-other-applications?locale=en-US">Consuming
* APIs from Other Applications</a>
*/
@Nonnull
public static
OptionsEnhancer<?>
withProviderClient( @Nonnull final String providerClientId, @Nonnull final String providerTenantId )
{
return new IasCommunicationOptions(null, providerClientId, providerTenantId, null, null);
}

/**
Expand All @@ -243,7 +295,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);
}

/**
Expand All @@ -269,7 +321,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);
}

/**
Expand Down Expand Up @@ -315,6 +367,10 @@ public static class IasCommunicationOptions implements OptionsEnhancer<IasCommun
@Nullable
String applicationName;
@Nullable
String providerClientId;
@Nullable
String providerTenantId;
@Nullable
String consumerClientId;
@Nullable
String consumerTenantId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,15 @@ 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();
}
optionsBuilder.withTokenRetrievalParameter("resource", resource);
return;
}

if( o.getConsumerClientId() != null ) {
String value = "urn:sap:identity:consumer:clientid:" + o.getConsumerClientId();
if( o.getConsumerTenantId() != null ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,66 @@ void testClientIdWithTenantId()
PROVIDER_TENANT_ID));
}

@Test
void testProviderClientId()
{
@SuppressWarnings( "deprecation" )
final ServiceBindingDestinationOptions options =
ServiceBindingDestinationOptions
.forService(BINDING)
.withOption(IasOptions.withProviderClient("provider-client-id"))
.build();

final OAuth2PropertySupplier sut = IDENTITY_AUTHENTICATION.resolve(options);

assertThat(sut).isNotNull();
assertThat(sut.getTokenUri()).hasToString(PROVIDER_URL + "/oauth2/token");
assertThat(sut.getServiceUri()).hasToString(PROVIDER_URL);

final OAuth2Options oAuth2Options = sut.getOAuth2Options();
assertThat(oAuth2Options.skipTokenRetrieval()).isFalse();
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));
}

@Test
void testProviderClientIdWithTenantId()
{
@SuppressWarnings( "deprecation" )
final ServiceBindingDestinationOptions options =
ServiceBindingDestinationOptions
.forService(BINDING)
.withOption(IasOptions.withProviderClient("provider-client-id", "provider-tenant-id"))
.build();

final OAuth2PropertySupplier sut = IDENTITY_AUTHENTICATION.resolve(options);

assertThat(sut).isNotNull();
assertThat(sut.getTokenUri()).hasToString(PROVIDER_URL + "/oauth2/token");
assertThat(sut.getServiceUri()).hasToString(PROVIDER_URL);

final OAuth2Options oAuth2Options = sut.getOAuth2Options();
assertThat(oAuth2Options.skipTokenRetrieval()).isFalse();
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));
Comment on lines +647 to +649
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, the term provider is ambiguous in this context, and it becomes pretty apparent here 😅

  • In the context of Cloud SDK, provider typically means the BTP subaccount in which this currently running Java application is hosted, i.e. the provider tenant
  • In the context of IAS App2App, provider refers to the target system that is providing the API, and the currently running Java application acts as the consumer

I don't see an easy way to resolve this confusion, other than adding an explicit comment here that the difference apptid:provider-tenant-id vs. app_tid=PROVIDER_TENANT_ID is expected and intended.

}

@AllArgsConstructor
private enum MutualTlsForTechnicalProviderAuthenticationTest
{
Expand Down