2015年4月23日木曜日

[Office365]Officeクライアントで多要素認証(Outlook編)

昨年末に発表されたOffice2013 Windowsクライアント(Outlookなど)の多要素認証対応が2015年3月にPublic Previewになった、という話を書きましたが、ようやく試してみましたので簡単に紹介します。

関連ポスト)
・Office2013 Windowsクライアントが多要素認証とSAML IdPサポート
 http://idmlab.eidentity.jp/2014/11/office2013-windowssaml-idp.html
・[Office Preview]Outlook等の多要素認証サポート
 http://idmlab.eidentity.jp/2015/03/office-previewoutlook.html


簡単に言いますとOfficeクライアントがADAL(Active Directory Authentication Library)に対応した、というだけなのですが、Office Teamの公式Blogなどでは「Office Modern Authentication」なんて呼んでいます。

◆準備
以下の2点を事前に実施する必要があります。

①Office365のテナントに対してModern Authenticationを有効にしてもらう
 ⇒現在実施中のPublic Previewプログラムに参加する必要があります。参加するにはMicrosoft Connectサイトへの登録とアンケートへの回答が必要です。

②OfficeクライアントをインストールするPCのレジストリを変更する
 ⇒以下のキーを追加する必要があります。

レジストリ・キータイプ
HKCU\SOFTWARE\Microsoft\Office\15.0\Common\Identity\EnableADALREG_DWORD1
HKCU\SOFTWARE\Microsoft\Office\15.0\Common\Identity\VersionREG_DWORD1
HKCU\SOFTWARE\Microsoft\Office\15.0\Common\Debug\TCOTraceREG_DWORD3

  詳細は以下のURLに記載されています。
  https://support.office.com/en-us/article/Enable-Modern-Authentication-for-Office-2013-on-Windows-devices-7dc1c01a-090f-4971-9677-f1b192d6c910?ui=en-US&rs=en-US&ad=US


※詳細は公式blogをみてください。
 http://blogs.office.com/2015/03/23/office-2013-modern-authentication-public-preview-announced/


◆Outlookにアカウントを追加する
準備が出来たら早速試してみます。
今回は多要素認証を有効、かつAD FSとID連携しているアカウントを使ってExchange Onlineに接続してみます。

①Outlookを起動し、アカウント情報を入力する。
 この際、パスワードを入れずに[次へ]をクリックします。



②AD FSのログイン画面が表示されるのでログインする。


③多要素認証を行う。
 今回はOffice365側の多要素認証を有効にしているアカウントなので、Microsoft Azure Authenticatorアプリケーションで追加認証をします。


④アカウント設定が完了する
 これで設定は完了です。Outlookを再起動して使い始めましょう。



通常の使用についてはこれで問題ないと思うのですが、セキュリティ面からはOutlookを起動する都度認証をしたいところです。
ところが、アカウントの設定⇒セキュリティ設定で[ログオン情報を毎回入力する]を設定しようとしたのですが、グレーアウトされており設定できませんでした。


今のところ端末を紛失したら困りますね。。。発行したトークンの無効化をする様な画面も見当たらないですし。。
このあたりは少し改善が必要なポイントかも知れません。
(公式blogのコメント欄で同じ質問している人がいますが回答はないみたいです)

2015年4月22日水曜日

[MIM]新しいPublic Previewがリリース、MIM2016へ

新しいMicrosoft Identity Manager(MIM)のPreviewがリリースされました。
都合CTP4になりますが、公式Blogによるとベータ・クォリティとの記述があるので、ほぼ完成の域に近づいてきた、ということだと思います。

Active Directory Team Blog
 Microsoft Identity Manager Public Preview Updated
 http://blogs.technet.com/b/ad/archive/2015/04/21/microsoft-identity-manager-public-preview-updated.aspx

更新されたポイントはやはり特権アクセス管理(Privilege Access Manage/PAM)回りが中心ですが、Azure ADと連携したレポーティング機能についても更新されています。
(こちらはPrivate Preview)
また、今回のリリースからForefront Identity Manager 2010R2(FIM)からのインプレース・アップデートが出来るようになっているようなので、その点も注目です。

  1. Manual approval of elevation requests
  2. The ability to require a Multi-Factor Authentication challenge as part of an elevation request
  3. Improved security monitoring of your privileged forest
  4. Azure AD based reporting capabilities in the cloud


