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対応についてもある程度試してはいるので、また書きたいと思います、

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

2015年4月2日木曜日

[FIM/MIM]ライセンス体系の変更~Windows Serverのライセンスに統合

※ライセンスにかかわる話なので、正式な見解は日本マイクロソフトにご確認ください。
 本ポストの内容については責任を負えません。

昨日から某所がざわついた話題です。

2015年4月1日のマイクロソフトのワールドワイドでのライセンス体系の変更によりForefront Identity Manager 2010 R2 Server(FIM)のライセンスが大きく変わっています。

以前と比較すると、下表のようになります。
2015年3月まで2015年4月から
サーバライセンスサーバごとに必要Windows Serverライセンスに含まれる
(OSの一機能として定義される)
CAL別途FIM CALが必要FIM機能を使うためには、別途FIM CAL/Enterprise Mobility Suite/AAD Premiumが必要
※実質変化なし
CAL例外事項FIM Syncのみの利用ならCALは不要同左


最大かつ唯一の変化点は「サーバ・ライセンスが不要になった」という点です。
FIMの様に多数のサーバで構成する製品だとこれはかなりの競争力の源泉となると思われます。
(まぁ、他社の例を見ていると基本はユーザライセンスのみ、というメーカが多いので同じような形になった、というだけかも知れませんが)

参考)Volume Licensingのページ
  http://www.microsoft.com/licensing/products/products.aspx


このページよりProduct Use Rights(PUR/製品使用権説明書)およびProduct List(PL/製品表)をダウンロードし中身を見てみると以下のように記載されています。

◆変更点(PUR/PL)
・削除された製品としてForefront Identity Manager 2010 R2 Serverが記載
・Windows Serverに関する変更点として以下が記載
Forefront Identity Manager 2010 R2 機能の追加 CAL の要件を満たすものとして、Forefront Identity Manager 2010 User CAL、Enterprise Mobility Suite User SL、および Microsoft Azure Active Directory Premium を追加しました。
Forefront Identity Manager 2010 R2 機能の追加エクスターナル コネクタの要件を満たすものとして、Forefront Identity Manager 2010 R2 External Connector を追加しました。
ID 情報を管理するための CAL の要件を追加しました。
Forefront Identity Manager 同期サービスのみを使用するユーザーについては CAL は不要である旨を明確にしました。

◆Windows Serverの項目
・機能として「Forefront Identity Manager 2010 R2機能」と記載
・FIM機能を利用する場合の必要CALとして以下が記載
Forefront Identity Manager 2010 R2 User CAL (デバイス CAL は使用できません) または
Enterprise Mobility Suite User SL または
Microsoft Azure Active Directory Premium
・追加の条件として以下が記載
証明書および ID の管理
本ソフトウェアで ID 情報を発行または管理するユーザーについては、CAL も取得する必要があります。
同期サービス
Forefront Identity Manager 同期サービスのみを使用するユーザーについては、CAL は必要ありません。





2015年3月31日火曜日

[Windows10/AAD]Technical Preview Build 10041のCDJでOffice365とのSSOを実現

ようやくWindows 10 Technical Previewの最新ビルドである10041のクラウド・ドメイン・ジョイン(CDJ)を試すことが出来ました。

前回のビルドでは実現できなかったOffice365へのシングルサインオンが今回のビルドから出来るようになっています。(まだ不安定な感じはしますが)
また今回、AD FSと連携されているAzure Active Directory(AAD)ドメインのユーザを使ってCDJを行うとどうなるのか?についても同時に試してみました。

こんな環境です。


◆AD FSアカウントでCDJ
まずは、CDJです。
前のビルドで行ったのと同じ方法でクラウドへ接続します。

ポイントは、組織アカウントを入力する際に、AADからAD FSに連携しているユーザアカウントを指定するところです。AD FSユーザを入力すると、クラウド体験ホストのウィンドウにAD FSのログオン画面が表示されます。
(ちなみにクラウド体験ホストではリダイレクトではなく、AzureADでProxyしてAD FSの画面が表示されているように見えます。つまり、PCから直接AD FSへの通信がこの段階では発生していないようです)




