Skip to content

Commit c468a17

Browse files
authored
feat: Extend error message for 401 errors (#827)
Co-authored-by: Jonas Israel <jonas.israel@sap.com>
1 parent 86da7c9 commit c468a17

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

cloudplatform/connectivity-oauth/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/OAuth2Service.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.sap.cloud.security.config.ClientIdentity;
3737
import com.sap.cloud.security.token.Token;
3838
import com.sap.cloud.security.xsuaa.client.DefaultOAuth2TokenService;
39+
import com.sap.cloud.security.xsuaa.client.OAuth2ServiceException;
3940
import com.sap.cloud.security.xsuaa.client.OAuth2TokenResponse;
4041
import com.sap.cloud.security.xsuaa.client.OAuth2TokenService;
4142

@@ -190,7 +191,21 @@ private OAuth2TokenResponse executeClientCredentialsFlow( @Nullable final Tenant
190191
tenantSubdomain,
191192
additionalParameters,
192193
false))
193-
.getOrElseThrow(e -> new TokenRequestFailedException("Failed to resolve access token.", e));
194+
.getOrElseThrow(e -> buildException(e, tenant));
195+
}
196+
197+
private TokenRequestFailedException buildException( @Nonnull final Throwable e, @Nullable final Tenant tenant )
198+
{
199+
String message = "Failed to resolve access token.";
200+
// In case where tenant is not the provider tenant, and we get 401 error, add hint to error message.
201+
if( e instanceof OAuth2ServiceException
202+
&& ((OAuth2ServiceException) e).getHttpStatusCode().equals(401)
203+
&& tenant != null ) {
204+
message +=
205+
" In case you are accessing a multi-tenant BTP service on behalf of a subscriber tenant, ensure that the service instance"
206+
+ " is declared as dependency to SaaS Provisioning Service or Subscription Manager (SMS) and subscribed for the current tenant.";
207+
}
208+
return new TokenRequestFailedException(message, e);
194209
}
195210

196211
private void setAppTidInCaseOfIAS( @Nullable final String tenantId )

cloudplatform/connectivity-oauth/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/OAuth2IntegrationTest.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@
22

33
import static java.util.Map.entry;
44

5+
import static com.github.tomakehurst.wiremock.client.WireMock.absent;
56
import static com.github.tomakehurst.wiremock.client.WireMock.containing;
67
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
78
import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
89
import static com.github.tomakehurst.wiremock.client.WireMock.post;
910
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
1011
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
12+
import static com.github.tomakehurst.wiremock.client.WireMock.unauthorized;
1113
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
1214
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
1315
import static com.sap.cloud.sdk.cloudplatform.connectivity.ServiceBindingTestUtility.bindingWithCredentials;
1416
import static org.assertj.core.api.Assertions.assertThat;
17+
import static org.assertj.core.api.Assertions.assertThatCode;
1518

1619
import java.io.IOException;
1720
import java.net.URI;
@@ -33,11 +36,13 @@
3336
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
3437
import com.sap.cloud.environment.servicebinding.api.ServiceBinding;
3538
import com.sap.cloud.environment.servicebinding.api.ServiceIdentifier;
39+
import com.sap.cloud.sdk.cloudplatform.connectivity.exception.DestinationAccessException;
3640
import com.sap.cloud.sdk.cloudplatform.connectivity.exception.HttpClientInstantiationException;
3741
import com.sap.cloud.sdk.cloudplatform.tenant.DefaultTenant;
3842
import com.sap.cloud.sdk.cloudplatform.tenant.TenantAccessor;
3943
import com.sap.cloud.security.client.HttpClientFactory;
4044
import com.sap.cloud.security.config.ClientIdentity;
45+
import com.sap.cloud.security.xsuaa.client.OAuth2ServiceException;
4146

4247
import io.vavr.control.Try;
4348

@@ -152,6 +157,55 @@ void testIasTokenFlow()
152157
}
153158
}
154159

160+
@Test
161+
void testExtended401ErrorMessage()
162+
{
163+
final ServiceBinding binding =
164+
bindingWithCredentials(
165+
ServiceIdentifier.DESTINATION,
166+
entry("credential-type", "binding-secret"),
167+
entry("clientid", "myClientId2"),
168+
entry("clientsecret", "myClientSecret2"),
169+
entry("uri", "http://provider.destination.domain"),
170+
entry("url", "http://provider.destination.domain"));
171+
final ServiceBindingDestinationOptions options = ServiceBindingDestinationOptions.forService(binding).build();
172+
173+
final Try<HttpDestination> maybeDestination =
174+
new OAuth2ServiceBindingDestinationLoader().tryGetDestination(options);
175+
assertThat(maybeDestination.isSuccess()).isTrue();
176+
final HttpDestination destination = maybeDestination.get();
177+
178+
{
179+
// provider case - no tenant:
180+
// Here, the short error message is returned.
181+
stubFor(
182+
post("/oauth/token")
183+
.withHost(equalTo("provider.destination.domain"))
184+
.withHeader("X-zid", absent())
185+
.willReturn(unauthorized()));
186+
assertThatCode(destination::getHeaders)
187+
.isInstanceOf(DestinationAccessException.class)
188+
.hasMessageEndingWith("Failed to resolve access token.")
189+
.hasRootCauseInstanceOf(OAuth2ServiceException.class);
190+
}
191+
{
192+
// subscriber tenant:
193+
// Here, the error message contains a note about updating the SaaS registry.
194+
stubFor(
195+
post("/oauth/token")
196+
.withHost(equalTo("provider.destination.domain"))
197+
.withHeader("X-zid", equalTo("subscriber"))
198+
.willReturn(unauthorized()));
199+
200+
TenantAccessor.executeWithTenant(new DefaultTenant("subscriber", "subscriber"), () -> {
201+
assertThatCode(destination::getHeaders)
202+
.isInstanceOf(DestinationAccessException.class)
203+
.hasMessageEndingWith("subscribed for the current tenant.")
204+
.hasRootCauseInstanceOf(OAuth2ServiceException.class);
205+
});
206+
}
207+
}
208+
155209
@Test
156210
@DisplayName( "The subdomain should be replaced for subscriber tenants when using IAS and ZTIS" )
157211
void testIasFlowWithZeroTrustAndSubscriberTenant()

0 commit comments

Comments
 (0)