個人的には2番目の特権アクセスを多要素認証で取得するあたりがとても良い機能だと思います。


Connectサイトに登録すれば誰でもダウンロードできるので、FIM使いの方は是非試してみましょう。

2015年4月21日火曜日

[Google]4/20を迎えてAPIはどうなった?

# 2015/04/23現在
# ClientLogin : OK
# OpenID 2.0 : OK
# Provisioning API : NG - 503 Quota exceeded for the current request

GoogleのIdentityに関与している人なら少なからず気にしていた2015年4月20日を遂に迎えたわけですが、実際移行し忘れた人たちがどうなったのか、、、を確認してみたいと思います。

OpenID 2.0のサポート終了関連
 ⇒ Azure Access Control Services 2.0(ACS)

 関連ポスト)
  GoogleのOpenID 2.0サポート終了による影響いろいろ(Azure ACS編)
  http://idmlab.eidentity.jp/2015/03/googleopenid-20azure-acs.html

ClientLoginおよびProvisioning APIのサポート終了関連
 ⇒ Forefront Identity Manager(FIM)用のGoogle Apps管理エージェント(旧版)

 関連ポスト)
  [FIM]汎用REST管理エージェントをリリースしました
  http://idmlab.eidentity.jp/2015/03/fimrest.html


結論、4/21現在両方ともまだ使えました(笑)
(Azure ACSについては元々2015/6/1までは使える、と言っているので使えて当然ですが)


◆OpenID 2.0

ACSを使うサービスでログオンするとOpenID 2.0を使って認証しているのがわかります。


◆ClientLoginおよびProvisioning API

ClientLoginでGoogle Appsの管理者IDとパスワードを投げ込んでGoogle Auth Tokenを取得し、Provisoning APIへクエリを投げてユーザ一覧の取得が出来ています。





まぁ、いつ使えなくなってもおかしくないので早めに移行した方が良いですね。
(旧版のGoogle Apps管理エージェントのサポートがあるので、使えなくなったらどんな動きをするのか早く把握したい・・・)

2015年4月20日月曜日

[GoogleApps/AD FS]iOS8.3でのアカウント管理の改善

手元のiPadのOSを順番に8.3にアップデートしている中で気が付いたのですがiOSのメール・カレンダーなのでアカウントにSSO設定がされたGoogle Appsアカウントの設定が出来るようになっています。
地味なアップデートですが、エンタープライズでGoogle Appsを利用しているユーザにとっては実は大きな意味を持つアップデータなので、これまでの課題と本アップデートによる今後のID運用の可能性について考えてみたいと思います。

◆これまでの課題
ネイティブアプリにアプリケーション・パスワードを使いたいのに、SSOユーザではアプリケーション・パスワードは使えない!

実際設定してしまえば動くのですが、SSOと2段階認証の同時設定はサポートされていません

https://support.google.com/a/answer/175197?hl=ja


このことにより、iOS標準のアプリケーションを始め、OutlookなどのネイティブアプリケーションをSSOが有効なユーザでは使うことが出来ず、スマホからでもブラウザを使うか、Google製のGMailアプリケーションを使う必要がありました

当然スマホからブラウザベースでサービスを使うとオフラインでのアクセスが出来なかったり、ユーザ・インターフェイスの面でかなりの苦痛があったりと実用性の面ではかなりの課題がありました。
(そのためにSecure Browserソリューションが流行っているんだと思います)

また、Google製のアプリケーションを使う場合、あくまでブラウザベースでのログイン(Cookieベース)なので、紛失した端末だけ強制ログアウトする、ということが出来ず、すべてのブラウザセッションを無効化することになってしまいます。(他の端末やPCのブラウザを含めすべてログオフされてしまう)