うまく行くと、AAD上にデバイスが登録されます。


これで、AD DSが使えない環境でのドメイン参加ができたことになりますので、ID管理対象はあくまでAD DSに集約させることが出来ますし、AD FSと連携しているアプリケーションの認証とPCのIDの連携を社内PCはAD DS、社外PCはAD FSという形で統合することが出来ます。



◆Office365へSSO
次にOffice365へのSSOです。

前回のビルドでは、Office365(https://portal.office.com)へアクセスしてもID/パスワードを入力してログインする必要がありましたが、今回のビルドではAAD Token Broker Pluginが(ある程度)動くようになっており、確認した限りでは、Office365/Visual Studio OnlineへはきちんとSSO出来るようになっていました。
(まだバグっぽい動きはありましたが)
※ちなみにOutlookを使ってExchange OnlineとSSO出来るか、現状はダメです。ただ、ADALを有効にしたOfficeクライアントへのSSOはできますので、SharePoint Online連携なんかはうまく行くんじゃないでしょうか?(試してないですが)

動きとしては非常にシンプルで、PCにログインしてそのままIEを起動、Office365やVisual Studio Onlineにアクセスするだけです。




内部的にはIEを起動すると、AAD Token Broker PluginというモジュールがPCログイン時に取得したPRT(Primary Refresh Token)でAccess Tokenを取得し、トークンを使ってログインする、という流れです。
そのため、AADやAD FSのログイン画面にリダイレクトされて、、、という動きはしないため、AD FSで認証する設定になっているOffice365にシングルサインオン出来るからと言って、同じAD FSを信頼している他のサービス(Google AppsやSalesforce.comなど)にシングルサインオン出来るわけではありません。



尚、このAAD Token Broker Pluginですが、現状以下の不具合?があります。
・初回PCログイン時、2つ設定が存在している
・[管理]をクリックしても何も起きない
・Office365にアクセスする時にアクセス権がない、というエラーが出ることがある

最後のアクセス権のエラーについてはAAD Token Broker Pluginを一旦削除すると上手く動くのですが、IEを起動した段階で再度Pluginが生成されるため、次にIEを起動すると同じエラーが再度出てきたりします。
(DCOM関連のエラーが大量に出るので、レジストリとDCOMのアクセス権を付けると上手く行くのかも知れませんが、現状私の環境では解消していません)



全体にまだまだな感じはしますが、デバイスとブラウザやアプリケーションのSSOがようやく実現しそうな予感がします。
夏の正式リリースまでにブラッシュアップされると思うので期待して待っておきましょう。

2015年3月26日木曜日

GoogleのOpenID 2.0サポート終了による影響いろいろ(Azure ACS編)

いよいよ4月20日のGoogleのOpenID 2.0サポート終了まで1か月を切りました。


Googleのアナウンスページ
 https://developers.google.com/accounts/docs/OpenID

ちなみに今回終了するサービスにはOpenID 2.0だけではなく、Provisioning APIなども含まれるため、各IdM製品ベンダのGoogle Apps接続用コネクタは作り直しを余儀なくされたり、テレビに内蔵されているYoutubeアプリが使えなくなったり、、、と様々な影響が出ています。

個人的にも少々影響がありました。。。。

 昔作ったFIM用のGoogle Apps管理エージェントの作り直し
  過去のバージョン
   https://fim2010gapps.codeplex.com/
  作り直したバージョン(汎用REST API向け)
   https://restmafim.codeplex.com/

 自宅のTVのYoutubeアプリ終了
  http://www.sony.jp/info/20150123/


他にも、最近は全然使っていなかったので個人的にはあまり影響はありませんでしたが、OpenID 2.0を使っているサービスということで影響を受けるのが懐かしのAzure Access Control Service 2.0(ACS)です。
マイクロソフトも移行手順を公開したりメールで通知を送るなどして移行を促しています。
※こちらは何故か6/1までに移行するように、と書いてありGoogleの公式発表よりも少し猶予があります。何らかの調整が2社間であったのかも知れません。

 移行手順のページ(英語)
 https://msdn.microsoft.com/en-us/library/azure/dn927169.aspx

と、言うことで手順に従いマイグレーションをしてみました。
大まかにいうと、Google+ APIにアクセスできるクライアントをGoogle Developer Consoleで作成し、作成したクライアント情報(client_idとclient_secret)をACSに登録する、という手順です。

1.移行前の状態の確認

まずは、移行前の状態です。
ACSのIDプロバイダのページを開くと、昔作成したGoogle接続設定があります。


Googleを開くとクライアントIDとクライアントシークレットを設定出来るようになっています。


この状態でアプリケーションがACSを使うように構成すると、Googleを使ってログオンできる、という仕掛けなわけです。

アプリケーションの設定例)
Visual Studioでプロジェクトを作成する際にFederation Metadataを設定するだけなので、ノンコーディングでOKです。

