Quantcast
Channel: IdM実験室
Viewing all 771 articles
Browse latest View live

[JWT/OAuth]Service Accountを使ってGoogle APIを利用する②

$
0
0
前回の続きです。

前回はGoogle Developer ConsoleおよびGoogleAppsの管理ダッシュボードでGoogle側の設定をするところまでを紹介しましたので、今回は実際にサービスアカウントを使ってAPIを利用するためのアクセストークンを取得してみます。

◆リクエストの仕様
Googleの公式ドキュメントを見るとアクセストークンを取得するためには、JWTを生成してトークンエンドポイントへPOSTする必要があるようです。

リクエストの仕様
エンドポイントhttps://www.googleapis.com/oauth2/v3/token
メソッドPOST
パラメータgrant_typeurn:ietf:params:oauth:grant-type:jwt-bearer
assertion作成したJWT


※ちなみにGoogleが提供している.Net用のクライアントライブラリの通信をキャプチャしてみるとエンドポイントアドレスがドキュメントに記載されているものとは異なり、https://accounts.google.com/o/oauth2/tokenとなっています。(ライブラリ側が古いまま?)

また、POSTするJWTは以下の通りの形である必要があるようです。

JWTの仕様
署名アルゴリズムRSA-SHA256
必要なクレームissサービスアカウントのメールアドレス
scope利用するAPIのスコープ
audhttps://www.googleapis.com/oauth2/v3/token
expトークンの有効期限To
iatトークンの有効期限From


尚、エンタープライズシナリオにおいて特定の管理者がAPIを実行したことを記録していくような場合においては、上記のクレームにsubを追加して管理者メールアドレスを設定することでロギングが出来るようになります。

◆JWTを生成する
・.Net標準のJwtSecurityTokenHandlerを利用する
せっかくマイクロソフト謹製のJWTを扱うライブラリがあり、Azure Active Directory(AzureAD)へのアクセス用のサンプルではほぼ100%このライブラリを使っているので、まずはこちらを使ってJWTを生成してみます。

このライブラリを使うことでコーディング量をかなり削減できるので、うまく使えればかなり楽に開発が出来るはずです。

使うのは、NuGetで提供されている以下のパッケージです。
 名称:JSON Web Token Handler For the Microsoft .Net Framework 4.5
 作成者:Microsoft Open Technologies.
 識別:System.IdentityModel.Tokens.Jwt
 バージョン:4.0.1

JWTを生成するときはシンプルにJwtSecurityTokenに必要なクレーム情報を指定してインスタンスを生成するだけです。

var token = new JwtSecurityToken(
SERVICE_ACCOUNT, // iss
TOKEN_ENDPOINT, // aud
claims, // additional claims
issuedTime, // iat
expiresTime, // exp
credentials); // 署名用のクレデンシャル

固定でiss/aud/iat/exp/credentialを引数で指定するのに加えて、追加のクレームについてはIEmurerable claimsで列挙型の引数を渡す形になるので、必要なクレームは事前にClaim型で定義しておきます。

var claims = new[]
{
// 「クレーム名,値」のセット
new Claim("scope", SCOPE)
};

また、署名についてはGoogleからダウンロードした鍵(.p12ファイル)から作成します。

var certificate = new X509Certificate2(
CERTIFICATE_FILE, // .p12ファイル
CERTIFICATE_PWD, // 秘密鍵のパスワード(notasecret)
X509KeyStorageFlags.Exportable);
var credentials = new X509SigningCredentials(certificate);


JWT自体はこれで簡単に生成できるので、ハンドラのインスタンスを生成し、JWTを渡します。
こちらも非常に簡単で、

var handler = new JwtSecurityTokenHandler();
でハンドラは生成でき、

var strJWT = handler.WriteToken(token);
とすればBase64Urlエンコードされた、[ヘッダ].[ペイロード].[署名]が文字列として返ってきます。
この文字列をGoogleのトークンエンドポイントへassertionとしてPOSTしてやれば良いはずです。


出来上がったコードはこんな感じになります。
とてもシンプルです。

static string CreateJWT()
{
// signing certificate
// pfx(.p12) file which is downloaded from Google Developer Console
var certificate = new X509Certificate2(
CERTIFICATE_FILE,
CERTIFICATE_PWD,
X509KeyStorageFlags.Exportable);
var credentials = new X509SigningCredentials(certificate);

// token lifetime
var issuedTime = DateTime.UtcNow;
var expiresTime = issuedTime.AddMinutes(55);

// additional claims
var claims = new[]
{
// add scope claim
new Claim("scope", SCOPE)
};

// create jwt token
var token = new JwtSecurityToken(
SERVICE_ACCOUNT, // iss
TOKEN_ENDPOINT, // aud
claims, // additional claims
issuedTime,
expiresTime,
credentials);

var handler = new JwtSecurityTokenHandler();

// exception in WriteToken method
return handler.WriteToken(token);

}



では、早速実行してみましょう。


はい、怒られました。
Googleの秘密鍵のキー長は1024bitなんですが、このライブラリは最低でも2048bitを要求しているようです。
残念です。
今後のGoogleもしくはMicrosoftに期待しましょう。


・スクラッチでJWTを生成するコードを書く
仕方がないのでスクラッチでコードを書きます。と言っても基本はJSONの取り扱いと署名だけなので、それほど複雑にはなりません。
JSONの扱いは、マイクロソフトのサンプルコードでもよく使われているNewtonsoftのJson.NETパッケージを使います。こちらもNuGetで提供されています。
 名称:Json.NET
 作成者:James Newton-King
 識別:Newtonsoft.Json
 バージョン:6.0.7

◇ヘッダ部
求めるのは、{ alg = "RS256", typ = "JWT" }というJSONなのでまずはJson.NETを使ってバイト配列を作成します。

var header = new { alg = "RS256", typ = "JWT" };
var headerSerialized = JsonConvert.SerializeObject(header,Formatting.None);
var headerBytes = Encoding.UTF8.GetBytes(headerSerialized);

その後、作成したバイト配列をBase64Urlエンコードするのですが、JWTの作者でもあるMicrosoft ResearchのMike Jonesがスペック(ドラフト)のAppendixにC#のサンプルコードを載せてくれているので、そちらを使います。
 参考URL)
 http://self-issued.info/docs/draft-goland-json-web-token-00.html


private static string Base64UrlEncode(byte[] input)
{
var output = Convert.ToBase64String(input);
output = output.Split('=')[0]; // Remove any trailing '='s
output = output.Replace('+', '-'); // 62nd char of encoding
output = output.Replace('/', '_'); // 63rd char of encoding
return output;
}

こちらを使って先ほどのバイト配列をエンコードします。

var headerEncoded = Base64UrlEncode(headerBytes);


◇ペイロード部
基本的な考え方はヘッダ部と同じです。必要なJSONは先に挙げた仕様通りなので、以下のようなコードになります。

var payload = new
{
iss = SERVICE_ACCOUNT, // iss
scope = SCOPE, // scope
aud = TOKEN_ENDPOINT, // aud
exp = exp, // exp
iat = iat // iat
};
var payloadSerialized = JsonConvert.SerializeObject(payload,Formatting.None);
var payloadBytes = Encoding.UTF8.GetBytes(payloadSerialized);
var payloadEncoded = Base64UrlEncode(payloadBytes);


◇署名部
ここまで作成したヘッダとペイロードを"."(ピリオド)でつないだ文字列を先の秘密鍵を使って署名します。
ポイントはRSACryptoServiceProviderを生成する際のパラメータにキー長をちゃんと設定してあげることです。(certificate.PrivateKey.KeySizeで取得できます。先に説明した通りGoogleの場合、1024bitです)

こちらも同じく作成した署名部分のバイト配列をBase64Urlエンコードして文字列を生成します。
こんなコードになります。


