-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: IAS App-to-Service Communication #331
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Progress looks good. I'm only concerned about
- customizability (for future JSON format changes)
- testability (for current event-broker JSON format)
...ud/sdk/cloudplatform/connectivity/IdentityAuthenticationServiceBindingDestinationLoader.java
Outdated
Show resolved
Hide resolved
return delegateLoader.tryGetDestination(optionsBuilder.build()); | ||
} | ||
|
||
private static boolean isIdentityAuthenticationServiceBinding( @Nonnull final ServiceBinding serviceBinding ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Comment)
I think this is fine for now. I wonder whether we'll need to make this an accessible / modifiable Predicate<ServiceBinding>
instead in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we are working together with the Event Broker colleagues (who are taking a front runner position in the entire IAS topic) to define a standard format for IAS-backed services, I'd hope that we can get around further configuration options in this implementation.
In other words: Services either adhere to our standard or won't be supported by the SDK. As we are the de-facto only library (AFAIK) in the entire SAP ecosystem to support IAS connectivity, I feel we are in a very strong position to "force" our standard onto service providers.
Nevertheless, I don't see any blockers for future extensibility of our implementation in case there are (once again) varying service binding formats.
...ud/sdk/cloudplatform/connectivity/IdentityAuthenticationServiceBindingDestinationLoader.java
Outdated
Show resolved
Hide resolved
@@ -1 +1,2 @@ | |||
com.sap.cloud.sdk.cloudplatform.connectivity.OAuth2ServiceBindingDestinationLoader | |||
com.sap.cloud.sdk.cloudplatform.connectivity.IdentityAuthenticationServiceBindingDestinationLoader |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Minor)
Until we have a JSON syntax aligned, let's disable the auto loading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any downside to having it loaded? I would argue the matching criteria of having an entry("authentication-service.service-label", "identity")
so so specific it is basically impossible to match it by accident to some existing binding..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initially, Alex and I discussed whether it would be a good idea to auto load this new implementation into all Cloud SDK applications without having a (somewhat) aligned standard for the Service Binding format.
However, as we further refined how we think those service bindings should look like, I'd agree that it doesn't really hurt to already load this new implementation.
...ud/sdk/cloudplatform/connectivity/IdentityAuthenticationServiceBindingDestinationLoader.java
Outdated
Show resolved
Hide resolved
if( !endpoint.requiresTokenForTechnicalAccess | ||
&& options.getOnBehalfOf() != OnBehalfOf.NAMED_USER_CURRENT_TENANT ) { | ||
optionsBuilder.withOption(BtpServiceOptions.IasOptions.withMutualTlsOnly()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering whether this is correct for the "current Tenant is subscriber" case... Probably not, right?
So it should be
if( !endpoint.requiresTokenForTechnicalAccess | |
&& options.getOnBehalfOf() != OnBehalfOf.NAMED_USER_CURRENT_TENANT ) { | |
optionsBuilder.withOption(BtpServiceOptions.IasOptions.withMutualTlsOnly()); | |
if( !endpoint.requiresTokenForTechnicalAccess | |
&& options.getOnBehalfOf() == OnBehalfOf.TECHNICAL_USER_PROVIDER ) { | |
optionsBuilder.withOption(BtpServiceOptions.IasOptions.withMutualTlsOnly()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, this implementation has been shifted towards the OAuth2PropertySupplier
as this class (the IdentityAuthenticationServiceBindingDestinationLoader
) cannot determine whether the current tenant is the provider.
Also see the changes for within the IasOptions
class for reference.
if( bindingView.endpoints.size() > 1 ) { | ||
log | ||
.warn( | ||
"The IAS-based service binding for service '{}' contains multiple HTTP endpoints. Only the first one will be used.", | ||
bindingView.serviceIdentifier); | ||
} | ||
|
||
return bindingView.endpoints.get(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussion
Should we already introduce some API for customers to select the endpoint they want? Or do we wait until we actually encounter a feature request?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Comment)
CAP reminded us; first element may not necessarily be consistent in JSON format.
Even in Java-case having LinkedHashMap
as deserialization object (maybe) it may not be consistent in service binding side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed: We are now throwing an DestinationAccessException
if there is not exactly one HTTP endpoint available.
This behavior will be changed when we introduce new API that lets customers pick the endpoint they want to connect to.
.../src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java
Outdated
Show resolved
Hide resolved
catch( final ValueCastException e ) { | ||
// the `service-label` entry is not a string | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Minor)
Please don't swallow exceptions, without a trace/debug log statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd argue that it doesn't provide any value if we were to log the exception here since it is a valid outcome that the authentication-service.service-label
is not a String (even though the chances are pretty minimal).
Unfortunately, we don't have any API within the SBL to check whether a field is of a certain type so that we have to rely on throwing and catching exception for the moment.
Personally, I'd be happy to introduce such new API, but I don't know if the benefit justifies the effort.
...ud/sdk/cloudplatform/connectivity/IdentityAuthenticationServiceBindingDestinationLoader.java
Outdated
Show resolved
Hide resolved
@@ -1 +1,2 @@ | |||
com.sap.cloud.sdk.cloudplatform.connectivity.OAuth2ServiceBindingDestinationLoader | |||
com.sap.cloud.sdk.cloudplatform.connectivity.IdentityAuthenticationServiceBindingDestinationLoader |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any downside to having it loaded? I would argue the matching criteria of having an entry("authentication-service.service-label", "identity")
so so specific it is basically impossible to match it by accident to some existing binding..
.../src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java
Outdated
Show resolved
Hide resolved
.../src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java
Outdated
Show resolved
Hide resolved
...ud/sdk/cloudplatform/connectivity/IdentityAuthenticationServiceBindingDestinationLoader.java
Outdated
Show resolved
Hide resolved
...ud/sdk/cloudplatform/connectivity/IdentityAuthenticationServiceBindingDestinationLoader.java
Outdated
Show resolved
Hide resolved
} | ||
|
||
try { | ||
return credentials.getMapView("authentication-service"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels a bit bad to have around 200 LoC just for loading a few JSON fields.. Personally I'd probably wrap some of this into a getOrDefault(str, default)
method, but not sure how much better that looks..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or we directly replace this with gson or jackson deserialization maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels a bit bad to have around 200 LoC just for loading a few JSON fields
Agreed. Let me see what I can do about it.
|
||
import io.vavr.control.Try; | ||
|
||
@Isolated( "because the tests manipulate the global default ServiceBindingAccessor" ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌🏼
.containsExactly(URI.create("https://foo.uri")); | ||
assertThat(delegateOptions.getOption(BtpServiceOptions.IasOptions.NoTokenForTechnicalProviderAccess.class)) | ||
.contains(true); | ||
assertThat(delegateOptions.getOption(BtpServiceOptions.IasOptions.IasCommunicationOptions.class)).isEmpty(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these assertions are the same as for the case above, right? If so, what does this test really assert, other than the behalf not impacting the assertions? Maybe we can reduce the code duplication between these test cases still a bit to make it clearer what the differences are between them?
...nnectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm 👍🏻
Context
SAP/cloud-sdk-java-backlog#373.
This PR adds a new
ServiceBindingDestinationLoader
implementation that is capable of dealing with (currently) imaginary service bindings from re-use services that use IAS for authentication.The suggested Service Binding format looks like this:
Feature scope:
Definition of Done
Documentation updatedRelease notes updated