IDプロバイダを選択

Googleアカウントでログイン

無事にログインし、ユーザ名が取得できます。


では、さっそく移行していきます。

2.クライアントの作成

Google Developer Console(https://console.developers.google.com/project)にログインし、プロジェクトを作成します。

[プロジェクトを作成]をクリックし、プロジェクト名などを適当につけます。



プロジェクトの作成が終わったら[APIと認証]の[認証情報]メニューを開き、[新しいクライアントIDを作成]をクリックします。
作成するアプリケーションの種類は「Webアプリケーション」を選択します。


途中、同意画面に関する情報を入力する画面が出ますが、適当にサービス名を入れておきます。



次に、JavaScript生成元、リダイレクトURIの指定が求められますので、それぞれ以下を設定します。
[承認済みのJAVASCRIPT生成元]
 https://[ACS名前空間].accesscontrol.windows.net:443
[承認済みのリダイレクトURI]
 https://[ACS名前空間].accesscontrol.windows.net:443/v2/openid

クライアントIDが正常に作成されると、クライアントIDとクライアントSecretが表示されるので、この2つの値をメモしておきます。(あとでACS側に設定します)


3.Google+ APIの有効化

Google Developer Consoleで作成したプロジェクトは初期状態でGoogle+ APIは無効状態なので、有効化しておきます。

APIの検索ボックスにGoogle+を入れてGoogle+ APIを探し、クリックします。

[Enable API]ボタンをクリックしてAPIを有効化します。

4.ACSにクライアントを登録する

これでクライアントの作成が終わったので、ACSに情報を登録します。
Use OpenID Connectにチェックをつけて、ClientID/Client Secretに先に取得した値を入れて保存します。


これで移行は終わりです。
※クレーム規則を定義していた場合は若干修正が必要になる場合があります。

5.動作確認

基本何も変わりません。
しかし、トレースするとOpenID Connectが使われていることがわかります。
Googleへのリダイレクト
GET https://accounts.google.com/o/oauth2/auth?client_id=xxxxxx.apps.googleusercontent.com&response_type=code&redirect_uri=https%3a%2f%2fxxxxxx.accesscontrol.windows.net%3a443%2fv2%2fopenid&scope=openid+email&openid.realm=https%3a%2f%2fxxxxx.accesscontrol.windows.net%3a443%2fv2%2fopenid&state=xxxxxxxxxxxx HTTP/1.1

code flowですね。
GET https://xxxxxx.accesscontrol.windows.net/v2/openid?state=xxxxxxxxxx&code=xxxxxxxxxx&authuser=0&num_sessions=1&session_state=xxxxx&prompt=none HTTP/1.1


参考までにOpenID Connectに変更する前の通信トレースはこんな感じです。
(こうやって見ると重たいプロトコルですねぇ。。)

GET https://www.google.com/accounts/o8/ud?openid.ns=http%3a%2f%2fspecs.openid.net%2fauth%2f2.0&openid.mode=checkid_setup&openid.claimed_id=http%3a%2f%2fspecs.openid.net%2fauth%2f2.0%2fidentifier_select&openid.identity=http%3a%2f%2fspecs.openid.net%2fauth%2f2.0%2fidentifier_select&openid.realm=https%3a%2f%2fxxxxx.accesscontrol.windows.net%3a443%2fv2%2fopenid&openid.return_to=https%3a%2f%2fxxxxx.accesscontrol.windows.net%3a443%2fv2%2fopenid%3fcontext%3dxxxxxxxxxx&openid.ns.ax=http%3a%2f%2fopenid.net%2fsrv%2fax%2f1.0&openid.ax.mode=fetch_request&openid.ax.required=email%2cfullname%2cfirstname%2clastname&openid.ax.type.email=http%3a%2f%2faxschema.org%2fcontact%2femail&openid.ax.type.fullname=http%3a%2f%2faxschema.org%2fnamePerson&openid.ax.type.firstname=http%3a%2f%2faxschema.org%2fnamePerson%2ffirst&openid.ax.type.lastname=http%3a%2f%2faxschema.org%2fnamePerson%2flast HTTP/1.1

GET https://accounts.google.com/o/openid2/auth?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup&openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.realm=https://xxxxx.accesscontrol.windows.net:443/v2/openid&openid.return_to=https://xxxxx.accesscontrol.windows.net:443/v2/openid?context%3Dxxxxxx&openid.ns.ax=http://openid.net/srv/ax/1.0&openid.ax.mode=fetch_request&openid.ax.required=email,fullname,firstname,lastname&openid.ax.type.email=http://axschema.org/contact/email&openid.ax.type.fullname=http://axschema.org/namePerson&openid.ax.type.firstname=http://axschema.org/namePerson/first&openid.ax.type.lastname=http://axschema.org/namePerson/last HTTP/1.1
GET https://accounts.google.com/o/openid2/auth?zt=xxxx&from_login=1&hl=ja&as=xxxxxx&authuser=0 HTTP/1.1

GET https://xxxxx.accesscontrol.windows.net/v2/openid?context=xxxxxx&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.mode=id_res&openid.op_endpoint=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fud&openid.response_nonce=xxxx&openid.return_to=https%3A%2F%2Fxxxx.accesscontrol.windows.net%3A443%2Fv2%2Fopenid%3Fcontext%3Dxxxx&openid.assoc_handle=xxxxx&openid.signed=op_endpoint%2Cclaimed_id%2Cidentity%2Creturn_to%2Cresponse_nonce%2Cassoc_handle%2Cns.ext1%2Cext1.mode%2Cext1.type.firstname%2Cext1.value.firstname%2Cext1.type.lastname%2Cext1.value.lastname%2Cext1.type.email%2Cext1.value.email&openid.sig=xxxxxx%3D&openid.identity=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fid%3Fid%3Dxxxxxxxx&openid.claimed_id=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fid%3Fid%3Dxxxxxxxxxx&openid.ns.ext1=http%3A%2F%2Fopenid.net%2Fsrv%2Fax%2F1.0&openid.ext1.mode=fetch_response&openid.ext1.type.firstname=http%3A%2F%2Faxschema.org%2FnamePerson%2Ffirst&openid.ext1.value.firstname=Naohiro&openid.ext1.type.lastname=http%3A%2F%2Faxschema.org%2FnamePerson%2Flast&openid.ext1.value.lastname=Fujie&openid.ext1.type.email=http%3A%2F%2Faxschema.org%2Fcontact%2Femail&openid.ext1.value.email=xxxxxxxxx%40gmail.com# HTTP/1.1

ちなみに、ACSのIDプロバイダに新規でGoogleの設定をすると、Use OpenID Connectのチェックボックスが最初からチェックされており、外すことが出来ません。

今回のようにクラウド・サービスの仕様変更に伴い様々な影響が出ることを考えると、ますます自前で対応するのではなく、プロバイダ側で勝手に設定を変更してもらえるIDaaSなどのサービスを利用する方が良い、と言えるかも知れません。

2015年3月18日水曜日

[AD FS]Windows Server Technical Previewで追加された機能~PowerShell編

以前のポストで概要を簡単にチェックしたWindows Server Technical PreviewのActive Directory Federation Services(AD FS)ですが、今回はPowerShellのコマンドレットがどのように変わったのか?という点から確認してみます。

関連ポスト
 [AD FS] Windows Server Technical PreviewのAD FSを試す
 http://idmlab.eidentity.jp/2014/10/ad-fs-windows-server-technical.html


結論としては、大きくは以下の機能関連のコマンドレットが追加されています。
・ローカルクレームプロバイダ
・アプリケーション・パーミッション(Scope/Permission)
・ポリシーテンプレート
・その他
 Relying Party Web Theme
 AD FS farm behavior level

特にアプリケーション・パーミッション関係の拡張ではOpenID ConnectのサポートやOAuth Implicit Flowのサポートに関連する拡張なので、AD FS活用のシナリオも広がってくると思われます。
(別途OAuth2.0やOpenID Connectのサポート状況については検証結果をポストしたいと思います。Previewなので若干おかしなところはありますが、概ね動いています)

参考)Windows Server 2012R2とWindows Server Technical PreviewのAD FS関連コマンドレット一覧比較
Windows Server 2012R2Windows Server Technical Preview変更
Add-AdfsAttributeStoreAdd-AdfsAttributeStore
Add-AdfsCertificateAdd-AdfsCertificate
Add-AdfsClaimDescriptionAdd-AdfsClaimDescription
Add-AdfsClaimsProviderTrustAdd-AdfsClaimsProviderTrust
Add-AdfsClientAdd-AdfsClient
Add-AdfsDeviceRegistrationUpnSuffixAdd-AdfsDeviceRegistrationUpnSuffix
Add-AdfsFarmNodeAdd-AdfsFarmNode
-Add-AdfsLocalClaimsProviderTrust新規
Add-AdfsNonClaimsAwareRelyingPartyTrustAdd-AdfsNonClaimsAwareRelyingPartyTrust
Add-AdfsRelyingPartyTrustAdd-AdfsRelyingPartyTrust
-Add-AdfsScopeDescription新規
Add-AdfsWebApplicationProxyRelyingPartyTrustAdd-AdfsWebApplicationProxyRelyingPartyTrust
Disable-AdfsClaimsProviderTrustDisable-AdfsClaimsProviderTrust
Disable-AdfsClientDisable-AdfsClient
Disable-AdfsDeviceRegistrationDisable-AdfsDeviceRegistration
Disable-AdfsEndpointDisable-AdfsEndpoint
-Disable-AdfsLocalClaimsProviderTrust新規
Disable-AdfsNonClaimsAwareRelyingPartyTrustDisable-AdfsNonClaimsAwareRelyingPartyTrust
Disable-AdfsRelyingPartyTrustDisable-AdfsRelyingPartyTrust
Disable-AdfsWebApplicationProxyRelyingPartyTrustDisable-AdfsWebApplicationProxyRelyingPartyTrust
Enable-AdfsClaimsProviderTrustEnable-AdfsClaimsProviderTrust
Enable-AdfsClientEnable-AdfsClient
Enable-AdfsDeviceRegistrationEnable-AdfsDeviceRegistration
Enable-AdfsEndpointEnable-AdfsEndpoint
-Enable-AdfsLocalClaimsProviderTrust新規
Enable-AdfsNonClaimsAwareRelyingPartyTrustEnable-AdfsNonClaimsAwareRelyingPartyTrust
Enable-AdfsRelyingPartyTrustEnable-AdfsRelyingPartyTrust
Enable-AdfsWebApplicationProxyRelyingPartyTrustEnable-AdfsWebApplicationProxyRelyingPartyTrust
Export-AdfsAuthenticationProviderConfigurationDataExport-AdfsAuthenticationProviderConfigurationData
Export-AdfsDeploymentSQLScriptExport-AdfsDeploymentSQLScript
Export-AdfsWebContentExport-AdfsWebContent
Export-AdfsWebThemeExport-AdfsWebTheme
Get-AdfsAdditionalAuthenticationRuleGet-AdfsAdditionalAuthenticationRule
-Get-AdfsApplicationPermission新規
Get-AdfsAttributeStoreGet-AdfsAttributeStore
Get-AdfsAuthenticationProviderGet-AdfsAuthenticationProvider
Get-AdfsAuthenticationProviderWebContentGet-AdfsAuthenticationProviderWebContent
Get-AdfsCertificateGet-AdfsCertificate
Get-AdfsClaimDescriptionGet-AdfsClaimDescription
Get-AdfsClaimsProviderTrustGet-AdfsClaimsProviderTrust
Get-AdfsClientGet-AdfsClient
Get-AdfsDeviceRegistrationGet-AdfsDeviceRegistration
Get-AdfsDeviceRegistrationUpnSuffixGet-AdfsDeviceRegistrationUpnSuffix
Get-AdfsEndpointGet-AdfsEndpoint
Get-AdfsGlobalAuthenticationPolicyGet-AdfsGlobalAuthenticationPolicy
Get-AdfsGlobalWebContentGet-AdfsGlobalWebContent
-Get-AdfsLocalClaimsProviderTrust新規
Get-AdfsNonClaimsAwareRelyingPartyTrustGet-AdfsNonClaimsAwareRelyingPartyTrust
-Get-AdfsPolicyTemplate新規
Get-AdfsPropertiesGet-AdfsProperties
Get-AdfsRegistrationHostsGet-AdfsRegistrationHosts
Get-AdfsRelyingPartyTrustGet-AdfsRelyingPartyTrust
Get-AdfsRelyingPartyWebContentGet-AdfsRelyingPartyWebContent
-Get-AdfsRelyingPartyWebTheme新規
-Get-AdfsScopeDescription新規
Get-AdfsSslCertificateGet-AdfsSslCertificate
Get-AdfsSyncPropertiesGet-AdfsSyncProperties
Get-AdfsWebApplicationProxyRelyingPartyTrustGet-AdfsWebApplicationProxyRelyingPartyTrust
Get-AdfsWebConfigGet-AdfsWebConfig
Get-AdfsWebThemeGet-AdfsWebTheme
-Grant-AdfsApplicationPermission新規
Import-AdfsAuthenticationProviderConfigurationDataImport-AdfsAuthenticationProviderConfigurationData
Import-AdfsWebContentImport-AdfsWebContent
Initialize-ADDeviceRegistrationInitialize-ADDeviceRegistration
Install-AdfsFarmInstall-AdfsFarm
-Invoke-AdfsFarmBehaviorLevelRaise新規
New-AdfsClaimRuleSetNew-AdfsClaimRuleSet
New-AdfsContactPersonNew-AdfsContactPerson
-New-AdfsLdapAttributeToClaimMapping新規
-New-AdfsLdapServerConnection新規
New-AdfsOrganizationNew-AdfsOrganization
-New-AdfsPolicyTemplate新規
New-AdfsSamlEndpointNew-AdfsSamlEndpoint
New-AdfsWebThemeNew-AdfsWebTheme
Publish-SslCertificatePublish-SslCertificate
Register-AdfsAuthenticationProviderRegister-AdfsAuthenticationProvider
Remove-AdfsAttributeStoreRemove-AdfsAttributeStore
Remove-AdfsAuthenticationProviderWebContentRemove-AdfsAuthenticationProviderWebContent
Remove-AdfsCertificateRemove-AdfsCertificate
Remove-AdfsClaimDescriptionRemove-AdfsClaimDescription
Remove-AdfsClaimsProviderTrustRemove-AdfsClaimsProviderTrust
Remove-AdfsClientRemove-AdfsClient
Remove-AdfsDeviceRegistrationUpnSuffixRemove-AdfsDeviceRegistrationUpnSuffix
Remove-AdfsFarmNodeRemove-AdfsFarmNode
Remove-AdfsGlobalWebContentRemove-AdfsGlobalWebContent
-Remove-AdfsLocalClaimsProviderTrust新規
Remove-AdfsNonClaimsAwareRelyingPartyTrustRemove-AdfsNonClaimsAwareRelyingPartyTrust
-Remove-AdfsPolicyTemplate新規
Remove-AdfsRelyingPartyTrustRemove-AdfsRelyingPartyTrust
Remove-AdfsRelyingPartyWebContentRemove-AdfsRelyingPartyWebContent
-Remove-AdfsRelyingPartyWebTheme新規
-Remove-AdfsScopeDescription新規
Remove-AdfsWebApplicationProxyRelyingPartyTrustRemove-AdfsWebApplicationProxyRelyingPartyTrust
Remove-AdfsWebThemeRemove-AdfsWebTheme
-Restore-AdfsFarmBehaviorLevel新規
-Revoke-AdfsApplicationPermission新規
Revoke-AdfsProxyTrustRevoke-AdfsProxyTrust
Set-AdfsAdditionalAuthenticationRuleSet-AdfsAdditionalAuthenticationRule
-Set-AdfsApplicationPermission新規
Set-AdfsAttributeStoreSet-AdfsAttributeStore
Set-AdfsAuthenticationProviderWebContentSet-AdfsAuthenticationProviderWebContent
Set-AdfsCertificateSet-AdfsCertificate
Set-AdfsCertSharingContainerSet-AdfsCertSharingContainer
Set-AdfsClaimDescriptionSet-AdfsClaimDescription
Set-AdfsClaimsProviderTrustSet-AdfsClaimsProviderTrust
Set-AdfsClientSet-AdfsClient
Set-AdfsDeviceRegistrationSet-AdfsDeviceRegistration
Set-AdfsDeviceRegistrationUpnSuffixSet-AdfsDeviceRegistrationUpnSuffix
Set-AdfsEndpointSet-AdfsEndpoint
Set-AdfsGlobalAuthenticationPolicySet-AdfsGlobalAuthenticationPolicy
Set-AdfsGlobalWebContentSet-AdfsGlobalWebContent
-Set-AdfsLocalClaimsProviderTrust新規
Set-AdfsNonClaimsAwareRelyingPartyTrustSet-AdfsNonClaimsAwareRelyingPartyTrust
-Set-AdfsPolicyTemplate新規
Set-AdfsPropertiesSet-AdfsProperties
Set-AdfsRegistrationHostsSet-AdfsRegistrationHosts
Set-AdfsRelyingPartyTrustSet-AdfsRelyingPartyTrust
Set-AdfsRelyingPartyWebContentSet-AdfsRelyingPartyWebContent
-Set-AdfsRelyingPartyWebTheme新規
-Set-AdfsScopeDescription新規
Set-AdfsSslCertificateSet-AdfsSslCertificate
Set-AdfsSyncPropertiesSet-AdfsSyncProperties
Set-AdfsWebApplicationProxyRelyingPartyTrustSet-AdfsWebApplicationProxyRelyingPartyTrust
Set-AdfsWebConfigSet-AdfsWebConfig
Set-AdfsWebThemeSet-AdfsWebTheme
-Test-AdfsFarmBehaviorLevelRaise新規
-Test-AdfsFarmBehaviorLevelRestore新規
Test-AdfsFarmInstallationTest-AdfsFarmInstallation
Test-AdfsFarmJoinTest-AdfsFarmJoin
Unregister-AdfsAuthenticationProviderUnregister-AdfsAuthenticationProvider
Update-AdfsCertificateUpdate-AdfsCertificate
Update-AdfsClaimsProviderTrustUpdate-AdfsClaimsProviderTrust
Update-AdfsRelyingPartyTrustUpdate-AdfsRelyingPartyTrust