RSAParameters rsaPara = ((RSACryptoServiceProvider)(certificate.PrivateKey)).ExportParameters(true);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(certificate.PrivateKey.KeySize);
rsa.ImportParameters(rsaPara);
Byte[] target = Encoding.UTF8.GetBytes(headerEncoded + "." + payloadEncoded);
byte[] signBytes = rsa.SignData(target, new SHA256Managed());
var signEncoded = Base64UrlEncode(signBytes);


◇JWTの生成
Googleに渡すJWTはヘッダ、ペイロード、署名を"."(ピリオド)で連携した文字列である必要があるので、単純に文字列を連結します。

var strJWT = headerEncoded + "." + payloadEncoded + "." + signEncoded;


出来上がったコードはこんな感じになります。
先ほどよりはコード量は多いですが、それでもシンプルです。

static string CreateJWT()
{
// signing certificate
// pfx(.p12) file which is downloaded from Google Developer Console
var certificate = new X509Certificate2(
CERTIFICATE_FILE,
CERTIFICATE_PWD,
X509KeyStorageFlags.Exportable);

// 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;


// header
var header = new { alg = "RS256", typ = "JWT" };
var headerSerialized = JsonConvert.SerializeObject(header,Formatting.None);
var headerBytes = Encoding.UTF8.GetBytes(headerSerialized);
var headerEncoded = Base64UrlEncode(headerBytes);

// payload
var payload = new
{
iss = SERVICE_ACCOUNT,
scope = SCOPE,
aud = TOKEN_ENDPOINT,
exp = exp,
iat = iat
};
var payloadSerialized = JsonConvert.SerializeObject(payload,Formatting.None);
var payloadBytes = Encoding.UTF8.GetBytes(payloadSerialized);
var payloadEncoded = Base64UrlEncode(payloadBytes);

// signature
RSAParameters rsaPara = ((RSACryptoServiceProvider)(certificate.PrivateKey)).ExportParameters(true);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(certificate.PrivateKey.KeySize);
rsa.ImportParameters(rsaPara);
Byte[] target = Encoding.UTF8.GetBytes(headerEncoded + "." + payloadEncoded);
byte[] signBytes = rsa.SignData(target, new SHA256Managed());
var signEncoded = Base64UrlEncode(signBytes);

// concatinate header + payload + signature
return headerEncoded + "." + payloadEncoded + "." + signEncoded;

}


実行すると単純に文字列を生成しているだけなので問題なく
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3Mi..
という文字列が取得できます。

後はGoogleにこれをPOSTするだけです。

◆アクセストークンのリクエストを投げる
こちらは単純にHTTP POSTするだけなのでhttpClientを使います。

POSTするためのメソッドを用意しておき、パラメータをセットして実行するだけです。

こんな非同期メソッドを用意しておいて、、、

private static async Task<string> Post(string url, Dictionary<string, string> param)
{
string result = "";
try
{
HttpClient httpClient = new HttpClient();
httpClient.MaxResponseContentBufferSize = int.MaxValue;
HttpContent content = new FormUrlEncodedContent(param);
var response = await httpClient.PostAsync(url, content);
String text = await response.Content.ReadAsStringAsync();
result = text;
}
catch (Exception Err)
{
result = "ERROR: " + Err.Message;
}
return result;
}

こんな感じでリクエストを投げ込みます。

Task task = Task.Factory.StartNew(async () =>
{
string result = await Post(
TOKEN_ENDPOINT,
new Dictionary<string, string>() {
{ "assertion" , request_jwt }, // 先ほど生成したJWT
{ "grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer" }});
Console.WriteLine("Access Token request result :\n{0}", result);
}).Unwrap();
task.Wait();

結果、こんな感じでアクセストークンが取得できます。


後は各APIを利用する際にアクセストークンを提示してあげればOK、という話です。


◆まとめ
サービスアカウントを使ってアクセストークンを取得するところまで解説しました。
どこにもユーザが介在せずにAPIを実行するために必要なトークンが取得できることがわかりましたので、サーバアプリケーションを使う場合は、この方法を使うことになります。
尚、本当は折角なのでマイクロソフト標準のJwtSecurityTokenHandlerを使えればAzureAD用とGoogleApps用でモジュールが簡単に共通化出来るかと思ったのですが、まだまだ発展途上?ということがわかりましたので、今後の対応に期待です。


最後にNGパターンを含めコードを載せておきます。


using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace GetAccessToken
{
class Program
{

//
// Constants
//
static string TOKEN_ENDPOINT = "https://www.googleapis.com/oauth2/v3/token";
static string SERVICE_ACCOUNT = "10.......kvghppo@developer.gserviceaccount.com";
static string SCOPE = "https://www.googleapis.com/auth/admin.directory.user";
static string CERTIFICATE_FILE = @"C:\Users\testuser\Downloads\FIMMA-8ce3eefa8ca2.p12";
static string CERTIFICATE_PWD = "notasecret";

//
// Common Library
//
private static string Base64UrlEncode(byte[] input)
{
var output = Convert.ToBase64String(input);
output = output.Split('=')[0]; // Remove any trailing '='s
output = output.Replace('+', '-'); // 62nd char of encoding
output = output.Replace('/', '_'); // 63rd char of encoding
return output;
}

//
static string OK_RSA256()
{
// signing certificate
// pfx(.p12) file which is downloaded from Google Developer Console
var certificate = new X509Certificate2(
CERTIFICATE_FILE,
CERTIFICATE_PWD,
X509KeyStorageFlags.Exportable);

// 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;


// header
var header = new { alg = "RS256", typ = "JWT" };
var headerSerialized = JsonConvert.SerializeObject(header,Formatting.None);
var headerBytes = Encoding.UTF8.GetBytes(headerSerialized);
var headerEncoded = Base64UrlEncode(headerBytes);

// payload
var payload = new
{
iss = SERVICE_ACCOUNT,
scope = SCOPE,
aud = TOKEN_ENDPOINT,
exp = exp,
iat = iat
};
var payloadSerialized = JsonConvert.SerializeObject(payload,Formatting.None);
var payloadBytes = Encoding.UTF8.GetBytes(payloadSerialized);
var payloadEncoded = Base64UrlEncode(payloadBytes);

// signature
RSAParameters rsaPara = ((RSACryptoServiceProvider)(certificate.PrivateKey)).ExportParameters(true);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(certificate.PrivateKey.KeySize);
rsa.ImportParameters(rsaPara);
Byte[] target = Encoding.UTF8.GetBytes(headerEncoded + "." + payloadEncoded);
byte[] signBytes = rsa.SignData(target, new SHA256Managed());
var signEncoded = Base64UrlEncode(signBytes);

// concatinate header + payload + signature
return headerEncoded + "." + payloadEncoded + "." + signEncoded;

}

// occur following error.
// IDX10630: The 'System.IdentityModel.Tokens.X509AsymmetricSecurityKey' for signing cannot be smaller than '2048' bits.
// cause: Google's certificate key length is 1024bits, but JwtSecurityTokenHandler/WriteToken requires 2048bits key.
static string NG_RS256()
{
// signing certificate
// pfx(.p12) file which is downloaded from Google Developer Console
var certificate = new X509Certificate2(
CERTIFICATE_FILE,
CERTIFICATE_PWD,
X509KeyStorageFlags.Exportable);
var credentials = new X509SigningCredentials(certificate);

// token lifetime
var issuedTime = DateTime.UtcNow;
var expiresTime = issuedTime.AddMinutes(55);

// additional claims
var claims = new[]
{
// add scope claim
new Claim("scope", SCOPE)
};

// create jwt token
var token = new JwtSecurityToken(
SERVICE_ACCOUNT, // iss
TOKEN_ENDPOINT, // aud
claims, // additional claims
issuedTime,
expiresTime,
credentials);

var handler = new JwtSecurityTokenHandler();

// exception in WriteToken method
return handler.WriteToken(token);

}

static void Main(string[] args)
{
string request_jwt = null;

// NG : use System.IdentityModel.Tokens.jwt
// Cause : JwtSecurityTokenHandler only supports 2048bit certificate for signature.
//request_jwt = NG_RS256();

// OK : use custom logic
request_jwt = OK_RSA256();

Console.WriteLine("Access token request jwt :\n{0}", request_jwt);

Task task = Task.Factory.StartNew(async () =>
{
string result = await Post(
TOKEN_ENDPOINT,
new Dictionary<string, string>() {
{ "assertion" , request_jwt },
{ "grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer" }});

Console.WriteLine("Access Token request result :\n{0}", result);
}).Unwrap();
task.Wait();
Console.WriteLine("End");
Console.ReadKey();

}

private static async Task<string> Post(string url, Dictionary<string, string> param)
{
string result = "";
try
{
HttpClient httpClient = new HttpClient();
httpClient.MaxResponseContentBufferSize = int.MaxValue;
HttpContent content = new FormUrlEncodedContent(param);
var response = await httpClient.PostAsync(url, content);
String text = await response.Content.ReadAsStringAsync();
result = text;
}
catch (Exception Err)
{
result = "ERROR: " + Err.Message;
}
return result;
}
}

}