◆iOS8.3での改善
⇒標準メール・カレンダー等のアカウントへの外部IdPでの認証がサポートされ、認可がOAuthベースとなったことにより、SSOユーザでも標準アプリケーションが利用できる!

・認証)外部IdPのサポート
 ⇒Google側での2段階認証を使わなくてもIdP側で多要素認証を実装することでより柔軟な構成が可能

・認可)OAuthのサポート
 ⇒クライアント(アプリケーション)単位で権限委譲を取り消すことが可能なので、アプリケーション・パスワードと同じく、端末やアプリケーション単位で利用を不可能に出来る。(全セッションをクリアする必要がなくなる)


◆実際の動作と設定
早速試してみます。

まず、iOSの設定からGoogleアカウントを追加します。


Googleのログイン画面が出てくるので、SSOが有効なドメインのユーザ名のみを入力して[ログイン]をクリックします。


するとGoogle Appsに設定してある外部IdP(今回はAD FS)のログイン画面に遷移するのでIdPにログインします。
必要に応じて外部IdPに多要素認証を設定するとよりセキュアです。


認証に成功すると、iOSに対して認可をするかどうかの同意画面が表示されるので必要な権限を委譲します。



これでSSOユーザで標準アプリケーションが利用可能となります。



では、今度は端末を紛失したことを想定し、アプリケーションを利用できない様にしてみます。
方法としては、管理者による取り消しと利用者自身による取り消しの両方が可能ですが、今回は利用者自身で権限を取り消してみます。
ブラウザでサービスにログインした状態で画面右上のアカウント設定を開き、接続されたアプリとサービスのアカウント権限をクリックします。



すると、アクセス権を与えたiOSが出てきますので、[アクセス権を取り消す]をクリックします。



アプリケーションで送受信などの操作をするとエラーが表示され、再度認証をするように求められるためアプリケーションが利用できなくなります。


※ただし、すでにローカルにダウンロードしてしまったコンテンツについては引き続き閲覧可能なので、リモート・ワイプなどとの組み合わせは必要です(アプリケーション・パスワードの場合も同様)


これまではGoogle製のアプリケーションを別途導入したり、サードパーティのソリューションを使う必要があったことを考えると端末管理の観点からもかなり有効な解決策となっていると思います。

課題は各端末をiOS8.3にアップデートするところになるとは思いますが・・・

2015年4月13日月曜日

[FIM/MIM]ビルトインの管理ポリシールールの拡張

今年夏にリリースされる予定のMicrosoft Identity Manager 2015(MIM)では特権アカウント管理に関する各種の機能拡張が行われています。

今回はMIM Serviceの管理ポリシールール(Management Policy Rule/MPR)が現行バージョンであるForefront Identity Manager 2010R2 SP1(FIM)とどのように変わったのかを見てみます。
※MIM 2015 CTP3とFIM 2010R2 SP1を比較していますので、リリースまでに変わる可能性があります。

以下のスクリプトで定義されているMPR一覧が取得できるので、変化点を見てみましょう。

Add-PSSnapin FIMAutomaion
$curObject = Export-FIMConfig -Uri http://localhost:5725/resourcemanagementservice -OnlyBaseResources -CustomConfig ("/ManagementPolicyRule")
foreach ($fimobject in $curObject)
{
   $attributes = $fimobject.ResourceManagementObject.ResourceManagementAttributes
   $displayName = $attributes | where {$_.AttributeName -eq 'DisplayName'}
   write-host $displayName.Value
}

