Writing /volume1/Web/Public/dokuwiki/data/log/deprecated/2024-11-15.log failed

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

次のリビジョン
前のリビジョン
study:java:sharepointonline:implement1 [2021/07/15 09:14] – 作成 bananastudy:java:sharepointonline:implement1 [2021/07/16 00:04] (現在) – [Main class code] banana
行 1: 行 1:
 ====== SAML Security token 取得の実装 ====== ====== SAML Security token 取得の実装 ======
 ここでは、[[study:java:sharepointonline:poc|POC of consuming Sharepoint online]]のPOC段階2について、Javaの実装例を紹介します。 ここでは、[[study:java:sharepointonline:poc|POC of consuming Sharepoint online]]のPOC段階2について、Javaの実装例を紹介します。
 +{{keywords>Get SAML Security token from Sharepoint online}}
 ===== 動作環境について ===== ===== 動作環境について =====
 テスト環境についてですが、Java7(IBM J9 VM (build 2.6, JRE 1.7.0 Windows 7 amd64-64 Compressed References 20150701_255667 (JIT enabled, AOT enabled))で、テストを行いました。\\ テスト環境についてですが、Java7(IBM J9 VM (build 2.6, JRE 1.7.0 Windows 7 amd64-64 Compressed References 20150701_255667 (JIT enabled, AOT enabled))で、テストを行いました。\\
行 37: 行 37:
 httpclientとして、apacheのhttpclientを使用していますが、Okhttpを使っても構いません。\\ httpclientとして、apacheのhttpclientを使用していますが、Okhttpを使っても構いません。\\
 また、RestTemplateを使用するため、spring-webを導入しています。\\ また、RestTemplateを使用するため、spring-webを導入しています。\\
-特に注目しいのは、boucycastleライブラリです。bouncycastleライブラリを導入する理由については、Binary token取得のjava実装編で紹介します。+特に注目して欲しい のは、boucycastleライブラリです。bouncycastleライブラリを導入する理由については、Binary token取得のjava実装編で紹介します。 
 + 
 +===== Main class code ===== 
 +実装のメインになるコードを以下に示します。\\ 
 +<code java> 
 +  private static final ResourceBundle RSC = ResourceBundle.getBundle("com.app.sample.ws.application"); 
 +  private static final String STS_AUTH_ENDPOINT = "https://xxxxx.contoso.com/adfs/services/trust/2005/usernamemixed"; 
 + 
 +  private Map<String, String> namespacePrefixes = new HashMap<String, String>(); 
 +   
 +  static { 
 +    //register the prefix of NameSpace 
 +    namespacePrefixes.put("t", "http://schemas.xmlsoap.org/ws/2005/02/trust"); 
 +  } 
 + 
 +  public String receiveSamlSecurityToken() { 
 +    String _token = ""; 
 +    try { 
 +      //request entity 
 +      RequestEntity<String> _requestEntity = RequestEntity 
 +      .post(new URI(STS_AUTH_ENDPOINT)) 
 +      .header("content-type", "application/soap+xml; charset=utf-8"
 +      .body(buildSamlSecurityRequestEnvelope()); ★Point1 
 +      RestTemplate _restTemplate = new RestTemplate(); 
 +      _restTemplate.setRequestFactory(buildHttpComponentsClientHttpRequestFactory()); ★Point2 
 + 
 +      ResponseEntity<String> _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 = "//t:RequestedSecurityToken/*";   ★Point3 
 +      Node _tokenNode = getXPathExpression(XPATH_EXPRESSION).evaluateAsNode(_definitionDocument); 
 +      _token = nodeToXmlString(_tokenNode);   ★Point4 
 + 
 +      if ("".equals(_token)) { 
 +        logger.error("Unable to authenticate: empty token"); 
 +      } 
 + 
 +    } catch (Exception e) { 
 +      logger.error("failed to receive SAML security token", e); 
 +    } 
 +    return _token; 
 +  }//receiveSamlSecurityToken 
 + 
 +  //build SAML request envelope 
 +  private String buildSamlSecurityRequestEnvelope() { 
 +    //UserName token mapping 
 +    Map<String, String> _mapRequest = new HashMap<String, String>(); 
 +    _mapRequest.put("sts_auth_url", STS_AUTH_ENDPOINT); 
 +    _mapRequest.put("loginuser", RSC.getString("soap.auth.username")); 
 +    _mapRequest.put("loginpass", RSC.getString("soap.auth.password")); 
 +    //replace placeHolder 
 +    StringSubstitutor _substitutor = new StringSubstitutor(_mapRequest, "%(", ")"); 
 +    String _finalXMLRequest = _substitutor.replace(RSC.getString("soap.saml.token.request")); 
 + 
 +    return _finalXMLRequest; 
 +  }//buildSamlSecurityRequestEnvelope 
 + 
 +  private HttpComponentsClientHttpRequestFactory buildHttpComponentsClientHttpRequestFactory() throws Exception { 
 +    return HttpComponentsClientHttpRequestFactoryBuilder.build(); 
 +  } 
 + 
 +  //create xPathExpression 
 +  private XPathExpression getXPathExpression(String expression) { 
 +    XPathExpression _xPathExpressioin = XPathExpressionFactory.createXPathExpression(expression, namespacePrefixes); 
 +    return _xPathExpressioin; 
 +  } 
 + 
 +  //convert nodes to XML string 
 +  private String nodeToXmlString(Node node) throws Exception { 
 +    StringWriter _writer = new StringWriter(); 
 +    Transformer _transformer = TransformerFactory.newInstance().newTransformer(); 
 +    _transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); 
 +    _transformer.setOutputProperty(OutputKeys.INDENT, "no"); 
 +    _transformer.transform(new DOMSource(node), new StreamResult(_writer)); 
 + 
 +    return _writer.toString(); 
 +  } 
 + 
 +</code> 
 + 
 +★Point1\\ 
 +SAML requestメッセージを作成する部分になります。\\ 
 +SOAP Envelopeメッセージ(xml)は、application.propertiesに格納されています。\\ 
 +application.propertiesの中身を以下に示します。 
 +<code properties> 
 +soap.auth.username=Sharepointユーザーアカウント 
 +soap.auth.password=ユーザーパスワード 
 +soap.saml.token.request=<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action><a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand="1">%(sts_auth_url)</a:To><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:UsernameToken><o:Username>%(loginuser)</o:Username><o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">%(loginpass)</o:Password></o:UsernameToken></o:Security></s:Header><s:Body><t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"><wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><a:EndpointReference><a:Address>urn:federation:MicrosoftOnline</a:Address></a:EndpointReference></wsp:AppliesTo><t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType><t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType><t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType></t:RequestSecurityToken></s:Body></s:Envelope> 
 + 
 +</code> 
 + 
 +★Point2\\ 
 +HttpComponentsClientHttpRequestFactoryを作成する部分です。\\ 
 +ごく一般的設定になりますが、ポイントとしてUser-Agentの指定です。((User-Agentを指定する理由は、SharePointサイトからの調整を回避するためです。詳細は[[https://docs.microsoft.com/ja-jp/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online#how-to-decorate-your-http-traffic-to-avoid-throttling|調整を回避するために、http トラフィックを装飾する方法]]を参照してください。))\\ 
 +コードの一部分を以下に示します。 
 +<code java> 
 +public class HttpComponentsClientHttpRequestFactoryBuilder { 
 +  public static HttpComponentsClientHttpRequestFactory build() { 
 +    final int TIMEOUT = 5; 
 +    //create connection manager 
 +    PoolingHttpClientConnectionManager _cm = new PoolingHttpClientConnectionManager(); 
 +    _cm.setMaxTotal(128); //default 20 
 +    _cm.setDefaultMaxPerRoute(24); //default 2 
 + 
 +    //request configuration 
 +    RequestConfig _requestConfig = RequestConfig.custom() 
 + .setConnectTimeout(TIMEOUT * 1000) 
 + .setConnectionRequestTimeout(TIMEOUT * 1000) 
 +        .setSocketTimeout(TIMEOUT * 1000) 
 + .build(); 
 + 
 +    //create HttpClient 
 +    HttpClientBuilder _builder = HttpClientBuilder.create() 
 + .setUserAgent("NONISV|Contoso|Sharepoint-demo/1.0"
 + .setConnectionManager(_cm) 
 + .setDefaultRequestConfig(_requestConfig); 
 + 
 +    HttpComponentsClientHttpRequestFactory _factory = new HttpComponentsClientHttpRequestFactory(_builder.build()); 
 + 
 +    return _factory; 
 +  } 
 + 
 +
 +</code> 
 + 
 +★Point3\\ 
 +SAML:Assertionを取り出す部分です。 ResponseのXMLから<t:RequestedSecurityToken>elementをXPathを利用して取り出します。\\ 
 +elementがnamespaceのものならXPathExpression生成時、namespaceを渡す必要があります。\\ 
 + 
 +★Point4\\ 
 +取り出したSAML:Assertionは、Node(Pretty-type)です。POCでも触れましたが、Binary tokenを取得する際、渡すSAML:Assertionはraw-typeです。\\ 
 +そのため、ここでNodeをStringに変換しています。 
 + 
 +~~DISCUSSION~~ 
 + 

QR Code
QR Code study:java:sharepointonline:implement1 (generated for current page)