[AAD]Graph API 1.5のGAとスキーマ拡張+GUIツール公開

$
0
0
12月末にリリースされたGraph API ver. 1.5を使うことによりAzure Active Directory上のオブジェクトのスキーマの拡張がGraph API経由で出来るようになりました。
合わせて、Graph APIライブラリのver. 2.xがリリースされ、自分でREST APIを実行するクライアントを実装しなくても簡単にGraph APIが実行できるようになっています。

関連ポスト
- Active Directory Team のblog
  Improved Azure AD Graph API and Client libraries for .Net, Android, iOS and much more!

- Windows Azure Active Directory Graph Team のblog
  Announcing Azure AD Graph API Client Library 2.0

  Announcing the new version of Graph API: api-version=1.5


と言っても、結局は自分でライブラリを使ったアプリケーションを作って、、となるとハードルも高いので、新しいAPIを試しがてらGUIツールを作ってみました。
Baby Metal武道館ライブのBluRayを見ながら2時間くらいで実装したのでかなり適当ですのであしからず。試す時は試験用のディレクトリを使ってください。何が起きても責任は負えません)


こんな感じでGUIで拡張プロパティが登録できます。
(ちなみにRemoveも実装しているのですが、現状うまく動きません。消したいときはREST Clientなどで直接消してください)

ダウンロード、詳しい説明はこちらよりどうぞ(英語ですみません)
 - Codeplex : Azure Active Directory Extended Schema Manager
     https://aadschema.codeplex.com/


詳細手順はCodeplexにも書きましたが、Azure Active Directory上にアプリケーションを一つ定義してあげる必要があります。そのアプリケーションにディレクトリの読み書きの権限を与えて、アプリケーションを通してスキーマを触っています。

必要なのは、以下です。
・アプリケーションの登録(Webアプリケーション/WebAPIとして登録)

・ClientId/Keyの取得

・Azure Active DirectoryへのRead/Write権限の付与


そのうち、Azureの管理ポータルからも触れるようになる気もしていますが、それまでに手軽に試してみたい方はどうぞ。

[AADSync/DirSync]同期に使うAzureAD管理者アカウントの管理

$
0
0
twitterで少し話題に上ったので、色々と調べ&試してみました。

きっかけは、複数企業(マルチドメイン)で一つのAzure Active Directory(AzureAD)テナントを共同利用するようなケースにおいて、各企業のオンプレミスActive Directoryから各社のユーザをAADSyncやDirSyncを使って同期する場合にAADSyncやDirSyncに設定するAzureADの管理者アカウントをどのように管理するべきなのか?という議論でした。

同期に利用するAzureAD上のユーザアカウントはテナントの全体管理者の権限が必要なので、同じAzureADテナント上のユーザやグループであれば他企業のものであっても管理することが権限上は可能となってしまいます。

参考)AADSyncに必要なAzureADアカウントの権限等
 http://msdn.microsoft.com/en-us/library/azure/dn757602.aspx
 ・必要な要件
  全体管理者ロールを持ったアカウントを利用すること
 ・推奨事項
  ①パスワード期限を無期限に設定すること(パスワードを16文字以上の強固なものにすること)
  ②AADSync専用のアカウントを作成すること


そこで、各AADSyncに設定する管理アカウントの権限をうまく制限出来ないか?という話になります。

まず、テナント内のユーザ情報の閲覧・更新を行うには、以下の4つの方法が考えられます。
①管理ポータルへアクセスする
②PowerShellのコマンドレット(Get-MsolUser等)を使う
③AADSyncの内部(Connector Space)を参照する
④GraphAPIを使う

AADSyncに設定するユーザで上記①~④を実行できなければよいのですが、結論としてはすべてを満たすのは無理なのですが、それぞれどのような状態になるのかを紹介してみます。

①管理ポータルへのアクセスを制限する
 これは比較的簡単です。
 単純にAzureのサブスクリプションを対象のアカウントに紐づけなければ済む話です。
 管理ポータルにアクセスしても以下の画面が表示され、ディレクトリの管理までたどりつけません。



②PowerShellのコマンドレットの実行を制限する
 まず、テナント中の特定ドメインのユーザのみを管理する、という思想がないのでコマンドレットの内部での権限分離は絶望的です。
 となると、コマンドレット自体を実行できないようにするには?という話になってきます。

 対策案としては、各企業に配る同期用ユーザのMFA(多要素認証)を有効にしてしまう、ということが考えられます。こうすれば勝手に各企業管理者が同期用ユーザを使って何かをしようとしても追加認証(例えばSMS通知)を抑えておけば勝手にログインすることはできなくなります。(当然管理ポータルへもログインできなくなります)

 これで問題ないのではないか?と思い、いざAADSyncの設定を行おうとすると認証エラーが出てしまいます。


 ちなみに設定時はMFAを設定せずに後からMFAを設定すると同期エラー(stopped-extension-dll-exception)が出ます。


 イベントログを見るとやはり認証エラーが出ています。



 次に試すのは多要素認証をONにして、アプリケーションパスワードを使ってAADSyncの設定をしてみます。
 結果、エラー内容は変わりますが、やはりだめです。



Technetのアプリケーションパスワードの説明を見ると、以下の記述があります。(強調は筆者追加)
 http://technet.microsoft.com/ja-jp/library/dn270518.aspx

[多要素認証をサポートしないブラウザー以外のクライアントに必要なアプリ パスワード] 多要素認証がユーザーのアカウントで有効になると、Outlook や Lync などの大半のブラウザー以外のクライアントでアプリ パスワードを使用できますが、そのユーザーが管理アカウントを保持している場合でも、Windows PowerShell などのブラウザー以外のアプリケーションではアプリ パスワードを使用した管理操作は実行できない点に注意してください。Powershell スクリプトを実行するための強力なパスワードでサービス アカウントを作成し、そのアカウントで多要素認証を有効にしないでください

クライアントがオンプレミスとクラウドの両方の自動検出エンドポイントと通信するハイブリッド環境ではアプリ パスワードは機能しない - オンプレミスでの認証にはドメイン パスワードが必要で、クラウドでの認証にはアプリ パスワードが必要なので、クライアントがオンプレミスとクラウドの両方の自動検出エンドポイントと通信するハイブリッド環境では、アプリ パスワードが機能しないことに注意してください。


 中々対応は難しそうです。
 ただ、このあたりを見ると
 「現在、Windows PowerShell 用 Azure Active Directory はアプリ パスワードに対応していません。」
 とあるので、将来的にはサポートするのかも知れません。


