はじめに
SAP BTPでSideBySideを行っている中、
SAPソリューションと連携を行う際、DestinationServiceに認証情報を定義し、DestinationServiceを用いてSAPソリューションのAPIをコールすることがあるかと思います。
今回はDestinationServiceに定義した認証情報毎にAPIの呼び出し方法をJavaでどのように実装するか投稿したいと思います。
Basic認証の場合
・SAP Cloud SDKを用いて、DestinationServiceに定義された情報を取得する
・取得した情報をもとにHttpClientを生成し、HttpClientを使ってHttpReqestを実行する
JAVAのコード例
// DestinationServiceに定義された情報を取得
HttpDestination destination = DestinationAccessor.getDestination(DESTINATION_NAME).asHttp();
// DestinationServiceに定義されたURL
String baseUrl = destination.getUri().toString();
// Destinationの情報からHttpClientを取得
HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
// 上記のhttpClientを用いてGet処理を実行
HttpGet request = new HttpGet(baseUrl + "/sap/opu/odata/sap/XXXX_SRV/XXXXEntity");
CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(request);
SAP Cloud SDKを使い、DestinationAccessor#getDestinationで
destinationの情報を取得すると、その中に認証情報もはいいてるので、
そのままHttpClient化→それを使用してHttpResponseを投げるといった単純なコードで
処理が可能です。
また、DestinationServiceにID/PWを定義するので、
ソースコードにID/PWを定義する必要もなく、ID/PW管理等余計な考慮も不要になります。
クライアント証明書の場合
・SAP Cloud SDKを用いて、DestinationServiceに定義された情報を取得する
・DestinationServiceに設定されている証明書を生成する
・HttpClientを生成し、作成時に証明を設定する
JAVAのコード例
// DestinationServiceに定義された情報を取得
HttpDestination destination = DestinationAccessor.getDestination(DESTINATION_NAME).asHttp();
// DestinationServiceに定義されたURL
String baseUrl = destination.getUri().toString();
// Destinationの情報からHttpClientを取得
HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
String keyStorePassword = destination.getKeyStorePassword().get().toString();
// 証明書情報(content)の取得
List<DestinationCertificate> certificateValue = (List<DestinationCertificate>) destination.get("certificates").get();
String contentValue = certificateValue.get(0).getContent().toString();
byte[] contentBytes = Base64.getDecoder().decode(contentValue);
// keyStoreのload
try (InputStream certInputStream = new ByteArrayInputStream(contentBytes)) {
keyStore.load(certInputStream, keyStorePassword.toCharArray()); }
// SSLContextの構築
SSLContext sslContext = SSLContextBuilder.create()
.loadKeyMaterial(keyStore, keyStorePassword.toCharArray())
.build();
// HttpClientの生成
HttpClient client = HttpClients.custom()
.setSSLContext(tsslContext)
.build();
// 上記のhttpClientを用いてGet処理を実行
HttpGet request = new HttpGet(baseUrl + "/sap/opu/odata/sap/XXXX_SRV/XXXXEntity");
CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(request);
Basic認証の時と違い、Destinationから生成するHttpClientでは、証明書を送付していないような動きとなってしまい、認証エラーとなったので、
別でSSLContextの生成と、HttpClientの生成を行いました。
DestinationServiceから証明書を取得する際は、Base64形式であることや
SSLContext生成時にIOが発生する。
HttpClientを独自に行わないといけないので、TimeOut設定等が必要になる。
(上記のサンプルコードはTimeOut設定は記載していない)
等の考慮が必要ですが、こちらも証明書やパスフレーズをソース上に管理する必要が無く、証明書の更新等はService上で行うことができプログラム側の影響が少なくすみます。
SAML Bearer Assertion (OAuth2.0) Authenticationの場合
・JavaへReqest時に送付されるTokenを用いてDestinationServiceに定義された情報を取得する
・取得した情報をもとにHttpClientを生成し、HttpClientを使ってHttpReqestを実行する
// TokenよりをJWTにでコードし、認証Tokenを取得
DecodedJWT decodedJWT = JWT.decode(token.getAppToken());
AuthToken authToken = new AuthToken(decodedJWT);
// 認証Tokenを用いてDestinationServiceより定義を取得
HttpDestination destination = AuthTokenAccessor.executeWithAuthToken(authToken,
() -> DestinationAccessor.getDestination(DESTINATION_NAME)).asHttp();
// DestinationServiceに定義されたURL
String baseUrl = destination.getUri().toString();
@SuppressWarnings("unchecked")
List<DestinationAuthToken> authTokensValue = (List<DestinationAuthToken>) destination.get("authTokens").get();
String accessToken = authTokensValue.get(0).getValue();
// HttpClientの生成
HttpClient httpClient = HttpClients.createDefault();
HttpPost postRequest = new HttpPost(baseUrl + "/sap/opu/odata/sap/XXXX_SRV/XXXXEntity"););
postRequest.setEntity(new StringEntity(payLoads.toString(), "UTF-8"));
postRequest.addHeader("Authorization", "Bearer " + accessToken);
httpClient.execute(postRequest);
SAML Bearer Assertion (OAuth2.0) Authenticationを使う場合は、
Cloud Identity Services(IAS)でユーザ管理し、SAP BTPとS/4HanaやSuccessFactorsがIAS管理のもとSSO認証ができる状態になっているのが大前提ではあり、DestinationServiceの定義も少し複雑ではありますが、SAPソリューション側の権限に則したデータ登録、取得が可能になります。
まとめ
Basic認証やクライアント証明書はSAPソリューションに限らず登場すると思いますが、
SAML Bearer Assertionを用いた認証はS/4HanaやSuccessFactorsとSSO認証がIASを用いて容易にできるBTPならではの認証方式かと思います。
SAPUI5(Fiori)から直接コールする場合はDestinationServiceの定義だけでよかったのですが、SAPUI5(Fiori)→JAVA→SAPソリューションの流れでAPIをコールする時に苦労したので、今回記事にしました。
別途JAVAでToken(ユーザ情報)の取得する処理は以下に投稿しているので、こちらも参考にしていただければと思います。
https://qiita.com/kojirousan/items/029f10f1809ace2cecfd