====== 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~~