③AADSyncの内部(Connector Space)を参照を制限する
 Synchronization Service Manager(miisclient.exe)の利用を制限することは無理ですので、Connector SpaceやMetaverseの中身を見ればAzureADからのImportやSynchronizationジョブで同期されたユーザ一覧が参照できてしまいます。
 ここで自社のユーザ以外を見れなくしようとするとあらかじめルールエディタでフィルタを設定する必要がありますが、当然あとから設定を変えることも可能なので、完全に制限をかけるのは無理です。



④GraphAPIを使わせない
 これは割と簡単です。
 GraphAPIを使うにはAzureAD上にクライアントアプリケーションを登録する必要がありますが、登録作業は管理ポータルから実施するため、①の方法で管理ポータルへアクセスできないようにしておけばOKです。



◆まとめ
現状、同一AzureADテナント内に複数ドメインをホストし、ドメイン毎に管理アカウントの権限を完全に分離するのは不可能
⇒MFAを有効にしたり、アプリケーションパスワードを使うとAADSyncでの同期に支障が出るので対策とはならない。

とりあえず、セキュリティの境界を分けたければテナントを分けましょう、ということですね。


[AADSync/DirSync]同期に使うAzureAD管理者アカウントの管理(続)

$
0
0
昨日のポストに引き続きAzureADの管理者アカウントの話です。

タケさんより、AADSyncに仕込む管理者アカウントをFederationユーザにしたらどう?というコメントを頂きましたので、どうなるのかちょっと試してみました。
※昨日のコメント欄を見ていただければわかると思いますが、ws-trust/saml-ecpなどのActiveEndpointのことをすっかり忘れていましたので、当然FederationユーザはAADSyncやPowerShellでは使えないと思い込んでいました。タケさんありがとうございました。


結果、もともとの課題(シングルテナントに複数のドメインを定義し、各ドメイン毎にAADSyncを入れてオンプレADと同期、ただしドメイン間でユーザ情報の閲覧などはさせたくない)については解決は出来なかったのですが、管理者アカウントの制御を含め別の使い方も出来そうなので、簡単にまとめておきます。

構築したのは下図のような環境です。


AADSyncやPowerShellなどMicrosoft Online Serviceサインインアシスタント経由の通信はAzure Active Directory(AzureAD)上に登録したドメインに設定されたActiveUriへws-trustやSAML(ECP)で通信して認証されるので、ActiveUrlだけをインターネットに公開し、Webブラウザ経由でアクセスされるPassiveUriは.localドメインなど社内ネットワークからのみアクセスできるアドレスを設定します。
この設定により、AADSyncなどに設定するAzureAD管理者アカウントとパスワードを知っていてもW社外ユーザは、社内にあるIdPに到達できないため、Webアプリケーションは使えない、という環境が作れます。

具体的な設定ですが、一旦は.localドメインでAD FSを構築し、AzureADとSSO設定を行った後、「Set-MsolDomainFederationSettings」コマンドレットでActiveLogOnUriプロパティのURIを外部公開しているURIに変更する、という方法をとりました。

設定した結果はこんな感じです。
> Get-MsolDomainFederationSettings -DomainName example.com

ActiveLogOnUri : https://adfs.example.com/adfs/services/trust/
2005/usernamemixed
FederationBrandName : eIdentity
IssuerUri : http://adfs.eidentity.local/adfs/services/trus
t
LogOffUri : https://adfs.eidentity.local/adfs/ls/
MetadataExchangeUri : https://adfs.eidentity.local/adfs/services/trust/mex
NextSigningCertificate :
PassiveLogOnUri : https://adfs.eidentity.local/adfs/ls/
SigningCertificate : MIIC9DCCAdygAwIBAgIQSjWgIWhJdKVN1NL85LCH3zANBgkqhkiG9w
0BAQsFADA2MTQwMgYDVQQDEytBREZTIFNpZ25pbmcgLSBhZGZzLWFh




ActiveLogOnUriのみ外部公開ドメインになっていて、後は.localになっているのがわかります。
これで、AADSyncに設定する管理アカウントにFederationユーザを設定しても問題なく認証が通るようになります。

ただ、昨日のポストでも書いたように、
・PowerShellが使えるのでGet/Set-MsolUserコマンドレットなどでユーザ一覧は参照・更新可能
・Synchronization Service ManagerのConnector SpaceやMetaverseでユーザ一覧を参照可能
・当然カスタムルールを書けば他ドメインのユーザを更新や削除も可能
なので、シングルテナント・マルチドメインの環境でドメイン単位でセキュリティ境界を作るのは困難なのは変わりません。

[AzureAD]管理者アカウントでAzureにサインアップする

$
0
0
AzureAD上に作成(もしくはオンプレミスADから同期)したユーザに全体管理者ロールを与えておき、そのユーザで別のAzureサブスクリプションへサインアップするとどうなるのか?を試してみました。

前々回のポストで全体管理者としてアサインしたユーザが他のユーザ情報を参照・編集してしまうのを防ぐには、という話題で初期状態で管理ポータルへアクセス出来ないので、、ということを紹介しました。
ただし、その管理者アカウントでAzureサブスクリプションを新規にサインアップしてしまえば管理ポータルにアクセスできてしまうので、やはり注意が必要です。
これを防ぐには前回のポストで紹介したようにWebアプリケーションの認証を行う際にIdPへネットワーク的にアクセスできないように構成するなど別の対策が必要になります。

実際にどうなるのかを試してみます。(かなり当たり前な結果ばかりですが)
全体管理者アカウントでサインアップして管理ポータルにアクセスすると以下のような状態になります。


最初から自分が管理者となっているAzure Active Directory(AzureAD)のディレクトリが見えています。

開いてみると、当然全ての操作が可能です。


柔軟に色々なことができるAzureADのアイデンティティ管理ですが、何をしたら何が起きるかをしっかり把握しておかないと危ないので、しっかり把握しておくことが大切です。

尚、当該のアカウントに多要素認証設定をしておくと最初からアカウントの管理メニューに追加の認証に関する項目が出てきます。(ちなみにこのユーザ、OpenAMで認証するように構成してあるユーザなので、ポータルにアクセスすると、OpenAMにリダイレクトされ認証された後、AzureADの多要素認証が実行されます)


[AzureAD]管理者アカウントの権限の絞り込み

$
0
0
注)現在Public Previewとして提供されている機能について紹介しているため、正式版がリリースされるタイミングで機能が変更になる可能性がありますのでご承知おきください。

ここしばらくAzure Active Directory(AzureAD)の管理アカウントの権限の絞り込みについて試行錯誤をしてきましたが、今回は現在Public Previewとして提供されている「Administrative Units(管理単位)」の機能について紹介します。
今のところ、やりたいことに一番近い機能はこれかも知れません。

まず、おさらいですが、やりたいことは以下の通りでした。

  • シングルテナントのAzureADに複数のドメインを作成する
  • 複数の企業や組織が各ドメインを使用、各組織のオンプレADからユーザを同期する
  • 各組織の管理者は自ドメインのユーザのみを管理したい


これまでのポストでは多要素認証やFederationを使って各ドメインの管理者アカウント(AADSyncに設定するユーザ)の権限を制限しようとしましたが、うまい方法はありませんでした。
 [AADSync/DirSync]同期に使うAzureAD管理者アカウントの管理
 [AADSync/DirSync]同期に使うAzureAD管理者アカウントの管理(続)
 [AzureAD]管理者アカウントでAzureにサインアップする


今回は昨年12月にPublic Preview公開されたAdministrative Units(管理単位)を使ってみます。
この機能はAzureADのディレクトリを論理的な単位に分割し、それぞれの管理権限をユーザへ委譲するための仕組みです。(オンプレActive DirectoryでOU単位で管理権限を委譲するのと同様の考え方です)

想定ケースの例として地域ごとに管理者をアサインするようなケースがあげられています。


Active Directoryチームのblog
 Wrapping up the year with a boat load of Azure AD news!

MSDNドキュメント
 管理単位の管理 - パブリック プレビュー


では、簡単に試してみます。