結果、以下の通りとなりました。
色を付けた部分のセルが新規追加になっているMPRです。
PAM(Privilege Access Management/特権アカウント管理)部分だけですね。
MPR一覧
Administration - Schema: Administrators can change selected attributes of non-system attribute type descriptionresources
Administration - Schema: Administrators can change selected attributes of non-system binding description resources
Administration - Schema: Administrators can change selected attributes of non-system schema related resources
Administration - Schema: Administrators can change selected attributes of schema related resources
Administration - Schema: Administrators can create attribute type description resources
Administration - Schema: Administrators can create binding description resources
Administration - Schema: Administrators can create resource type description resources
Administration - Schema: Administrators can delete non-system schema related resources
Administration: Administrators can control requests
Administration: Administrators can control synchronization configuration resources
Administration: Administrators can delete non-administrator users
Administration: Administrators can read all resources
Administration: Administrators can read and update Users
Administration: Administrators can update synchronization filter resources
Administration: Administrators control configuration related resources
Administration: Administrators control management policy rule resources
Administration: Administrators control set resources
Administration: Administrators control synchronization rule resources
Administration: Administrators control workflow definition resources
Administrators have full control over filter scope resources
Anonymous users can reset their password
Button viewable management: Members could read all attributes of the sets in all button viewable sets
Distribution list management: Owners can read attributes of group resources
Distribution list management: Owners can update and delete groups they own
Distribution list Management: Users can add or remove any members of groups subject to owner approval
Distribution list management: Users can add or remove any members of groups that don't require owner approval
Distribution List management: Users can create Static Distribution Groups
Distribution list management: Users can read selected attributes of group resources
General workflow: Filter attribute validation for administrator
General workflow: Filter attribute validation for non-administrators
General workflow: Registration initiation for authentication activity
General: Users can read non-administrative configuration resources
General: Users can read schema related resources
Group management workflow: Group information validation for dynamic groups
Group management workflow: Group information validation for static groups
Group management workflow: Owner approval on add member
Group management workflow: Validate requestor on add member to open group
Group management workflow: Validate requestor on remove member
Group management: Group administrators can create and delete group resources
Group management: Group administrators can read attributes of group resources
Group management: Group administrators can update group resources
[新規]PAM: Administrators control PAM Requests
[新規]PAM: Administrators control PAM Roles
[新規]PAM: User can read Pam Roles that he can request
[新規]PAM: User can see PAM requests that he created
[新規]PAM: Users can create a PAM Request
Password reset users can read password reset objects
Password Reset Users can update the lockout attributes of themselves
Reporting Administration: Administrators can control reporting binding resources.
Reporting Administration: Administrators can control reporting job resources.
Request management: Request approvers can read their approval resources
Request management: Request approvers can read their approval response resources
Request management: Request creators can cancel their requests
Request management: Request creators can read related approval response resources
Request management: Request creators can read their approval resources
Request management: Request creators can read their request resource
Request management: Request participants can read related approval resources
Request management: Request participants can read related approval response resources
Request management: Request participants can read their request resource
Security group management: Owners can read selected attributes of group resources
Security group management: Owners can update and delete groups they own
Security group management: Users can add or remove any member of groups subject to owner approval
Security Group management: Users can create Static Security Groups
Security group management: Users can read selected attributes of group resources
Security groups: Users can add and remove members to open groups
Synchronization: Synchronization account can delete and update expected rule entry resources
Synchronization: Synchronization account can read group resources it synchronizes
Synchronization: Synchronization account can read schema related resources
Synchronization: Synchronization account can read synchronization related resources
Synchronization: Synchronization account can read users it synchronizes
Synchronization: Synchronization account controls detected rule entry resources
Synchronization: Synchronization account controls group resources it synchronizes
Synchronization: Synchronization account controls synchronization configuration resources
Synchronization: Synchronization account controls users it synchronizes
Temporal policy workflow: Impending group resource expiry notification
User management: Users can read attributes of their own
User management: Users can read selected attributes of other users
Users can create registration objects for themselves
Users can modify registration objects for themselves

2015年4月9日木曜日

[MIM]特権アクセス管理のデモ動画

今年リリースされる予定のForefront Identity Manager 2010R2(FIM)の後継バージョンである、Microsoft Identity Manager 2015(MIM)の一番の目玉機能はなんといっても「特権アクセス管理(Privileged Access Management/PAM)です。

この機能を使うとActive Directory上のユーザに一時的に特権を付与することが出来ます

このことにより、

  • 個人アカウントで管理をすることが出来るので、いつ、だれが、何をしたのか?について正確にロギング出来る
  • 必要な時に必要な権限を付与するので、不要な権限を与えることによる事故が起きにくい
  • ビルトインAdministratorなどの特権ユーザを管理者や運用者間で共有する必要がなくなるので、システム管理を安全に行うことが出来る