2015年3月17日火曜日

[Office Preview]Outlook等の多要素認証サポート

発表されてからずっとクローズド・ベータという形となっており、公には音沙汰がなかったOffice2013の多要素認証サポートですが、Office2016 Public Previewという形で出てきました。

 Office Blog
  Announcing the Office 2016 IT Pro and Developer Preview


発表によると、DLP(Data Loss Prevension/情報漏えい防止)やIRM(Information Rights Management)に加えて、OutlookのADALサポートが発表されています。

Multi-factor authentication. With this release of the Outlook client, we’ll support multi-factor authentication through integration with the Active Directory Authentication Library (ADAL)

これまでブラウザベースでのOffice365利用では多要素認証などによるクライアントデバイス制御を実装出来ましたが、ws-trustを使うMSOnline Signin Assistant経由のリッチクライアント(OutlookやLyncのCommunicator)では細かい制御ができませんでした。
今回、ADALベースとなることで、OAuth2.0 JWTベースとなるはずなので、Office365を使う場合に以下のメリットが得られます。
  • AD FSでIdPを構成していてOutlook/Communicatorを使う場合はWAP/AD FS Proxyを使ってws-trustのエンドポイントをインターネットに公開する必要がありましたが、パッシブ・プロトコルへの変更となるため、社内利用に限ればWAP/AD FS Proxyが不要
  • 同じ理由で.localドメインでの構成が容易に
  • 同じ理由で公開用の証明書が不要に(社内だけで使うオレオレ証明書でOK)
  • サードパーティIdPを構成してOutlook/Communicatorを使う場合、ws-trustやSAML ECPに対応したIdPが必要でしたが、単純にws-federation/SAML WebSSO Profileで対応可能なので相当ハードルが下がる