現状はPowerShellコマンドレットでしか操作が出来ませんので、PowerShellを使います。
必要なWindows Azure Active Directory管理PowerShellモジュールのバージョンは1.0.8070.2以上です。

以下のコマンドで使っているバージョンがわかります。
> (get-item C:\Windows\System32\WindowsPowerShell\v1.0\Modules\MSOnline\Microsoft.Online.Administration.Automation.PSModule.dll).VersionInfo.FileVersion

⇒現状の最新版だと「1.0.8262.2」が出てきます。


以下の順に操作をします。(特定のAU以下のユーザしか管理出来ないように管理者の権限を制限します)
①グローバル管理者でAzureADに接続する
②管理単位(AU)を作成する
③管理単位(AU)に管理対象ユーザを追加する
④管理者ユーザにスコープ付管理ロールを付与する

結果的に言いますと、管理者は③で管理対象ユーザについてだけ「更新」が出来るようになります。
つまり、
・管理対象外ユーザの参照は出来てしまう
・新規にユーザを作成したり、削除することは出来ない
ということなので、やはり元々やりたかったことは実現出来ません。(当然AADSyncに管理者アカウントとして設定してもユーザの作成などが出来ないので実質使えません)


とりあえず現状出来ることを見てみます。

AU名TestAU
AUメンバkenshinu@example.com
AU管理者auadmin@example.com


◆設定
①グローバル管理者でAzureADに接続する
> Connect-MsolService

②管理単位(AU)を作成する
> New-MsolAdministrativeUnit -DisplayName "TestAU" -Description "Test AU"

ExtensionData Description DisplayName ObjectId
------------- ----------- ----------- --------
System.Runtime.S... Test AU Test AU edfd9c4a-e529-46...

③管理単位(AU)に管理対象ユーザを追加する
> $au = Get-MsolAdministrativeUnit -SearchString "TestAU"
> $user = Get-MsolUser -UserPrincipalName "kenshinu@example.com"
> Add-MsolAdministrativeUnitMember -AdministrativeUnitObjectId $au.ObjectId -AdministrativeUnitMemberObjectId $user.ObjectId

④管理者ユーザにスコープ付管理ロールを付与する
> $role = Get-MsolRole -RoleName "User Account Administrator"
> $admin = Get-MsolUser -UserPrincipalName "auadmin@example.com"
> Add-MsolScopedRoleMember -RoleObjectId $role.ObjectId -AdministrativeUnitObjectId $au.ObjectId -RoleMemberObjectId $admin.ObjectId

◆確認
①管理者ユーザでAzureADに接続する
> Connect-MsolService

②ユーザ一覧を参照する
> Get-MsolUser

UserPrincipalName DisplayName isLicensed
----------------- ----------- ----------
mitsuhidea@example.net Mitsuhide Akechi True
nfujie@hoge.onmicrosof... 富士榮尚寛 True
auadmin@example.com AU Admin False
kenshinu@example.com Kenshin Uesugi True
⇒残念ながら全員見えてしまいます。

②管理対象ユーザを更新する
> Set-MsolUser -UserPrincipalName kenshinu@example.com -UsageLocation CA
⇒問題なく更新できます

③管理対象外ユーザを更新する
> Set-MsolUser -UserPrincipalName mitsuhidea@example.net -UsageLocation CA
Set-MsolUser : Access Denied. You do not have permissions to call this cmdlet.
発生場所 行:1 文字:1
+ Set-MsolUser -UserPrincipalName mitsuhidea@example.net -UsageLocatio ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~
+ CategoryInfo : OperationStopped: (:) [Set-MsolUser], MicrosoftO
nlineException
+ FullyQualifiedErrorId : Microsoft.Online.Administration.Automation.Acces
sDeniedException,Microsoft.Online.Administration.Automation.SetUser
⇒権限がないって言われます

④ユーザを作成する
> New-MsolUser -UserPrincipalName hoge@example.com
New-MsolUser : Access Denied. You do not have permissions to call this cmdlet.
発生場所 行:1 文字:1
+ New-MsolUser -UserPrincipalName hoge@example.com
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [New-MsolUser], MicrosoftO
nlineException
+ FullyQualifiedErrorId : Microsoft.Online.Administration.Automation.Acces
sDeniedException,Microsoft.Online.Administration.Automation.NewUser
⇒権限がないって言われます

⑤ユーザを削除する
> Remove-MsolUser -UserPrincipalName kenshinu@example.com

確認
この操作を続行しますか?
[Y] はい(Y) [N] いいえ(N) [S] 中断(S) [?] ヘルプ (既定値は "Y"):
Remove-MsolUser : Access Denied. You do not have permissions to call this cmdle
t.
発生場所 行:1 文字:1
+ Remove-MsolUser -UserPrincipalName kenshinu@example.com
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [Remove-MsolUser], Microso
ftOnlineException
+ FullyQualifiedErrorId : Microsoft.Online.Administration.Automation.Acces
sDeniedException,Microsoft.Online.Administration.Automation.RemoveUser
⇒権限がないって言われます

⑥管理者ユーザでAzureサブスクリプションにサインアップし管理ポータルからディレクトリを操作する
 ⇒ユーザ一覧が見えません。PowerShellだと見えるんですが、管理ポータルからだと管理対象AUのメンバユーザすら見れません。


現状はこんな感じです。
今後はグループオブジェクトなんかもAUメンバに追加できるようになったりするようなので、今後の進化に期待です。

[FIM]カスタム管理エージェントのトレースログを出力する

$
0
0
久しぶりにForefront Identity Manager(FIM)の話題です。
ID管理システムを構築する際、管理対象のすべてのシステムを製品に含まれる管理エージェントでまかなえることは稀だと思います。
FIMの場合、カスタムで管理エージェントを開発するためのECMA2というフレームワークが提供されており、各種システムとの柔軟な接続性を確保することができます。

カスタムで管理エージェントを開発する際、避けて通れないのがデバッグとトレース(ロギング)です。
デバッグについては別途紹介したいと思いますので、今回はトレースについてのポイント(TIPS)を少し紹介します。

トレースを行う方法も色々とあると思いますが、最近はプリセットのアダプタ群も対応しているEvent Tracing for Windows(ETW)を使うのが主流です。
(昔はMicrosoft.MetadirectoryServices.Loggingなんていうのもありましたが、最近はあまり使っていないような・・・。一応今でもあります、念のため)

 ETWトレース
  https://msdn.microsoft.com/ja-jp/library/vstudio/ms751538(v=vs.100).aspx
 Microsoft.MetadirectoryServices.Logging
  https://msdn.microsoft.com/en-us/library/microsoft.metadirectoryservices.logging.logging.aspx


ETWを使う場合、アプリケーション構成ファイル(hogehoge.exe.config)にSourceとListenerを記載すればモジュールに手を入れることなく、イベントログやテキストファイルなどへ柔軟にトレースを出力することが出来ます。
この時に注意すべきなのが、管理エージェントをFIM Sync(miisserver.exe)のプロセス内で動かすのか、別プロセスとして動かすのかによって使われるアプリケーション構成ファイルが異なる、ということです。


ここで「Run this management agent in a separate process」にチェックが入っているとFIM Sync(miisserver.exe)ではなく、独立したプロセス(dllhost.exe)で管理エージェントが実行されます。つまり、この場合はmiisserver.exeではなくdllhost.exeが使うアプリケーション構成ファイルにETWの設定をする必要があるのです。


それぞれの実行プロセスと構成ファイルは以下の通りです。

管理エージェント実行方法実行プロセス名アプリケーション構成ファイル
FIM Sync内miisserver.exeC:\Program Files\Microsoft Forefront Identity Manager\2010\Synchronization Service\Bin\miisserver.exe.config
別プロセスdllhost.exeC:\Program Files\Microsoft Forefront Identity Manager\2010\Synchronization Service\dllhost.exe.config




