SharePoint Onlineについて調査、検討



 ・目的
  Cordova等のモバイルクライアントから非対話ベースでSharePointへログインし、
  SharePointリストへのRead/Writeを行う


 ・着手、調査
  https://blogs.msdn.microsoft.com/tsmatsuz/2013/07/11/native-application-mobile-app-azure-active-directory-login-authentication/
  oauth2手順でaccess_tokenを取得し、それを元にREST APIを実行する。
  grant_type = passwordで認証を行うことで可能だということは分かった。
  ただしこの手順は非推奨であり、二段階認証が不可となるなど考慮すべき点がある。


  この手順を行う前に、予め認証を行うための口としてのアプリを登録する必要がある。
  https://blogs.msdn.microsoft.com/tsmatsuz/2014/06/02/office-365-api/


  以下の手順でアプリに権限とスコープを定義する
  https://buchizo.wordpress.com/2017/01/25/sharepoint-online-%E3%81%AB%E3%82%A2%E3%83%97%E3%83%AA%E3%81%8B%E3%82%89%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B/


 ・実行(Postman)


  ・認証を実行する
   URL:https://login.microsoftonline.com/common/oauth2/token


   POST:
   { grant_type:'password'
    , client_id:{上記アプリの登録で得たclient_id}
    , client_secret:{上記同client_secret}
    , username:{Office365のユーザ名}
    , password:{パスワード}
    , redirect_uri: {認証後リダイレクトするURL}
    , resource:{上記アプリの登録で得たclient_id}


   resourceは何を指定する必要があるのか意味不明だったが、上記で調べた通りに入れると
   「client_idと同じものを入れてください」的な英語エラーが出るのでこうしている。
   色々調べたが設定すべきパラメータがバラバラで参考にならない。


  ・実行結果
   →OK。access_token取得できる。


  ・REST API(例)
   https://{テナント名}.sharepoint.com/sites/Monaca/_api/web/lists/getbytitle('List')/items
   
   GET:
   Authorization:Bearer + " " + 認証で得たaccess_token
   Accept:application/json;odata=verbose


  ・実行結果
   →エラー。401。主旨不明。詳細不明。


   {"error_description":"Exception of type 'Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException' was thrown."}
   
   www-authenticate →Bearer realm="d6ab9302-8c72-4f6b-b728-96ba9a7642e8",client_id="00000003-0000-0ff1-ce00-000000000000",
   trusted_issuers="00000001-0000-0000-c000-000000000000@*,https://sts.windows.net/*/,00000003-0000-0ff1-ce00-000000000000@90140122-8516-11e1-8eff-49304924019b",
   authorization_uri="https://login.windows.net/common/oauth2/authorize"
   x-content-type-options →nosniff
   x-frame-options →SAMEORIGIN
   x-ms-diagnostics →3000003;reason="Invalid audience Uri 'e5cfc728-cb6b-4736-ba65-dd563042d5de'.";category="invalid_client"


 ・原因切り分け
  Postmanを使用しているからではないか、という切り分けのためにブラウザで検証


 ・実行(ブラウザ、通常のajax)
  基本的にやることは同じ。


  ・認証を実行する


   $.ajax({
    url: 'https://login.microsoftonline.com/common/oauth2/token',
    type: 'POST',
    dataType: 'json',
    data: data,
    headers: {
      'Accept': 'application/json;odata=verbose',
      'Content-Type': 'application/x-www-form-urlencoded',
    },
   }).done(function(data){
     alert("ok");
   }).fail(function(XMLHttpRequest, textStatus, errorThrown) {
     alert("error");
   })


  ・実行結果
   → エラー。
   No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null'
   内容としては表示された通りなのですが、サーバサイド(SharePoint Online)でカスタムヘッダを
   追加する手段は無いので、クロスドメイン問題をクリアしなければならない様子。
   (同一要求元ではないため、モダンブラウザはすべてこうなる)


  ・結論
   この時点で、一般的なモダンブラウザから非対話での認証+REST API実行は不可との認識。
   ブラウザでなくネイティブコードで記述する分には回避可能と思われる。


 ・他の手順で実行(SP.js) ※MS謹製のJavascriptライブラリ群


  ・認証を実行する
   MSのサイト記述、各サンプルに「認証」用の関数は明示されておらず認証自体は通常の
   Office認証画面をiframe等で表示し、セッションを確立する必要があると思われる
   ※未確認。それらしい記述ははっきりと明示されていない。


  ・REST API
   基本的には下記の手順
   https://msdn.microsoft.com/ja-jp/library/office/fp179927.aspx?f=255&MSPPError=-2147217396


   コア部
   executor.executeAsync(
   {
     url:
       appweburl +
         "/_api/web/lists/getbytitle('List')/items",
     method: "GET",
     headers: { "Accept": "application/json; odata=verbose" },
     success: onQuerySucceeded,
     error: onQueryFailed
   });


  ・実行結果
   → エラー。
   SP.RequestExecutor.js?_=1508838788373:2 Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://{テナントID}.sharepoint.com') does not match the recipient window's origin ('null').
   クロスドメイン回避手順になっているはずなのに、エラーとしてはクロスドメインである旨の表示になっている。


 ・総括
  ・非対話で認証+REST API実行が可能なのか確証が取れない。
   PowerShellで同様のことを行っている例はあり、不可能ではないハズなのだが、原因を特定できない。


  ・access_token + REST API実行でのエラー('Invalid_Client')について
   額面通りに受け取ると色々な原因が考えられるが、文献が少ない・曖昧・オンプレ用語が混在しており調査が難航。


   ・考えうる理由
    ・client_idが不正
     → アプリの登録手順は他になく、これを疑っても他に試すことが無い
    ・アプリの登録が不正
     → そもそも「アプリ」という名前で「登録」しているコレが何なのか意味不明である。
       昔は「アドイン」に相当したらしいがそれそのものが処理を行うわけでもないのに「アプリ」?
       「アドイン」?
       一応疑うべき項目としてredirect_urlが意味をなさないことぐらいだが、非対話ベースなので
       これに意味があるなら成立しない
    ・アプリの権限付与が不正
     → SharePoint Onlineリソースにフルコントロールを与えてもダメなので手詰まり
    ・やはりresource_idに意味がある
     → そもそも文献がバラバラで試す余地も少ないが現状で回避できた例が上記の=client_idのみなので、
       これもここで手詰まり。


   ・この手順については凍結


  ・sp.jsでの実行エラーについて


   ・考えうる理由
    → 「認証手順を踏んでいないため」というパターンは当然考えられるが「非対話で」を
      満たさなくなるため調査する意味なし


      サンプルの通り実装しているので正直どうしろと。


  ・テクニカルサポートを利用し、そもそもの目的は「可能なのか」「非推奨のリスクは」
   は確認しようと思ったのだが、SharePoint 「Online」のテクニカルサポートを受けるには
   MSDNプレミアサポートが必要ですぐにそれをクリアできない状況。


 ・私的な感想
  ・オンプレ版SharePointでは行えていた.asmx実装も不可であったり、SharePoint Online上の
   パブリックサイトの作成も不可になったり、MSとしては「枠にはまった使い方」以外は
   あまりしてほしく無いのだろうと思う。
   実際、Flowを駆使すると割と色々出来ることは調査のついでで分かった。が今回は技術検証の
   側面が強いので手段と目的が異なってしまうためFlowを採用することは無い。
  ・各所に英語直訳と思われる表現が見られたり、オンプレ版の表現が混ざったり著しく過渡期感がある。
   サポートもSharePoint Onlineは一段上の扱いとなるため、オンプレ版でないならこのような実装は
   それらのリスクを加味して開始すべきである。