など様々なメリットを享受することが出来ます。

特に仮想化テクノロジを使ってグループ企業向けのプライベート・クラウドを提供しているような環境においては管理者アカウントの管理は非常に重要な意味合いを持つので、今後ますます厳重に管理をしていくべき対象となることでしょう。
これまでActive Directory上の特権アカウントの管理は非常に面倒だったので、今回のMIMのリリースは今後のシステム管理を行う上での重要な意味を持つものになると考えられます。


と、ここまで書きましたが文字ばかりだとイメージがつきにくいと思います。
そんな方に朗報です。

私と同じFIM MVPのEihab Isaac氏がPAMのデモ動画をYouTubeにアップロードしてくれています。
3分程度と非常に短いながらも非常にわかりやすいので是非ご覧ください。




2015年4月8日水曜日

[AD FS/OAuth]Windows Server Technical PreviewでのOAuth対応

5月に2度目のビルドが公開されるというのWindows Server Technical Previewですが、これまで何回か紹介してきたようにActive Directory Federation Services(AD FS)の機能が大幅に拡張されています。

(参考)これまでのポスト
- [AD FS] Windows Server Technical PreviewのAD FSを試す
 http://idmlab.eidentity.jp/2014/10/ad-fs-windows-server-technical.html
- [AD FS]Windows Server Technical Previewで追加された機能~PowerShell編
  http://idmlab.eidentity.jp/2015/03/ad-fswindows-server-technical.html


今回はその中でもOAuth2.0への対応について現状をまとめておきます。
(OpenID Connectにも対応しているのですが、そちらは次回にでも)

ポイントは、以下の3点です。
①Confidential Clientの作成が出来るようになった
②Implicit/Client Credentialsに対応した
 ※ちなみにResource Owner Password Credentialsは未サポートです
③Client AuthenticationにJWTが使えるようになった

■ポイント①:Confidential Clientを作成できるようになった
Windows Server 2012R2まではPublic Clientしか作成することが出来ず、client_secretが必要なフロー(client_credentialsなど)には対応していませんでしたが、Add-AdfsClientコマンドレットの拡張によりConfidential Clientを作成することが出来るようになりました。

こちらはこれまでと同じく、Public Clientの作成です。
PS> Add-AdfsClient -ClientId 6c831710-cd6c-11e4-8830-0800200c9a66 -Name TestPublicClient -RedirectUri http://localhost -ClientType Public


次に、新たに追加されたConfidential Clientの作成です。-ClientTypeオプションに[Confidential]を指定し、-GenerateClientSecretオプションを付けることによりclient_secretを生成できます。
※-ClientTypeオプションの値がPublicだと-GenerateClientSecretオプションは使えません。
PS> Add-AdfsClient -ClientId bf7fb880-cd6f-11e4-8830-0800200c9a66 -Name TestConfidentialClient -RedirectUri http://localhost2 -ClientType Confidential -GenerateClientSecret