尚、設定する内容は同じなので、両方に同じことを書いておけばどちらのモデルで実行してもログの取り忘れはなくなるので、とりあえず両方に設定しておくのが良いかも知れません。



以下、具体的な設定方法です。

◆管理エージェント側
<必要な準備>
①#define TRACEを定義するか、コンパイルオプションに/d:TRACEを付けていること
②System.Diagnosticsをusingで定義
③TraceSourceオブジェクトインスタンスを生成

こんな感じで書きます。
#define TRACE
using System;
using Microsoft.MetadirectoryServices;
using System.Diagnostics;

namespace FimSync_Ezma
{
public class EzmaExtension :
IMAExtensible2CallExport,
IMAExtensible2CallImport,
IMAExtensible2GetSchema,
IMAExtensible2GetCapabilities,
IMAExtensible2GetParameters
{
// trace
TraceSource traceSource = new TraceSource("sampleMA",SourceLevels.All);

※testma部分がアプリケーション構成ファイル内のSource Nameになります。SourceLevelについてはお好みで。

<トレース出力の例>
実際にトレースを出力したい箇所では以下のように書きます。
traceSource.TraceEvent(TraceEventType.Information, 0, "hogehoge");
traceSource.Flush();



◆アプリケーション構成ファイル側
テキストファイルに出力する例です。
initializeDataに対象ファイル名を記載します。
<system.diagnostics>      
<sources>
<source name="sampleMA" switchValue="All">
<listeners>
<add name="sampleMA"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="c:\Logs\sampleMA_dllhost.log">
<filter type="" />
</add>
<remove name="Default"/>
</listeners>
</source>
</sources>
</system.diagnostics>





switchValueで出力レベルが変更できますので、開発中やデバッグ中は構成ファイル側でログレベルを上げておいて、平常時はレベルを落とすことで性能やディスク容量への影響を減らすことが出来ますので、うまく調整をしていきましょう。

[Office365/ADFS/AAD]クラウドIDのアクセス制御にAD FSを利用する

$
0
0
タイトルだけを見ると一体何をしようとしているのか良くわからないと思いますが、Office365フォーラムに質問が上がっていたので、こんなケースもあるかも知れないなぁ、ということで動きを検証してみました。


◆実現したい環境の概要
・Office365をクラウドID(Azure Active Directory上のユーザ)で使いたい
 ※ローカルのActive Directoryユーザを使いたくない
・Azure Active DirectoryだとクライアントIPやブラウザ種別などでアクセス制御が出来ないのでActive Directory Federation Services(AD FS)のクレームルールでの制御を行いたい

いざ実現しようとすると色々と課題があります。



そこで、Office365(AzureAD)⇒AD FS(アクセス制御用)⇒AzureAD(認証用)というフェデレーションの連鎖をさせて実現できるか確認してみます。

こんな環境です。


かなりややこしい構成です。



◆結果は、、、、曲がりなりにも動いた!
まずは結論から。
「一応」動きました。。。。が、ユーザビリティに少々難ありかと。(ある程度工夫で何とかなりますが)

フローを追って確認してみます。
①Office365にアクセスする
 まずはOffice365にアクセスします。https://portal.office.comへブラウザでアクセスし、ログイン画面を表示させます。



②AD FSのドメイン名のユーザ(ダミー)をログインIDに入れる
 Office365(AzureAD)のレルム・ディスカバリ機能でAD FSへリダイレクトされます。



③AD FSのレルム選択画面でAzureADを選択する
 あらかじめAD FSに外部IdPを設定してあるとローカルのAD DSで認証するか、外部IdP(今回はAzureAD)で認証するかを選択できます。ここでAzureADを選択すると再度AzureADのログイン画面へ遷移します。


 ※ちなみにAzureADからAD FSへの遷移はajaxで制御されています。通常フローだとAzureADのログイン画面に入れたユーザ名がそのままAD FSに引き継がれるので便利なのですが、AD FSのログイン画面で別のユーザ名(AzureADのonmicrosoft.comユーザ)を入れる必要があるので、アドレスバーに表示されるURLのGETパラメータのusername=xxxという部分を手動で消してあげる必要があります。この部分の省力化方法は後で紹介します。


④AzureADユーザ(onmicrosoft.comユーザ)で認証する
 今度はAD FSにリダイレクトするためのダミーユーザではなく、AzureAD上の実ユーザでログインするため、ユーザ名にonmicrosoft.comドメインのユーザ名を入力します。するとAzureAD上の自分のテナントの認証画面へ遷移します。



⑤ログインする
 自分のテナントのログイン画面に遷移したらクラウドIDでログインします。



⑥AzureAD⇒AD FS⇒Office365(のIdPであるAzureAD)へ戻る
 認証が終わるとAzureADでAssertionが発行され、AD FSへ戻されます。次にAD FSはAzureADから受け取ったAssertionをOffice365(のIdPであるAzureAD)向けのAssertionに変換・発行し直してAzureADへ戻し、AzureADでの認証プロセスが完了します。
 この時、Office365のIdPとしてのAzureADはAD FSのユーザで認証されますが、前段階ですでにクラウドID(onmicrosoft.comユーザ)でログオンしていますので、すでに認証済みとして扱われ、改めてログインし直すか聞かれます。ここでログインし直す選択をするとログアウトからやり直すので、永遠に2重ログイン状態を繰り返してしまいますので、AD FSユーザでのログインはあくまでアクセス制御のためと割り切って、クラウドIDでのログイン継続を選択します。



⑦Office365へのログイン
 ライセンスを付与していないので画面ショットは単なるプロファイル表示画面になっていますが、無事にOffice365へアクセスできます。




これで一連の流れは完了です。
ここまで出来れば、AD FSの部分でアクセス制御ルールを設定してあげればOKです。上記フローの⑥の部分でアクセス制御が挟まるので、アクセス拒否されるとこんな画面が出てきます。




◆どうやって実現するか?
まずは環境設定です。
AzureAD、AD FSそれぞれに下記の設定を行います。

対象設定箇所設定内容設定方法
AzureADアプリケーション設定Office365を登録Office365の設定を行えば自動的に設定される
AD FSを登録ws-federationで連携するWebアプリケーションとして登録する
ドメイン設定AD FSとID連携するドメインを設定Office365のPowerShellで設定する
ユーザ設定ダミーユーザ(AD FS連携用ユーザ)PowerShellなどで登録する
実ユーザ(ログインするユーザ)PowerShellなどで登録する
AD FSRP設定Office365(AzureAD)を登録Office365のPowerShellで設定する
IdP設定AzureADを登録AzureADのFederationMetadataを使って登録する



順番に設定内容を見ていきます。
・AzureAD/アプリケーション設定
 Office365は自動的に登録されるので、AD FSを登録します。
 AzureADのアプリケーション設定で「組織で開発中のアプリケーションを追加」します。


 アプリケーションの種類は「WEBアプリケーションやWEB API」を選択します。


 以下の通りサインオンURLとアプリケーションID/URIを設定します。
 ・サインオンURL:AD FSのPassiveログインURL
 ・アプリケーションID/URI:AD FSのサービスID



・AzureAD/ドメイン設定
 こちらは通常のOffice365でAD FSとID連携用ドメインを設定する手順で設定を行います。

・AzureAD/ユーザ設定
 ・ダミーユーザ(AD FS連携用ユーザ)
  このユーザは実際にOffice365を利用するためのユーザではないので適当に作成すればOKです。
  作成した後、Get-MsolUserコマンドレットなどでImmutableIdおよびUserPrincipalNameの値を確認、メモしておきます。実際にログインに使うAzureAD上のユーザのSAML Assertionの中にこのダミーユーザのImmutableIdとUserPrincipalNameの値が必要となるためです。

 ・実ユーザ(ログインするユーザ。onmicrosoft.comユーザ)
  このユーザで実際にOffice365を使います。先にも書いたように、AzureADでこのユーザを認証した後、AD FSにSAML Assertionを渡すのですが、AD FSでこのユーザの属性(クレーム)と先に作成したダミーユーザのImmutableIdとUserPrincipalNameを一致させることで紐づけ(Federation)をさせます。
  そのため、このユーザの属性にダミーユーザのImmutableIdとUserPrincipalNameを設定します。
  今回は名にImmutableId、姓にUserPrincipalNameを設定しました。(この属性がOffice365のプロファイルに表示されてしまうので、本来はスキーマを拡張して利用者に見えない属性を使った方が良いと思います)



  また、このユーザでAzureAD上に登録してあるアプリケーションとしてのAD FSへアクセスするために、先に登録したAD FS(アプリケーション)へのアクセス権を割り当てます。



・AD FS/RP設定
 Office365とのID連携設定をすると自動的にRPとして「Microsoft Office 365 Identity Platform」が登録されるので、こちらのクレームルールを変更します。
 もともとあるのはActive Directoryから属性をとってきてNameID、ImmutableId、UserPrincipalNameを発行するルールなので、潔くすべて削除します。
 そして、以下の3つのルールを設定します。


 ・NameID発行(AzureADのユーザの名に入っているImmutableIdの値を発行)

c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"]
=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", Issuer = c.Issuer, Value = c.Value, ValueType = c.ValueType, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");