是非Connectサイトから申し込んで、試してみましょう。


参考)以前のPOST
 Office2013 Windowsクライアントが多要素認証とSAML IdPサポート




2015年3月13日金曜日

[Windows10/AAD]OOBEでクラウド・ドメイン参加

※PIN入力がうまく行ったので少し追記しました。
※うまく行く条件が判明しました。AADのユーザの姓名に日本語があるとNGです。

先日の続きです。

 [Windows10/AAD]クラウド・ドメイン参加を試す
 http://idmlab.eidentity.jp/2015/02/windows10aad.html

先日は一旦LiveアカウントでWindows10にログインした後、組織のアカウントでクラウド・ドメイン参加をしましたが、今回はsysprep後の初期セットアップ中にいきなり組織のアカウントでログインします。
(先日のポストでうまく行かなかった部分のフォローアップです)


前提となるAzureAD側の準備は先日のポストと何も変わりません。

PC側の手順は以下の通りです。

①PCを初期起動すると、ライセンスキーの入力を始め、色々と設定を入れる画面が出てきますが、まず[Shift+F10]を押してコマンドプロンプトを起動します。

②そしてレジストリエディタ(regedit.exe)を起動すると、いきなり「HKLM\Software\Microsoft\Windows\CurrentVersion\OOBE\TestHooks」が開いた状態になっていますので、表示されているキー「TestBlockAadWebApp」を消してしまいます。

