Written in collaboration with: Santosh Kumar
Previous Blogs:
- [Blog Series] X.509 certificate-based authentication(mTLS) – Demystified
- Generating X.509 certificates of BTP managed services
- Communicating with services using SAP destination service
Introduction:
This is the fourth blog in this blog post series. This blog will focus on how to communicate to various SAP BTP services which support x.509 certificate authentication using the VCAP environment variables.
Content:
- Analysing VCAP Environment variables of the service
- Fetching VCAP configuration in code
- Using the VCAP config to fetch certificate-based JWT bearer token
- Communicating to the service using the bearer token
- Summary
1) Analysing VCAP Environment variables of the service
We have already altered service binding with the example of archiving service in the blog Generating X.509 certificates of BTP managed services to enable X509 authentication.
Let’s look at the VCAP_SERVICES of the archiving service bound to our application.
- Go to the application bound to the archiving service and click on Environment Variables in the left tab.
- Scroll down and find the archiving service binding, and you’ll observe the uaa credentials as certificate-based.
- We can use these credentials to call the service endpoint. Let’s see how it’s done in the code
2) Fetching VCAP configuration in code
To call the archiving service, we would need a client ID, certificate, key, token URL and service endpoint, which we can fetch from the VCAP_SERVICES
- Define the following parameters in your application.yaml file under srv>main>resources.
archivingservice: clientid: ${vcap.services.data-archiving-service.credentials.uaa.clientid} certificate: ${vcap.services.data-archiving-service.credentials.uaa.certificate} key: ${vcap.services.data-archiving-service.credentials.uaa.key} archivingServiceUrl: ${vcap.services.data-archiving-service.credentials.archivingServiceUrl} uaadomain: ${vcap.services.data-archiving-service.credentials.uaa.uaadomain} space: ${vcap.application.space_name}
- Then, create a config class as below:
package com.sap.dataarchiving.config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @ConfigurationProperties("archivingservice") public class ArchivingServiceConfigParameters { /** * platform archiving service attributes */ private String archivingServiceUrl; private String uaadomain; private String clientId; private String certificate; private String key; private String space; public String getArchivingServiceUrl() { return archivingServiceUrl; } public void setArchivingServiceUrl(String archivingServiceUrl) { this.archivingServiceUrl = archivingServiceUrl; } public String getUaadomain() { return uaadomain; } public void setUaadomain(String uaadomain) { this.uaadomain = uaadomain; } public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } public String getCertificate() { return certificate; } public void setCertificate(String certificate) { this.certificate = certificate; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getSpace() { return space; } public void setSpace(String space) { this.space = space; } }
- Now, this class can be Autowired to fetch the relevant field values in code.
- For communicating with the archiving service, we just need to fetch the JWT token using the certificate and key. Then a WebClient call using the bearer token would be sufficient to communicate with the service.
3) Using the VCAP config to fetch certificate-based JWT bearer token
- To fetch the token, SAP Cloud SDK has provided an easier way. You can refer here for documentation.
- Code sample to fetch bearer token:
public OAuth2TokenResponse retrieveToken(String certificate, String key, String clientID, String url) { OAuth2ServiceConfigurationBuilder builder = OAuth2ServiceConfigurationBuilder.forService(Service.XSUAA); OAuth2ServiceConfiguration config = builder.withClientId(clientID).withCertificate(certificate).withPrivateKey(key) .withCertUrl(url).build(); XsuaaTokenFlows xs = new XsuaaTokenFlows( new DefaultOAuth2TokenService(HttpClientFactory.create(config.getClientIdentity())), new XsuaaDefaultEndpoints(config), config.getClientIdentity()); OAuth2TokenResponse token = null; try { token = xs.clientCredentialsTokenFlow().disableCache(true).execute(); } catch (IllegalArgumentException | TokenFlowException e) { LOGGER.error("Failed to fetch oauth token: {}, {}", e.getMessage(), e.getCause()); throw new CertificateOAuthException(e.getMessage()); } return token; }
4) Communicating to the service using the bearer token
- The token can now be used to communicate to the archiving service:
OAuth2TokenResponse token = certToken.retrieveToken(certificate,key,clientId,tokenURL); String tokenValue =token.getAccessToken(); WebClient newClient = client.mutate().filter(logResponse()).build(); Mono<String> resource = newClient.put() .uri(url) .headers(h -> h.setBearerAuth(tokenValue)) .bodyValue(archiveData) .retrieve() .bodyToMono(String.class) .retryWhen(Retry.backoff(3, Duration.ofSeconds(5))); String response = resource.block();
5) Summary:
In this blog, we have learnt how to access the bearer token in the Java application using the VCAP environment variables and to communicate with the archiving service using it.
Please let us know if you find this content helpful and share any inputs and feedback.