====== Binary token取得の実装 ======
本稿では、[[study:java:sharepointonline:implement1|SAML Security token 取得の実装]]に続き、Binary token取得処理の実装について、紹介します。\\
動作環境については、上記ページに紹介してありますので、割愛します。
{{keywords>Get Binary token Sharepoint online}}
===== Mainコード =====
実装コードのメインとなる部分を以下に示します。
private static final ResourceBundle RSC = ResourceBundle.getBundle("com.app.sample.ws.application");
private static final String CUSTOM_STS_ENDPOINT = "https://login.microsoftonline.com/extSTS.srf";
private Map namespacePrefixes = new HashMap();
static {
//register the prefix of NameSpace
namespacePrefixes.put("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
}
public String receiveBinarySecurityToken(String samlAssertion) {
String _token = "";
try {
//request entity
RequestEntity _requestEntity = RequestEntity
.post(new URI(CUSTOM_STS_ENDPOINT))
.header("content-type", "application/soap+xml; charset=utf-8")
.body(buildBinaryTokenRequestEnvelope(samlAssertion)); ★ポイント1
RestTemplate _restTemplate = new RestTemplate();
_restTemplate.setRequestFactory(buildProxyClientHttpRequestFactory()); ★ポイント2
ResponseEntity _responseEntity = _restTemplate.exchange(_requestEntity, String.class);
DOMResult _result = new DOMResult();
Transformer _transformer = TransformerFactory.newInstance().newTransformer();
_transformer.transform(new StringSource(_responseEntity.getBody()), _result);
Document _definitionDocument = (Document) _result.getNode();
final String XPATH_EXPRESSION = "//wsse:BinarySecurityToken"; ★ポイント3
_token = getXPathExpression(XPATH_EXPRESSION).evaluateAsString(_definitionDocument);
if ("".equals(_token)) {
logger.error("Unable to authenticate: empty token");
}
} catch (Exception e) {
logger.error("failed to receive binary security token", e);
}
return _token;
}//receiveBinarySecurityToken
//build Binary token request envelope
private String buildBinaryTokenRequestEnvelope(String samlAssertion) {
//SAML Assertion mapping
Map _mapRequest = new HashMap();
_mapRequest.put("samltoken", samlAssertion);
_mapRequest.put("siteurl", RSC.getString("site.url"));
//replace placeHolder
StringSubstitutor _substitutor = new StringSubstitutor(_mapRequest, "%(", ")");
String _finalXMLRequest = _substitutor.replace(RSC.getString("soap.binary.token.request"));
return _finalXMLRequest;
}//buildBinaryTokenRequestEnvelope
//build HttpComponentsClientHttpRequestFactory for PROXY connection
private HttpComponentsClientHttpRequestFactory buildProxyClientHttpRequestFactory() throws Exception {
return ProxyClientHttpRequestFactoryBuilder.build());
}
//create XPathExpression
private XPathExpression getXPathExpression(String expression) {
XPathExpression _xPathExpressioin = XPathExpressionFactory.createXPathExpression(expression, namespacePrefixes);
return _xPathExpressioin;
}
★ポイント1\\
SOAPリクエストメッセージを作成する部分です。\\
%(samltoken)部分をSAML security token(SAML Assertion)に置換します。\\
%(siteurl)部分は、SharepointサイトURLに置換します。\\
appliction.propertiesの一部分を以下に示します。
site.url=SharepointサイトURL
soap.binary.token.request=http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issuehttp://www.w3.org/2005/08/addressing/anonymous%(samltoken)%(siteurl)http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKeyhttp://schemas.xmlsoap.org/ws/2005/02/trust/Issueurn:oasis:names:tc:SAML:1.0:assertion
★ポイント2\\
ここからの処理は外部サイトにアクセスするので、Proxy環境にある場合はProxy設定と、Https通信設定が必要です。\\
詳細は次節を参照してください。
★ポイント3\\
レスポンスXMLから、XPathを利用してBinary tokenを抽出します。\\
wsse:BinarySecurityToken項目がnamespaceのものなので、XPathExpression生成時namespaceを渡す必要があります。
===== ProxyClientHttpRequestFactoryBuilderクラス =====
ProxyClientHttpRequestFactoryBuilderクラスのコードを以下に示します。
public class ProxyClientHttpRequestFactoryBuilder {
private static final String PROXY_HOST = "proxy.sample.com";
private static final int PROXY_PORT = 8080;
public static HttpComponentsClientHttpRequestFactory build() throws Exception {
HttpHost _proxy = new HttpHost(PROXY_HOST, PROXY_PORT );
final int TIMEOUT = 5;
//request configuration
RequestConfig _reqConfig = RequestConfig.custom()
.setConnectTimeout(TIMEOUT * 1000)
.setSocketTimeout(TIMEOUT * 1000)
.setConnectionRequestTimeout(TIMEOUT * 1000)
.setProxy(_proxy) ★ポイント1
.build();
BouncyCastleFipsProviderHelper.setUpProvider(); ★ポイント2
//setup SSLContext(BouncyCastle provider)
SSLContext _sslContext = SSLContexts.custom()
.setProvider(new BouncyCastleJsseProvider(true)) ★ポイント3
.build();
SSLConnectionSocketFactory _sslSocketFactory = new SSLConnectionSocketFactory(_sslContext,
new String[]{"TLSv1.2"},
new String[]{"SSL_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", ★ポイント4
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"}, //key length=128制限があるため
new DefaultHostnameVerifier());
Registry _socketFactoryRegistry = RegistryBuilder.create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", _sslSocketFactory)
.build();
PoolingHttpClientConnectionManager _cm = new PoolingHttpClientConnectionManager(_socketFactoryRegistry);
_cm.setMaxTotal(200);
_cm.setDefaultMaxPerRoute(100);
//create HttpClient
HttpClient _client = HttpClientBuilder.create()
.setUserAgent("NONISV|Nskcom|Sharepoint-demo/1.0") //NONISV|CompanyName|AppName/Version
.setConnectionManager(_cm)
.disableRedirectHandling()
.setDefaultRequestConfig(_reqConfig)
.build();
HttpComponentsClientHttpRequestFactory _factory = new HttpComponentsClientHttpRequestFactory(_client);
return _factory;
}//build
}
★ポイント1
HTTP Proxyを設定する部分です。ID/Password認証は必要ありません。
★ポイント2
Bouncy CastleプロバイダーをSecurity Providerとして登録する部分です。\\
詳細については、[[study:java:sharepointonline:implement2|3rd Party Security Providerの導入について]]を参照してください。
★ポイント3
FIPSモードとしてBouncy castleプロバイダーを設定します。
★ポイント4
Cipher Suiteを指定します。 Java 7環境では、key size制限(128)があるため、Sharepointサイト要求のCipher Suiteから128lengthのみを選択します。\\
この指定がないと、「java.security.InvalidKeyException: Illegal key size」エラーが発生します。
~~DISCUSSION~~