③PCを問答無用で再起動します。

④うまく行けば、「このPCを所有しているのは誰ですか?」と聞いて来ます。
 この画面が出なければ再起動を繰り返します。私は3回くらい再起動したら出ました。どうやらタイミングの問題の様です。

⑤ここまでくれば前回と同じなので、組織のアカウントでログインします。
⑥PCにログインした後、AzureADのユーザの情報を見るとデバイスが登録されているのがわかります。




ディレクトリ同期されている環境だと、このデバイス情報がオンプレミスのADにも同期されるようですが、現状はうまく同期されません。おそらく同期ルールがまだ対応していない、もしくはAD FSのDRSで拡張するオンプレADスキーマがクラウド・ドメイン参加のデバイスに対応していないんだと思います。

また、PCにログインした後、「クラウド体験ホスト」が自動的に起動してきてPINの登録が求められるんですが、これがやたらと不安定で、なかなかうまくPIN登録画面にたどり着かず、「Something went wrong」と言われてしまいます。
ここでPIN登録まで終わるとNGC(Next Generation Credentials)のセットアップ・フェーズが完了するはずなんですが、中々うまく行かないものですね・・・。

⇒試行錯誤していたらPIN入力画面が出てきました。
 関係性はわかりませんが、デバイス登録したユーザとは別のAADユーザでログインしたらPIN登録画面が出ました。
 ⇒姓・名に日本語が入っているユーザだとダメなようです。Previewの間は英語名のユーザを使うしかありませんね。

PINを使ってログオンできるようになります。


尚、この状態だとVisualStudio OnlineについてはPCログインとブラウザログオンがSSOされるようです。(初回ブラウザ起動時にID/PWDを入力するとクレデンシャルが保持される仕組みっぽい)
※Cookieとか全部消すとやり直せます。
※Office365でも試してみましたが、こちらはまだダメでした。



今後に期待です。