 ・UserPrincipalName発行(AzureADのユーザの姓に入っているUserPrincipalNameの値を発行)

c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"]
=> issue(Type = "http://schemas.xmlsoap.org/claims/UPN", Issuer = c.Issuer, Value = c.Value, ValueType = c.ValueType);

 ・ImmutableId発行(AzureADのユーザの名に入っているImmutableIdの値を発行)

c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"]
=> issue(Type = "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID", Issuer = c.Issuer, Value = c.Value, ValueType = c.ValueType);

 アクセス制御をする場合はここで設定をしておきます。


・AD FS/IdP設定
 次にAD FSのIdPとしてAzureADを登録します。
 AzureADがFederationMetadataを公開しているので、URIを設定するだけで簡単に設定できます。
 設定するURIは「https://login.windows.net/[テナントID]/federationmetadata/2007-06/federationmetadata.xml」です。AzureADのアプリケーション設定のページでエンドポイントは確認できます。


 次に、AzureADから取得した属性(クレーム)を受け取る設定です。特に何も考えずにすべての属性をパススルーします。


 こんなルールです。

c:[]
=> issue(claim = c);



これですべての設定が完了しました。
先のフロー通りに動きます。


◆ちょっとした工夫
画面遷移を紹介しましたが、何度もレルムを選択したりするのは、かなり不便です。
そこで、最初のOffice365⇒AD FSへのレルム選択を自動化するために以下のURLをユーザにBookmarkしてもらうといきなりAD FSのログイン画面にたどり着きますので、かなり画面遷移がすっきりします。先の画面遷移の③からいきなり始まりますので、username=xxxをアドレスバーから手動で消す必要もなくなります。

 ブックマークするURL
  https://login.microsoftonline.com/login.srf?wa=wsignin1.0&wreply=https:%2F%2Fportal.office.com%2F&whr=example.net

◆Assertionの中身
細かい話ですが、ログインまでの間で以下のようなAssertionが飛んでおり、各ポイントで必要に応じて処理をします。
・AzureAD(実ユーザでログイン)⇒AD FS
<Subject>
<NameID+Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">ixxxxxxxxxxxxxxxxx0ZM</NameID>
<SubjectConfirmation+Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"+/>
</Subject>

<AttributeStatement>
<Attribute+Name="http://schemas.microsoft.com/identity/claims/tenantid">
<AttributeValue>2cxxxxxxxxxxxxxxxxxxxxxbfff</AttributeValue>
</Attribute>
<Attribute+Name="http://schemas.microsoft.com/identity/claims/objectidentifier">
<AttributeValue>baxxxxxxxxxxxxxxxxxxxba2ac2</AttributeValue>
</Attribute>
<Attribute+Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name">
<AttributeValue>nobunagao@xxxx.onmicrosoft.com</AttributeValue>
</Attribute>
<Attribute+Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname">
<AttributeValue>nobunagao@example.net</AttributeValue>
</Attribute>
<Attribute+Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
<AttributeValue>QDibxxxxxxxxxfIENg==</AttributeValue>
</Attribute>
<Attribute+Name="http://schemas.microsoft.com/identity/claims/displayname">
<AttributeValue>ADFS/AADテスト</AttributeValue>
</Attribute>
<Attribute+Name="http://schemas.microsoft.com/identity/claims/identityprovider">
<AttributeValue>https://sts.windows.net/2c6xxxxxxxxx1bfff/</AttributeValue>
</Attribute>
</AttributeStatement>



・AD FS⇒AzureAD(ダミーユーザ情報)
 クレーム変換ルールでImmutableId、UPNに必要な値が代入されています。
<saml:AttributeStatement>
<saml:Subject>
<saml:NameIdentifier+Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">QDxxxxxxNg==</saml:NameIdentifier>
<saml:SubjectConfirmation>
<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Attribute+AttributeName="UPN"+AttributeNamespace="http://schemas.xmlsoap.org/claims">
<saml:AttributeValue>nobunagao@example.net</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute+AttributeName="ImmutableID"+AttributeNamespace="http://schemas.microsoft.com/LiveID/Federation/2008/05">
<saml:AttributeValue>QDxxxxxxNg==</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>





いかがでしょうか?
色々とトリッキーなことをしているので、実用性は?ですがクラウドIDを使う場合にアクセス制御をしたい、という要件はあると思います。
今後はAzureAD側でのアクセス制御が実装されてくる日が来るかも知れませんね。

[Windows10/AAD]クラウド・ドメイン参加を試す

$
0
0
Windows 10からの新機能としてAzure Active Directory(AzureAD)のアカウントでPCにログインできる「クラウド・ドメイン参加(Cloud Domain Join)」があります。

先日リリースされたTechnical Preview Build 9926からクラウド・ドメイン参加が出来るようになっている様なので試してみます。

◆準備事項
 クラウド・ドメイン参加するためには、AzureADのテナント側で「デバイスの登録(Device Registration)」を有効にしておく必要があります。
 管理ポータルからAzureADの構成メニューを開き、デバイスの登録より「ワークプレース参加の有効化」を行います。


◆PC側の設定
 早速設定していきます。
 PCのキッティング時(OOBE)からAzureADアカウントでログインさせることも可能らしいのですが、何故かうまく行かなかったので、一旦別のマイクロソフトアカウントでPCにログインします。
 スタートメニューから[Settings]を開き、[システム]、[バージョン情報]の順で画面を開きます。



すると、[クラウドに接続する]というリンクが存在するので、迷わずクリックすると「クラウド体験ホスト」というウィンドウが起動してきます。

しばらくするとサインイン画面になります。


ここでおもむろにAzureADのアカウント(onmicrosoft.comのアカウント)を入れると、見慣れたAzureADのサインイン画面が表示されます。


正常にサインインしたら、クラウド体験ホストを閉じてPCを再起動します。

PCが起動してきたらサインイン画面で「別のユーザ」を選択します。

「他のユーザ」を選択するとAzureADへのサインイン画面となるのでAzureADのIDとパスワードを入力してサインインします。


うまく行くとデスクトップが立ち上がってきます。


スタートメニューに表示される名前もちゃんとAzureADから取得できています。

とりあえずここまでです。
単にPCへのログインだけなので、これでOffice365などPCへのログインで使ったAzureADアカウントでログインするアプリケーションへのシングルサインオンが出来るか?というと「できません」。
あくまでPCへAzureADのアカウントでログインするだけです。



やっぱりブラウザを立ち上げると再度ログインする必要があります。。。


まだ管理面は見れていないので、AzureAD側で何が出来るかは今後見ていく必要がありそうです。

ちなみにクラウド接続がうまく行くと、AzureADのユーザプロファイルから該当アカウントのデバイス情報が見れます。
デバイス紛失などの場合はここで無効化などできるはずです。


[AADSync]新バージョンがリリース(1.0.485.0222)

$
0
0
新しいバージョン(1.0.485.0222)がリリースされています。

今回のアップデートでは以下が更新されています。
  • Password Sync honors the cloudFiltered attribute used by attribute filtering. Filtered objects will no longer be in scope for password synchronization.
  • In rare situations where the topology had very many domain controllers, password sync doesn't work.
  • "Stopped-server" when importing from the Azure AD Connector after device management has been enabled in Azure AD/Intune.
  • Joining Foreign Security Principals (FSPs) from multiple domains in same forest causes an ambiguous-join error.
特に大きな機能追加もなく、不具合修正が中心ですね。

残念ながら今回もAzure Active DirectoryからオンプレADへのDevice情報の書き戻しもサポートされません。(AzureADのDevice Registration ServiceがAndroidをサポートしたので、この機能が一番欲しいです。まだDirSyncを手放せない最大の理由です)





[FIM/MIM]新しいPublic Previewがリリース

$
0
0
ConnectサイトにMicrosoft Identity Manager 2015の新しいPublic Previewがリリースされています。

Active Directory TeamのBlog
 Microsoft Identity Manager Public Preview #2 is available
 http://blogs.technet.com/b/ad/archive/2015/03/03/microsoft-identity-manager-public-preview-2-is-available.aspx

今回のPreviewの一番の目玉はやはりPAM(特権アカウント管理)がWindows Server 2012 R2のドメインコントローラでも動くようになった、というところです。(前回のPreviewではWindows Server vNextのみのサポートだったのでとってもハードルが高かったので、、、)
また、PAM用のREST APIやサンプルポータルなんかが同梱されています。

他にもCertificate ManagerのアップデートやForefront Identity Manager 2010 R2からのインプレースアップグレードなんかも出来るようになっているので、検証はしやすくなっています。

とりあえず試してFeedbackですね。

[FIM]汎用REST管理エージェントをリリースしました

$
0
0
Google AppsがProvisioning APIのサポートをやめる、という発表があってから、以前リリースしたGoogle Apps用管理エージェントの更新をしないと、、、と思っていたのですが、ようやく対応することが出来ました。
今年の4/20に廃止なので、かなりギリギリになりましたが。
実は前のGoogle Apps管理エージェントがインドあたりで大規模に使われていたりするらしく・・・

Google Provisioning API
 https://developers.google.com/google-apps/provisioning/

現在公開しているGoogle Apps用管理エージェント
 https://fim2010gapps.codeplex.com/

詳しい使い方は追って公開していこうと思いますので、今回は特徴だけ。

今回の目玉はGoogle Appsだけ、という特定のサービス向けではなく、RESTful APIでプロビジョニングできるサービスなら(ある程度前提はあるものの)接続できる(はず)というところです。
その意味で「汎用」としています。

Generic REST API Management Agent for Forefront Identity Management 2010 R2
 https://restmafim.codeplex.com/
 ※codeplexに公開しているので基本英語でドキュメントは書いていきます。日本語版についてはこのblogで今後書いていこうと思います。


主な特徴としては、