RedirectUri                          : {http://localhost2/}
Name                                 : TestConfidentialClient
Description                          :
ClientId                             : bf7fb880-cd6f-11e4-8830-0800200c9a66
BuiltIn                              : False
Enabled                              : True
ClientType                           : Confidential
ADUserPrincipalName                  :
ClientSecret                         : buEgBXgYZO5Y7bdk6kjPE9oDLAA1ZRtvSCwm6orc
JWTSigningCertificateRevocationCheck : CheckChainExcludeRoot
JWTSigningCertificate                : {}


ちなみに生成されたClientSecretはこの作成結果画面でしか見れませんので、必ずメモしておきましょう。
(もちろん再生成することも出来ます)


■ポイント②:Implicit/Client Credentialsに対応した
Windows Server 2012R2ではCode Flow一択でしたが、今回のビルドからImplicitおよびClientCredentialsにも対応しています。

おまけですが、まずはこれまでの同じくCode Flowです。
※相変わらずResourceパラメータが必要なので、AD FSに登録したRelying PartyのIdentifierを指定します。これは他のgrant_typeでも同様です。

◆Code Flow
①認可コードを要求します。
https://adfsserver.example.com/adfs/oauth2/authorize?response_type=code&client_id=6c831710-cd6c-11e4-8830-0800200c9a66&redirect_uri=http%3A%2F%2Flocalhost&resource=google.com%2Fa%2Fhoge.example.net


②ユーザ認証後、redirect_uriにリダイレクトされ、GETパラメータで認可コードが取得できます。
http://localhost/?code=QAILg...snip...3r6dSQ


③取得した認可コードをtokenエンドポイントへPOSTします。
https://adfsserver.example.com/adfs/oauth2/token
grant_type authorization_code
code
redirect_uri http://localhost
client_id 6c831710-cd6c-11e4-8830-0800200c9a66


④access_tokenが取得できます。
ついでにid_tokenまで返ってきてしまいます。。。
{
access_token: "eyJ0eXAiOiJKV...snip...m1Pu0pRHEqQNr_uilmeMZ_Z1i2lM3hHDFGLmwg"
token_type: "bearer"
expires_in: 3600
id_token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJ...snip...P662gJhkaquYh3vvW9lvxZAqbThO6Oql8hRw"
}


取得できたaccess_token、id_tokenをデコードするとこんな感じです。
- access_token
{
  "aud": "microsoft:identityserver:google.com/a/hoge.exmample.net",
  "iss": "http://adfsserver.example.com/adfs/services/trust",
  "iat": 1426683515,
  "exp": 1426687115,
  "sub": "admin@example.com",
  "apptype": "Public",
  "appid": "6c831710-cd6c-11e4-8830-0800200c9a66",
  "authmethod": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
  "auth_time": "2015-03-18T12:58:33.642Z",
  "ver": "1.0"
}


- id_token
{
  "aud": "6c831710-cd6c-11e4-8830-0800200c9a66",
  "iss": "http://adfsserver.example.com/adfs/services/trust",
  "iat": 1426683515,
  "exp": 1426687115,
  "auth_time": "2015-03-18T12:58:33.642Z",
  "sub": "yMpiFIT0ydzHFXmiKhjSPqiqFDvSHnYlGctCv3NyAas=",
  "ver": "1.0"
}


ちなみにSet-AdfsRelyingPartyTrustコマンドレットを使ってResource(Relying Party)の設定のIssueOAuthRefreshTokensToに[AllDevices]を設定することでrefresh_tokenを発行することも出来ます。
{
access_token: "eyJ0eXAiOiJKV1...snip...2Qd0FZ5J_zORnxOyvj1MxQsVCwMMmlNg"
token_type: "bearer"
expires_in: 3600
refresh_token: "NLGBlhSJjs7_zvjTkKtnnGY...snip...OSlKvCA"
id_token: "eyJ0eXAiOiJKV1QiLCJh...snip...0tr3iS_RIxFiNZBxOfvcBlzV9u3HA"
}


これでgrant_typeにrefresh_tokenをセットしてtokenエンドポイントにrefresh_tokenをPOSTすることで再度ユーザ認証を求められることなくaccess_tokenを取得することが出来ます。


◆implicit flow
いよいよ新しくサポートされたImplicit Flowです。

①Authorizationエンドポイントにresponse_type=tokenを付けてaccess_tokenをリクエストします。
https://adfsserver.example.com/adfs/oauth2/authorize?response_type=token&client_id=6c831710-cd6c-11e4-8830-0800200c9a66&redirect_uri=http%3A%2F%2Flocalhost&resource=google.com%2Fa%2Fhoge.example.net


②ユーザ認証が行われるため、ログオンするとredirect_uriにリダイレクトされ、フラグメントにaccess_tokenが返ってきます。
http://localhost/#access_token=eyJ0eXAiO...snip...MP_bQsjj7Jvp81j-qztASSrzzAypA&token_type=bearer&expires_in=3600


CodeFlowと同じく取得したaccess_tokenをデコードするとこんな感じになります。当然同じようなものになりますが。。。
{
  "aud": "microsoft:identityserver:google.com/a/hoge.example.net",
  "iss": "http://adfsserver.example.com/adfs/services/trust",
  "iat": 1426683944,
  "exp": 1426687544,
  "sub": "admin@example.com",
  "apptype": "Public",
  "appid": "6c831710-cd6c-11e4-8830-0800200c9a66",
  "authmethod": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
  "auth_time": "2015-03-18T13:05:42.250Z",
  "ver": "1.0"
}




◆Client Credentials Flow
次にClient Credentialsです。こちらも新しくサポートされました。

①tokenエンドポイントにPOSTします。
その際、client_id/client_secretを一緒にPOSTすることでクライアント認証を行います。
このあたりの認証方法が各社バラバラなのが困りますね。。。
POST https://adfsserver.example.com/adfs/oauth2/token
grant_type client_credentials
resource urn:dummyapi
client_id bf7fb880-cd6f-11e4-8830-0800200c9a66
client_secret bu....snip....rc


・・・。unauthorized_clientエラーが返ってきました。。。
{
error: "unauthorized_client"
error_description: "MSIS9605: The client is not allowed to access the requested resource."
}


Resource(Relying Party)の設定をGet-AdfsRelyingPartyTrustで確認すると、
 AllowedClientTypes : Public
となっています。

②今回使うClientはclient_secretを使うのでConfidential Clientなので、Resourceの設定を変更する必要があります。Set-AdfsRelyingPartyTrustでAllowClientTypesにConfidentialを設定して、再度tokenエンドポイントにPOSTします。

今度はちゃんとaccess_tokenが取得できました。



◆Resource Owner Password Credentials Flow
最後に一応Resource Owner Password Credentialsです。

①tokenエンドポイントにgrant_type:passwordでPOSTします。
POST https://adfsserver.example.com/adfs/oauth2/token
grant_type password
username nfujie@example.com
password P@ssw0rd
resource urn:dummyapi
client_id bf7fb880-cd6f-11e4-8830-0800200c9a66
client_secret buEgB...snip..6orc


②残念ながら[unsupport_grant_type]といって怒られてしまいます。
{
error: "unsupported_grant_type"
error_description: "MSIS9611: The authorization server does not support the requested 'grant_type'. The authorization server only supports 'authorization_code' or 'refresh_token' as the grant type."
}




■ポイント③:Client AuthenticationにJWTが使えるようになった
JWT(JSON Web Token) Profile for OAuth 2.0 Client Authentication and Authorization Grants(http://self-issued.info/docs/draft-ietf-oauth-jwt-bearer-06.html)への対応ですね。

ちなみにまだAuthorization Grantについては試していませんが、多分対応している気がします(マイクたん的に)

先ほどClient Credentials FlowでのClient認証を行うためにclient_idとclient_secretをリクエストに入れましたが、client_secretを毎回通信に入れるのが嫌な場合に秘密鍵で署名したJWTを使ってクライアント認証をする仕組みなので、Set-AdfsClientコマンドレットでクライアントに公開鍵を設定しておき、リクエストのJWT(client_assertion)に対応する秘密鍵で署名します。

①クライアントに公開鍵を設定する
以下の様にしてあらかじめ用意しておいたcerファイルをクライアントに設定します。
PS> $cert=New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("c:\temp\public.cer")
PS> Set-AdfsClient -TargetClientId bf7fb880-cd6f-11e4-8830-0800200c9a66 -JWTSigningCertificate $cert


設定した結果をGet-AdfsClientで確認すると、JWTSigningCertificateパラメータに証明書の情報が表示されます。
PS> Get-AdfsClient -Name TestConfidentialClient

RedirectUri                          : {http://localhost2/}
Name                                 : TestConfidentialClient
Description                          :
ClientId                             : bf7fb880-cd6f-11e4-8830-0800200c9a66
BuiltIn                              : False
Enabled                              : True
ClientType                           : Confidential
ADUserPrincipalName                  :
ClientSecret                         : ********
JWTSigningCertificateRevocationCheck : CheckChainExcludeRoot
JWTSigningCertificate                : {[Subject]
CN=adfsserver.example.com, OU=hoge, OU=hoge
[Issuer]
CN=hoge, hoge,
L=hoge, S=hoge, C=JP
[Serial Number]
00D6...snip...6116767C
[Not Before]
2/26/2015 12:00:00 AM
[Not After]
2/25/2018 11:59:59 PM
[Thumbprint]
51A5...snip....3F3A23DA
}


②リクエストにセットするclient_assertionを作成し、秘密鍵で署名する
ADALを使えば割と楽に作れますが、今回はロジックをわかりやすくするため、生でコードを書いています。
こんなコードでclient_assertionを取得します。
static string Get_Client_Assertion(){
    // 秘密鍵ファイルとパスフレーズをセット
    var certificate = new X509Certificate2(
        "c:\temp\private.p12",
        "secret",
        X509KeyStorageFlags.Exportable);

    // Credentialの生成
    var credentials = new X509SigningCredentials(
        certificate,
        new SecurityKeyIdentifier(
            new NamedKeySecurityKeyIdentifierClause(
               "kid",
               "51...snip...A23DA(thumbprint)"))); 

    // token lifetime
    var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
    var issueTime = DateTime.Now;
    var iat = (long)issueTime.ToUniversalTime().Subtract(utc0).TotalSeconds;
    var exp = (long)issueTime.ToUniversalTime().AddMinutes(55).Subtract(utc0).TotalSeconds;
    var issuedTime = DateTime.UtcNow;
    var expiresTime = issuedTime.AddMinutes(5);
    var epoch = new DateTime(1970, 01, 01, 0, 0, 0);

    // JWT Headerの生成
    var header = new { alg = "RS256", typ = "JWT", x5t = "Ua...snip...9o(thumbprint)" };
    var headerSerialized = JsonConvert.SerializeObject(header, Formatting.None);
    var headerBytes = Encoding.UTF8.GetBytes(headerSerialized);
    var headerEncoded = Base64UrlEncode(headerBytes);

    // JWT Payloadの生成
    var payload = new
    {
        sub = "bf7fb880-cd6f-11e4-8830-0800200c9a66(client_id)",
        iss = "bf7fb880-cd6f-11e4-8830-0800200c9a66(client_id)",
        aud = "https://adfsserver.example.com/adfs/oauth2/token",
        jti = "admin@example.com",
        exp = exp,
        iat = iat
    };
    var payloadSerialized = JsonConvert.SerializeObject(payload,Formatting.None);
    var payloadBytes = Encoding.UTF8.GetBytes(payloadSerialized);
    var payloadEncoded = Base64UrlEncode(payloadBytes);

    // 署名の生成
    var x509Key = new X509AsymmetricSecurityKey(certificate);
    RSACryptoServiceProvider rsa = x509Key.GetAsymmetricAlgorithm(SecurityAlgorithms.RsaSha256Signature, true) as RSACryptoServiceProvider;
    RSACryptoServiceProvider newRsa = null;
    newRsa = GetCryptoProviderForSha256(rsa);
    using (SHA256Cng sha = new SHA256Cng())
    {
        return headerEncoded + "." + payloadEncoded + "." + Base64UrlEncode(
            newRsa.SignData(Encoding.UTF8.GetBytes(headerEncoded + "." + payloadEncoded), sha));
    }
}


③生成したclient_assertionを使ってaccess_tokenを要求する
tokenエンドポイントにclient_assertionを含むパラメータをPOSTします。

POST https://adfsserver.example.com/adfs/oauth2/token
grant_type client_credentials
resource urn:dummyapi
client_assertion_type urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion  eyJhbGciO...snip...6r3LZa-H2avPokc4sp4A

client_secretを使わないので少し気分的に楽になります。

④access_tokenが返ってくる
ここは先に解説したClient Credentials Flowの結果と変わりません。



とりあえずここまでです。
他にもOAuth2.0 JWT Bearer TokenフローやOpenID Connect対応についてもある程度試してはいるので、また書きたいと思います、

後は、次のビルドが出たらもう少し試してみたいと思います。