  • プラグイン型にしたので、サービス固有のパラメータ(スキーマなど)はプラグインライブラリを作ることで拡張できる
  • プロキシサーバ(認証付でもOK)のサポート(DirSyncやAADSyncで困るところですよねぇ)
  • セットアップを簡素化するため管理エージェントをパッケージ化(setup.exeとmapackageを作っただけですが)
です。

こんな仕組みです。(久しぶりにReflectionとか使いましたw)


対応しているアプリケーションには少々条件があり、

  • OAuth2.0 JWT Bearer Token Flowをサポートしていること
  • オブジェクト表現にJSONを使っていること
  • (当然ですが)RESTful APIでオブジェクト管理が出来ること
が最低限の条件です。

現状Google Apps用のプラグインライブラリを同梱しているので、これをベースに拡張すればSalesforce.comなんかも繋がると思います。
(ちなみにAzure Active DirectoryについてはOAuth周りが特殊すぎて現状ダメですね。これはこれで別途解説したいと思います。)

ソースコードも公開していますので、FIMの管理エージェントを開発する人、OAuth2.0 JWT Bearer Token Flowを生で実装する人には参考になると幸いです。
(もちろん本来の目的であるFIMの管理エージェントとしても使ってもらえると幸いです)

プラグインライブラリの開発方法などを含めまだ公開できていないドキュメントが多数あるので、順次公開していきますので、よろしければ試してみてフィードバックいただけると助かります。


[告知]Japan SharePoint Group勉強会でお話します

$
0
0
なんだか久しぶりの大阪でのイベントです。

SharePoint MVPの山崎さんにお誘いいただき、少々お話をすることになりました。 
と、言っても特にSharePointについてネタがあるわけではないので、Web Application Proxy(WAP:旧AD FS Proxy)とAzure WAPについて話をしようかな、と。

WAPの使い方ってOffice365をインターネット経由で使う時に、Active Directory Federation Services(AD FS)にアクセスするための単純なリバースプロキシ、という認識の方も多いと思うのですが、個人的にその真の価値はws-federation / ws-trustで使われるSAMLトークンをWindows統合認証で使われるKerberosトークンに変換するところにあると考えています。

例えば、オンプレにWindows統合認証で組まれた古いSharePointがあり、そのポータル上には同じくWindows統合認証で組まれたClassic ASPのIISアプリがあって、という環境において、スマホをはじめとする非ドメイン端末からアクセスすると、認証ダイアログが山の様に出てきて、というような問題が起きるわけです。
そんな場合、本来であればアプリケーションを利用環境に合わせて修正していくのが筋なんでしょうが、そんなに簡単に修正・移行できるわけではないので、一時的なワークアラウンドとしてWAPを間に挟み、社外や非ドメイン端末はAD FSでフォーム認証し、発行されたSAMLトークンをWAPがKerberosトークンに変換してWindows統合認証を行う、ということも可能になるわけです。

そのあたりを少しデモも交えつつ紹介できればなぁ、、と。

以下が申込みサイトです。
 Japan SharePoint Group 勉強会 #18
 http://jpsps.com/event/20150314/

3/14(土)に大阪ですが、お暇な方はどうぞ。

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

$
0
0
※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でも試してみましたが、こちらはまだダメでした。



今後に期待です。


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

$
0
0
発表されてからずっとクローズド・ベータという形となっており、公には音沙汰がなかった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サポート





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

$
0
0
以前のポストで概要を簡単にチェックした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


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

$
0
0
いよいよ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などのサービスを利用する方が良い、と言えるかも知れません。

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

$
0
0
ようやく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がようやく実現しそうな予感がします。
夏の正式リリースまでにブラッシュアップされると思うので期待して待っておきましょう。

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

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

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

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 は必要ありません。





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

$
0
0
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&amp;client_id=6c831710-cd6c-11e4-8830-0800200c9a66&amp;redirect_uri=http%3A%2F%2Flocalhost&amp;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&amp;client_id=6c831710-cd6c-11e4-8830-0800200c9a66&amp;redirect_uri=http%3A%2F%2Flocalhost&amp;resource=google.com%2Fa%2Fhoge.example.net


②ユーザ認証が行われるため、ログオンするとredirect_uriにリダイレクトされ、フラグメントにaccess_tokenが返ってきます。
http://localhost/#access_token=eyJ0eXAiO...snip...MP_bQsjj7Jvp81j-qztASSrzzAypA&amp;token_type=bearer&amp;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対応についてもある程度試してはいるので、また書きたいと思います、

後は、次のビルドが出たらもう少し試してみたいと思います。
Viewing all 771 articles
Browse latest View live