2017年9月7日木曜日

[リリース]LINE/Yahoo! IDを使ってOffice365へのログインを便利にする

こんにちは、富士榮@北海道です。

たまにはお仕事の話です。

本日、Azure AD B2CとLINE、Yahoo! JAPAN IDを連携させるソリューションを雇用主よりプレス発表しました。

SNSアカウントを活用するシステムの構築サービスを開始
http://www.ctc-g.co.jp/news/press/20170906a.html

Impressさん、日経電子版などのメディアに取り上げていただけました。

IT Leaders
 http://it.impressbm.co.jp/articles/-/14950
日経電子版
 https://www.nikkei.com/article/DGXLRSP456311_W7A900C1000000/
クラウドWatch
 http://cloud.watch.impress.co.jp/docs/news/1079437.html

本日北海道大学で開催されたCloud Week 2017で、本件に関する講演を行いデモを含めお披露目をさせていただきました。



簡単に内容を説明すると、Azure AD B2Cをカスタマイズし、
・LINEやYahoo! JAPAN IDなどの日本でメジャーなIdPへの対応
・Office365やG SuiteなどSAMLアプリケーションへの対応
・Microsoft Graphを利用し、Office365に届く重要なメールをLINEへも通知
・個別、一斉でのSNSへのメッセージ配信
というような仕組みをくみ上げたサービスとなっています。



こんな感じです。

動いている姿は以下です。


こんな流れです。
1.LINEで友達になる
2.LINEメニューから組織の払い出したID/PWDでOffice365へログインする
3.LINE IDと紐づけを行う
4.重要なメールはLINEへも通知する様に設定する
5.LINE IDでOffice365へシングルサインオンする
6.Office365へ重要なメールが届くとLINEのタイムラインへも通知される


他にも、公衆無線Wifiへのユーザ登録の簡素化などにも使えます。WeChatなどの中国のSNSにも対応しているので観光客向けのサービスとして無線LANを提供するようなケースを想定しています。


公衆無線Wifiを使った不正行為やいたずらが増えてきているらしいので、サービスレベルの向上(登録の簡素化)と利用者への到達性、証跡の確保の両立をしたい場合などはうまく使ってもらえると思います。

追記)
Cloud Week 2017で使った資料を公開したので、張り付けておきます。



尚、今後は以下のイベントで詳細を説明していきますので、是非ご参加ください。
・9/15 Japan Identity & Cloud Summit 2017
 https://nosurrender.jp/jics2017/
・10/13 CTCフォーラム 2017
 https://www.event-site.info/ctcforum2017/
・11/08 Tech Summit 2017
 https://www.microsoft.com/ja-jp/events/techsummit/2017/
・12/13 AXIES年次総会
 URL未定

また、個別に仕組みが知りたい、という方はぜひご連絡ください!
(標準のAzure AD B2Cでは出来ないことを独自拡張でかなりカバーしているので)

2017年8月23日水曜日

[Azure AD/Office365]Azure AD Connectでカスタムコネクタを使用する

こんにちは、富士榮です。

先日公開したAzure AD ConnectとCDATA API Serverを組み合わせたSalesforce.comへのプロビジョニングや、3年ほど前に公開したAzure AD ConnectからOpenAMのレポジトリとして構成したOpenDJへのプロビジョニングの記事では、Azure AD ConnectのMicrosoft Identity ManagerのSynchronization Serviceとしての機能を使ってカスタムのコネクタ(ECMA2エージェント)や組み込みのGeneric LDAP Connectorを使って「無理やり」、ADやAzure AD以外のシステムとの同期を実現していました。
※Azure AD ConnectにGeneric LDAP Connectorなどが同梱され始めたのは1年くらい前ですね。

実はこの構成、オフィシャルに公開されていなかっただけで、Premierサポートとの契約があれば使うことは出来たんですが、なかなかハードルが高いので、これまであまり言及してきませんでした。

しかし、Azure Active Directory PoCプレイブックの中に、しれっとGeneric LDAP Connectorを使ったオンプレミスLDAPとAzure ADの同期のシナリオが記載されていることに気が付いてしまいました(笑)

Generic LDAPコネクタ構成
https://docs.microsoft.com/ja-jp/azure/active-directory/active-directory-playbook-building-blocks#generic-ldap-connector-configuration

流石に、こんな注意書きが添えられていてハードルを上げまくっています。まぁ、やってみるとそれほど難しくはありませんが。
これは高度な構成で、FIM/MIM に関する知識を必要とします。 運用環境で使用されている場合、この構成に関するご質問については、Premier サポートを使ってお問い合わせください。

Azure AD ConnectがGAしたタイミングで公開されたドキュメントに書いてある構成が徐々に実現してきている、ということですね。




ちなみに以下のドキュメントを見ると、オンプレミスのLDAPなどへAzure AD Connectを使って接続する構成はFR(今後サポート)となっており、正式にサポートされたわけではないので、実際に利用する場合はPremierサポートと十分に協議をすることをお勧めします。

ハイブリッド ID ディレクトリ統合ツールの比較
https://docs.microsoft.com/ja-jp/azure/active-directory/active-directory-hybrid-identity-design-considerations-tools-comparison



2017年8月15日火曜日

JICS 2017開催!コンシューマから学術、エンタープライズまでIDに関与している人は参加必須です

こんにちは、富士榮です。

お馴染みのVittorio Bertocci氏を招聘したJapan Identity & Cloud Summit(JICS)2014から3年、久しぶりにJICSが復活します。



今年は、ゲストが豪華です。

  • オープニング・キーノートはプレゼンのわかりやすさでは定評のあるSalesforce.comのChuck Mortimore氏
  • 続くキーノートはMicrosoft CorporationのAlex Weinert氏よりCloud Identity元年的な話でIdentityの将来を見据えた時にオープン・スタンダードの重要性について
  • そこからはブレークアウトセッションに分かれて金融、学術、ソーシャル、IoT、トラストフレームワークなど見所がたくさん
  • セキュリティネタではOWASP Japanのリーダー岡田氏
  • お馴染みOpenIDファウンデーション・ジャパンのエヴァンジェリスト達による標準技術(OAuth、OpenID Connect)の解説
  • クロージング・キーノートはこれまたIdentity界隈では知らぬ人はいない、Nishant Kaushik氏からNRI/OpenID Foundationの崎村さん、というこれまた必聴のセッションで畳みかけ。

見所満載です。

私もモバイル・ソーシャルのトラックとトラスト・フレームワークのトラックの2つを見ており、2コマ+VTR再放送で都合3コマも登壇するのですが、自分が出ている時間帯のセッションが聞けないのが非常に残念です。



定員は1000名くらいだったと思いますが、希望のセッションを登録時に選択する方式なので、早めに登録しないと聞けないセッションもあると思うので、ぜひ早めに登録を!

登録はこちらから。
https://nosurrender.jp/jics2017/

2017年8月14日月曜日

APIゲートウェイでSaaSのIDを簡単に管理する②

こんにちは、富士榮です。

前回に引き続き、CDATA API ServerとID管理システムを使ってSaaS(今回はSalesforce.com)へのプロビジョニングを簡単に行う、という仕組みを作っていきます。

前回は、API ServerをSalesforce.comのUserテーブルへ接続し、ユーザの取得をしましたが、今回はいよいよID管理システム(今回はAzure AD Connect)を使ってユーザを作成します。

やることは非常に単純で、API Serverで定義されたリソース(実際はSalesforce.comのUserテーブル)に対してJSON形式で作成したいユーザの情報をPOSTするだけです。

◆投げ込むJSONを確認する

Salesforce.comの開発者ドキュメントを見ると、Userテーブルに新規レコード(つまり新規ユーザ)を作成する際に必須となる属性を確認します。

 SOAP API開発者ガイド)User
 https://developer.salesforce.com/docs/atlas.ja-jp.api.meta/api/sforce_api_objects_user.htm

これを見ると、以下の属性が必須との事です。
  • Username :ユーザ識別子。メールアドレス形式
  • Alias :ユーザの別名
  • Email :ユーザのメールアドレス
  • LastName :ユーザの姓
  • EmailEncodingKey :メールの文字コード
  • LanguageLocaleKey :ユーザの言語
  • LocaleSidKey :ユーザのロケール
  • ProfileId :ユーザのプロファイルのID
  • TimeZoneSidKey :ユーザのタイムゾーン
  • UserPermissionsOfflineUser :オフラインエディションの使用可否
  • UserPermissionsMarketingUser :キャンペーン管理の可否

ユーザを作成するには、最低限これらの値をJSON形式でAPI ServerのリソースへPOSTすればよい、ということなので、まずは直接POSTしてみます。

ただ、EmailEncodingKeyやProfileIdなど、何を値として設定すれば良いのかよくわからない属性もあるので、まずはSalesforce.com上に手動で作成したユーザをGETし、各属性にどのような値が入っているのかを確認すると以下のような値が入っていることがわかるので、この例をテンプレートにPOSTするデータを作成します。

属性
Usernamexxxxx@example.com
AliasFujie
Emailxxxxx@example.com
LastNameFujie
EmailEncodingKeyISO-2022-JP
LanguageLocaleKeyja
LocaleSidKeyja_JP
ProfileId(Chatter Free Userの場合)00e7F000001LotXQAS
TimeZoneSidKeyAsia/Tokyo
UserPermissionsOfflineUserfalse
UserPermissionsMarketingUserfalse


以下のようなJSONを作成し、Chrome ExtensionのAdvanced REST Clientを使ってAPI Serverに定義したリソースエンドポイントへPOSTをします。
{
  "Username": "test999@eidentity.jp",
  "Alias": "test999",
  "Email": "test999@eidentity.jp",
  "LastName": "Test",
  "EmailEncodingKey": "ISO-2022-JP",
  "LanguageLocaleKey": "ja",
  "LocaleSidKey": "ja_JP",
  "ProfileId": "00e7F000001LotXQAS",
  "TimeZoneSidKey": "Asia/Tokyo",
  "UserPermissionsOfflineUser": "false",
  "UserPermissionsMarketingUser": "false"
}


上手くいくと、HTTP 201 Createdが返ってきて実際にユーザが作成されます。


Salesforce.comの管理画面からユーザを確認すると実際に作成されていることがわかります。


◆管理エージェントの作成

投げ込むJSONがわかったところで、あとはID管理システムでJSONの生成からPOSTを自動化するだけです。

やることはFIM/MIM向けのECMA2エージェントとして以前公開したGeneric REST API Management Agentとよく似たようなことなので、このコードをカスタマイズしてみます。

細かいECMA2エージェントの開発方法は別エントリでそのうち解説しますが、以下の手順でGeneric REST API Management Agentを改造します。

1.スキーマ定義(GetSchemaメソッド)
 先にリストアップした必須属性を定義します。Username属性をAnchor属性として設定をしています。こんなコードになります。
                SchemaType personType = SchemaType.Create("Person", false);
                personType.Attributes.Add(SchemaAttribute.CreateAnchorAttribute("Username", AttributeType.String));
                personType.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute("Alias", AttributeType.String));
                personType.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute("Email", AttributeType.String));
                personType.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute("LastName", AttributeType.String));
                personType.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute("EmailEncodingKey", AttributeType.String));
                personType.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute("LanguageLocaleKey", AttributeType.String));
                personType.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute("LocaleSidKey", AttributeType.String));
                personType.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute("ProfileId", AttributeType.String));
                personType.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute("TimeZoneSidKey", AttributeType.String));
                personType.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute("UserPermissionsOfflineUser", AttributeType.Boolean));
                personType.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute("UserPermissionsMarketingUser", AttributeType.Boolean));
                Schema schema = Schema.Create();
                schema.Types.Add(personType);
                return schema;

 こうすることで管理エージェントで管理対象属性を選択できるようになります。


2.パラメータ定義(GetConfigParametersメソッド)
 API Server上のリソースURIや接続に使うAPI ServerユーザのAuthTokenを指定できるようにします。こんなコードになります。接続パラメータの部分だけで良いのでConnectivityの部分にパラメータを追加しています。
                switch (_page)
                {
                    case ConfigParameterPage.Capabilities:
                        break;
                    case ConfigParameterPage.Connectivity:
                        _configParametersDefinitions.Add(ConfigParameterDefinition.CreateLabelParameter("Connection parameters"));
                        _configParametersDefinitions.Add(ConfigParameterDefinition.CreateStringParameter(ConstDefinition.CFG_RESOURCE_URI, ""));
                        _configParametersDefinitions.Add(ConfigParameterDefinition.CreateStringParameter(ConstDefinition.CFG_AUTH_TOKEN, ""));
                        break;
                    case ConfigParameterPage.Global:
                        break;
                    case ConfigParameterPage.Partition:
                        break;
                    case ConfigParameterPage.RunStep:
                        break;
                    case ConfigParameterPage.Schema:
                        break;
                }

尚、テストなので、ValidateConfigParametersについては処理を入れておらず、指定されたパラメータの値の確認などは行っていません。

これで、管理エージェント設定画面で接続関連のパラメータを指定することが出来るようになります。ここにAPI ServerのリソースURIとAuthTokenを指定します。

3.インポート処理関連(OpenImportConnection/GetImportEntriesメソッド)
 まずはOpenImportConnectionで、設定パラメータからリソースURIとAuthTokenの値を取り出し、後続のGetImportEntriesで使えるようにグローバル変数にセットしておきます。
                resource_uri = _configParameters[ConstDefinition.CFG_RESOURCE_URI].Value.ToString();
                auth_token = _configParameters[ConstDefinition.CFG_AUTH_TOKEN].Value.ToString();

 次に、API Server(を経由してSalesforce.com)からユーザ情報を取得するGetImportEntriesです。やることはシンプルで、API ServerのリソースURIへAuthToken付きのGETリクエストを投げ、取得したJSONをパースしてConnector Space上のエントリに追加していくだけです。尚、本来はページング処理などをする必要があるのですが、今回はテストなので省略しています。
                var _csentries = new List<CSEntryChange>();
                string _importEntriesJSON = utils.GetContentsWithAccessToken(resource_uri, auth_token, null);
                var _getImportEntriesByObjectTypeResult = JObject.Parse(_importEntriesJSON).SelectToken("value").ToString();
                var _importObjectJSONArray = JArray.Parse(_getImportEntriesByObjectTypeResult);
                foreach (var _importObjectJSON in _importObjectJSONArray)
                {
                    var _csentryChange = CSEntryChange.Create();
                    _csentryChange.ObjectModificationType = ObjectModificationType.Add;
                    _csentryChange.ObjectType = "Person";
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("Alias", _importObjectJSON["Alias"].ToString()));
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("Email", _importObjectJSON["Email"].ToString()));
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("Username", _importObjectJSON["Username"].ToString()));
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("LastName", _importObjectJSON["LastName"].ToString()));
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("EmailEncodingKey", _importObjectJSON["EmailEncodingKey"].ToString()));
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("LanguageLocaleKey", _importObjectJSON["LanguageLocaleKey"].ToString()));
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("LocaleSidKey", _importObjectJSON["LocaleSidKey"].ToString()));
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("ProfileId", _importObjectJSON["ProfileId"].ToString()));
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("TimeZoneSidKey", _importObjectJSON["TimeZoneSidKey"].ToString()));
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("UserPermissionsOfflineUser", false));
                    _csentryChange.AttributeChanges.Add(AttributeChange.CreateAttributeAdd("UserPermissionsMarketingUser", false));
                    _csentries.Add(_csentryChange);
                }
                var _importReturnInfo = new GetImportEntriesResults();
                _importReturnInfo.MoreToImport = false;
                _importReturnInfo.CSEntries = _csentries;
                return _importReturnInfo;

utils.GetContentsWithAccessTokenの中ではx-cdata-authtokenヘッダにAuthTokenをセットし、リソースURIにGETリクエストを投げているだけです。
                _httpClient.DefaultRequestHeaders.Add("x-cdata-authtoken", _accessToken);
                return await _httpClient.GetStringAsync(_url);


4.エクスポート処理関連(OpenExportConnection/PutExportEntriesメソッド)
 こちらは先のインポートとは逆で、実際にAPI Serverへユーザを出力(プロビジョニング)する処理です。
 OpenExportConnectionではインポート時と同じくリソースURIとAuthTokenを設定から取得し、PutExportEntriesでConnector Space内のプロビジョニング対象ユーザを取得してJSON形式に整形してリソースURIへPOSTを行います。
                foreach (CSEntryChange _csentryChange in _csentries)
                {
                    // build json to POST
                    var _attr = new Dictionary<string, string>();
                    // anchor attribute
                    _attr.Add("Username", _csentryChange.DN.ToString());
                    switch (_csentryChange.ObjectModificationType)
                    {
                        case ObjectModificationType.Add:
                        case ObjectModificationType.Update:
                        foreach (string _attribName in _csentryChange.ChangedAttributeNames)
                        {
                            var _attributeChange = _csentryChange.AttributeChanges[_attribName];
                            var _valueChanges = _attributeChange.ValueChanges;
                            if (_valueChanges != null)
                            {
                                foreach (var _valueChange in _valueChanges)
                                {
 if (_valueChange.ModificationType == ValueModificationType.Add)
 {
// new value
_attr.Add(_attribName, _valueChange.Value.ToString());
break;
}
 }
                                }
                            }
                            // build json
                            string _exportDataJSON = JsonConvert.SerializeObject(_attr);
                            string _exportResult = utils.PostContentsWithAccessToken(resource_uri, auth_token, _exportDataJSON, null);

                            _exportEntriesResults.CSEntryChangeResults.Add(
                                CSEntryChangeResult.Create(_csentryChange.Identifier,
_csentryChange.AttributeChanges,
MAExportError.Success));
                                break;
                            case ObjectModificationType.Delete:
                                // NOT Implemented
                                break;

先ほどと同じく、utils.PostContentsWithAccessTokenではAuthTokenをヘッダにつけてJSONをリソースURIへPOSTしています。

大きくはこれで終わりです。
後はビルドしてAzure AD Connectが読み込めるようにExtensionsフォルダ(初期値はC:\Program Files\Microsoft Azure AD Sync\Extensions)へDLLファイルをコピーしておきます。

参考までにソースは以下のレポジトリにあげておきます。
https://github.com/fujie/apiserver

◆管理エージェントの設定

*繰り返しになりますが、Azure AD ConnectへカスタムManagement Agentを組み込む場合、所定の手続きを踏まないとサポート対象外となります。今回は手元にちょうどあった環境を使ったのでAzure AD Connectを使いましたが、本番環境ではMIM(Microsoft Identity Manager)やExgen LDAP Managerなど汎用的なID管理ツールを使ってください。
次は、Azure AD ConnectのSynchronization Serviceに開発したECMA2エージェントを設定します。
コネクタの種類にExtensible Connectivity 2.0を選択し、DLLをロードします。



後は、先に示した画面の様に接続設定でリソースURI、AuthTokenを設定し、管理対象の属性を選択すれば管理エージェント自体の構成は終了です。

次は、Run Profileの設定です。これを設定しないとAzure AD Connectはインポート、同期、エクスポートの各処理を実行してくれません。また、プロファイルの名前をFull Import、Full Synchronization、Export、など決められた名称にしておかないと30分に一回の自動処理の流れに乗せてくれず処理がスタックするので命名は大事です。
尚、今回作った管理エージェントにはDelta Importの処理を実装していないので、プロファイルの定義は行えません。イベントログにDelta Importの定義が無いのでスキップしますよ~という警告が出ますが特に影響はないので無視します。


これでSynchronization Service側の設定は完了です。

◆同期ルールを定義する

後は実際のMetaverse上のデータと先ほど作成した管理エージェントのConnector Space上のエントリの属性のマッピング(同期ルール)の設定を行います。FIMやMIMではポータルでISR/OSRを定義してルールを設定するのですが、今回はAzure AD ConnectなのでSynchronization Rules Editorを使います。個人的にはFIM/MIMの設定画面よりもこのルールエディタの方が使いやすいので好きだったりします。

今回はプロビジョニングだけでいいので、アウトバウンド同期ルールを定義します。
DirectionはOutbound、Connectorは先ほど作成したAPI Serverを選択してAdd new ruleをクリックしてルールを作成します。(以下は作成後の画面)

LinkTypeにprovisionを選択することで新規にユーザを作成するためのルールとして扱われます。

MetaverseとConnector SpaceのユーザのマッチングはUserprincipalNameおよびUsernameを使うので、Join rulesは以下のように設定しています。

後は、本命の属性のマッピングです。
エンコードやロケール、プロファイルIDなどは面倒なので固定値を入れて、ユーザ固有の値だけMetaverseの情報をマッピングします。

これでSaveをするとすべての設定が完了です。

◆テスト

後は、ローカルのAD上にユーザを作成、Azure AD Connectの同期ジョブが動くと、Azure ADへのユーザ作成に加えて、API Serverを経由してSalesforce.comへもユーザが作成されます。

この辺りは前回も紹介したデモの動画を見てもらった方が早いと思います。



Azure AD Connectを使った関係で色々とトリッキーなこともしていますが、少なくともID管理システム側でSalesforce.com自体の存在を殆ど意識せずに構成をすることが出来ていることはご理解いただけるのではないでしょうか?
スキーマの設定についても動的に取得する様に管理エージェントを構成すれば、API Serverの先にあるのがSalesforce.comだろうがDynamics365だろうが基本設定を変える必要は全くなく、API Serverが上手くハンドリングをしてくれますので、従来の個別開発に比べて相当簡単に各種SaaSなどへのプロビジョニングを構成することが可能になります。

今後、クラウド・サービスの活用がますます増えてくると思われますので、既存のID管理システムを効率よく対応させていくための一つの選択肢として、API Serverのようなデータ統合プラットフォームを活用するのはアリかも知れませんね。

2017年7月29日土曜日

APIゲートウェイでSaaSのIDを簡単に管理する①

こんにちは、富士榮です。

先日、CDATAさんのイベントで、CDATA API Serverを利用してローカルADのアカウントをSalesforceへプロビジョニングする、というデモをお見せしました。



当日は時間も限られていたのと、あくまでAPI Serverの活用事例の一つとして紹介したので、あまり細かい話はしなかったのですが、ID管理をやっている方々からは、このデモの仕組みをもう少し細かく知りたい、という声も頂いたので少し細かくご紹介していきたいと思います。

当日の資料はこちら。




まずは、どのようなデモをお見せしたのか、動画を用意しているので最初にこちらをご覧ください。


使っている道具は、
・オンプレミスのActive Directory
・Azure AD Connect+REST Management Agent(カスタム)
・Azure Active Directory
・CDATA API Server 2017J
・Salesforce.com
です。
*ちなみにAzure AD ConnectへカスタムManagement Agentを組み込む場合、所定の手続きを踏まないとサポート対象外となります。今回は手元にちょうどあった環境を使ったのでAzure AD Connectを使いましたが、本番環境ではMIM(Microsoft Identity Manager)やExgen LDAP Managerなど汎用的なID管理ツールを使ってください。

こんなことをしなくてもAzure ADから直接Salesforce.comへプロビジョニングすればいいじゃん、という話はありますが、手軽にテナントが用意できるSaaSなのであえてSalesforce.comを選択しています。もちろんCDATA API Serverが接続用のドライバを持っているサービスであれば何でも構いません。


では、早速環境の解説をしていきます。

1.オンプレミスのActive DirectoryからAzure ADへの同期環境を構成する

これは、特に特殊なことはしていません。Office365向けのID基盤を構築する時と同様にAzure AD Connectを構成します。

ものすごいシンプルな構成です。ローカルADもexample.localですし。。。


2.Salesforce.comのテナントを用意し、Azure ADとシングルサインオンを設定する

これも良くあるものなので、何も細かいことは気にしません。
以下の手順で設定をしていきます。

・Salesforce.comへのカスタムドメインの追加

・Azure ADにSalesforce.comアプリの追加とシングルサインオン設定
 サインオンURL、EntityIDにSalesforce.comに設定したカスタムドメインを指定し、証明書をダウンロードしておきます。

・Salesforce.comへAzure ADとのシングルサインオン設定
 Azure ADからダウンロードした証明書のアップロード、Issuerの設定、SSO URI、SLO URI、Salesforce側のEntityIDの設定を行います。設定すべきURI等の情報はAzure ADの設定ページに手順を含め記載されています。

ここまででシングルサインオンは出来るようになります。


3.API ServerとSalesforce.comを接続する

API Serverはここから評価版のダウンロードができます。
http://www.cdata.com/jp/apiserver/

ただ、この本体にはSalesforce.comとの接続に使うドライバが同梱されていないので、別途Salesforce.comドライバ(ADO.NET版)をダウンロードします。
こちらも評価版があります。
http://www.cdata.com/jp/download/?f=ado

インストール自体は次へ、次への世界なので何も気にすることは無く、インストールが終わるAPI Serverが起動してきます。
ちなみにデモでは手元のWindows 10の端末で動かしています。

設定メニューより接続タブを開き、新規に接続先を追加します。

接続先アプリケーションとしてSalesforceを選択します。


Salesforce.comへの接続に使うユーザIDとパスワードを入れ、保存します。

ちなみに、信頼されていないネットワークから接続している場合は、セキュリティ・トークンの設定が求められることがあります。

このエラーが出た場合は、Salesforce.comに管理者でログインし個人の設定からセキュリティ・トークンをリセットし、メールで送られてくるセキュリティ・トークンをAPI Serverに設定します。



次に、Salesforce.comのユーザを管理しているテーブルをAPI Serverのリソースとして定義し、REST APIとして公開します。
同じく、設定メニューの中のリソースタブを開き、リソースを追加します。

データソースに先ほど定義したSalesforce.comへの接続を選択します。

ユーザ情報が格納されているテーブルの名前はその名の通りUserなので、選択して保存します。

Userテーブルのカラム一覧が自動的に取得されるので、そのまま保存します。

ここまででSalesforce.comのUserテーブルをAPI ServerがREST APIとして公開できました。
最後にAPI接続を行うためのAPI Server上のユーザを定義します。
ユーザタブを開き、追加をします。

ユーザ名と実行できるメソッドを指定して保存します。

保存すると認証に使うAuthトークンが表示されるのでユーザ名と合わせてメモしておきます。

これで設定は完了です。

接続確認としてユーザ一覧を取得してみます。
APIメニューを開き、先ほど作成したリソースを開くとエンドポイントとメソッドが出てきます。

今回はテストなのでユーザ一覧を取得するので、単純にUserエンドポイントをGETします。
BASIC認証がかかり、ダイアログが出てくるので先ほど作成したユーザとAuthトークンをID、パスワードとして入力します。

上手くいくと、ユーザ一覧がODATA形式で取得出来ます。

これで、API Server経由でSalesforce.com上のユーザを操作するための準備はすべて整いました。

後は、Azure AD ConnectからAPI Serverで公開したAPIを叩くだけです。
この部分は若干コードを書くので、次回詳細は解説したいと思います。

ということで今回はここまでです。

2017年7月13日木曜日

「ID管理システム導入における現状把握チェックリスト」が公開されました

こんにちは、富士榮です。

JNSA(日本ネットワークセキュリティ協会)のアイデンティティ管理ワーキンググループで一昨年~昨年と分科会リーダーとして取りまとめて来た「ID管理システム導入における現状把握チェックリスト」が公開されました。

 こちらからダウンロードできます。
 http://www.jnsa.org/result/2017/std_idm/index.html

主にID管理システムの導入を企画する段階でエンドユーザ企業と導入ベンダやコンサルとの間に発生しやすいギャップを埋めることを目的として作成したツールで、様々な観点で企業内の現状把握をどのような観点で行うか、をチェックリスト形式で取りまとめました。

本来は、どこまで出来ていれば良いか?という基準・水準も設定できるのがゴールなのですが、まず今回リリースした第1版では現状把握を行うための観点、項目をとりまとめています。

Excelシート上で各項目を評価していくと、グラフを作成することが出来るので、現状把握の度合を可視化することが出来ます。


是非一度試して頂き、フィードバックを頂ければと思いますのでよろしくお願いいたします!



2017年6月30日金曜日

[Office365]Azure AD Connectの脆弱性?と最新版へ更新後の運用上の変化点

こんにちは、富士榮です。

先日、Azure AD Connectに関するセキュリティ・アドバイザリが発表され、脆弱性対応版として最新版がリリースされました。
脆弱性対応のためとはいえ、一部ヘルプデスク運用が変わってくるので、Office365やAzure ADの管理者の方は十分に注意して運用マニュアルの修正などを行う必要があります。

 セキュリティ・アドバイザリ 4033453
  Azure AD Connect の脆弱性により特権が昇格される
  https://technet.microsoft.com/ja-jp/library/security/4033453

 最新ビルド(1.1.553.0)
  https://www.microsoft.com/en-us/download/details.aspx?id=47594

しかし、発表された内容を見ていると、どちらかというと脆弱性というよりも単に不適切な運用をしているだけじゃ、、、という話なので内容を解説してみたいと思います。

また、アドバイザリの中では対応策として、最新ビルドにバージョンアップすることが推奨されていますが、単にバージョンアップしただけでは環境によっては不具合が出ることもあるので、その辺りも解説しておきます。

最後に、Azure AD Connectの話としてアドバイザリが出ていますが、構成によってはFIM(Forefront Identity Manager)/MIM(Microsoft Identity Manager)にも当てはまる内容なので、FIM/MIMを使っている場合の構成の見直しポイントも簡単に。

◆脆弱性?の概要

簡単に言うと、パスワード書き戻しが有効になっているテナントにおいて、同期元のローカルActive Directory上で管理者権限を持っているユーザのパスワードをAzure ADやOffice 365上でリセットすると当然の事ながらローカルActive Directory上の管理者権限を持ったユーザのパスワードもリセットされてしまうので、悪意のあるAzure AD管理者がクラウド上でパスワードリセットを行うことによりローカルActive Directoryの管理者権限の奪取が可能になってしまう、という話です。

色々と前提があるので整理をしておきましょう。

  • 環境
    • パスワード書き戻しが有効になっていること
    • 管理者権限のあるユーザをAzure ADへ同期していること
    • 同期を実行しているユーザに特権ユーザに対するパスワードリセットの権限を付与していること(以下が典型的なケースです)
      • Domain AdminsやEnterprise Adminsのメンバにしている
      • 同期対象のOUの管理権限を同期ユーザへ委譲し、AdminSDHolderコンテナにパスワードリセット権限を付与している
  • 脆弱性利用者
    • 悪意のある管理者。オンプレミスのリソース(AD配下)へアクセスが可能なこと

※AdminSDHolerの話は国井さんのブログ記事を参照してください。
 

こうやって見ていくと当たり前すぎて、製品の不具合というより構成の問題という気がしてきます。
基本的に同期対象となっているOUに管理者権限を持ったユーザが存在するのは、、、ということです。同期してOffice365にログインするユーザなのであれば、恒常的にローカルActive Directoryの管理者権限を与える必要もないはずですし。

◆実際どうなるのか?

では、管理者権限を持ったローカルActive Directory上のユーザをAzure Active Directoryへ同期させてみて、パスワード・リセットをしてみます。

まずは、同期されたユーザ自身によるパスワード変更のパターンです。
アクセスパネルのプロフィール変更画面よりパスワードを変更します。

当然ですが、パスワードがオンプレミスに書き戻され、新しいパスワードでログインできるようになります。(試しにリモートデスクトップしてみるとちゃんとログインできます。当たり前ですが)


次に、SSPR(セルフ・サービス・パスワード・リセット)のシナリオを見てみます。いわゆる秘密の質問や認証用電話・メールなどを使ってパスワードを忘れた際に回復する、というシナリオです。
ログイン画面からパスワード忘れの場合のリンクをクリックすると回復画面に遷移するので、CAPTCHAを入力します。

秘密の質問への回答をします。


無事にパスワードがリセットされ、ローカルActive Directoryへパスワードが書き戻されます。

悪意のあるユーザが秘密の質問を推測してしまうケースは結構あるそうなので、第3者によってパスワードのリセットがされ、ローカル管理者の権限が奪取される、ということもあり得ますね。


最後に、管理者によるリセットです。
Azure AD Portalからユーザを選んでパスワードをリセットするやつですね。

これも管理者がリセットを行い、一時パスワードが割り当てられた段階でローカルActive Directoryのパスワードも変更されるので、一時パスワードでローカルリソースへアクセスできてしまいます。

そう、パスワード書き戻しの機能を普通に使っているだけです。
単に対象となっているユーザの中に管理者権限を持っているユーザが存在しただけです。

これが脆弱性なのか、と・・・。


◆Azure AD Connectのバージョンアップと注意点

どのみち、今後のバージョンのAzure AD Connectにはこの改修が入ってしまうので、仕方がないので対応版である1.1.553.0へバージョンアップします。

バージョンアップによる具体的な変更内容は、アドバイザリのサイトにもあるように以下の2点です。

  • 対象ユーザのadminCount属性の値を見てNullもしくは0なら一般ユーザとみなし、パスワード書き戻しを許可する
  • 対象ユーザが特権ユーザだった場合、パスワードリセットを要求したAzure ADユーザが、対象ユーザと同じユーザだった場合は書き戻す(メタバース上で要求したユーザと対象ユーザの関係を確認する)
    • この部分が原文・翻訳ともにものすごくわかりにくいです。
      • 日本語「要求したユーザーが対象のオンプレミス AD アカウントのオーナーであるかどうかを検証します。それは、対象のオンプレミス AD アカウントと、要求したユーザーの Azure AD アカウントの関係をメタバースで確認します。要求したユーザーがオーナーの場合、Azure AD Connect はパスワード ライトバック要求を許可します。そうではない場合、要求は拒否されます」
      • 原文「it then validates whether the requesting user is the owner of the target on-premises AD account. It does so by checking the relationship between the target on-premises AD account and the Azure AD account of the requesting user in its Metaverse. If the requesting user is indeed the owner, Azure AD Connect permits the Password writeback request. Otherwise, the request is rejected」
    • このオーナー(is the owner)というのが何を指すのか、が全く分からず、ローカルAD上のOUや対象ユーザのセキュリティ構成でオブジェクトのオーナーにしてみたり、と色々とやったのですが、結局オーナー=自身のアカウント、というオチだと思います。#違ったらご指摘ください。


早速バージョンアップを行います。


無事に1.1.553.0になりました。


この状態でユーザ自身でのパスワード変更をAzure AD側で行います。


ここは問題なく変更、書き戻しされます。

同様に自身によるパスワード・リマインドでも問題なく変更、書き戻しされます。

次に管理者によるリセットです。
見事に失敗します。

この時、イベントログには特権ユーザに対するパスワードリセットが拒否された旨、記録されます。
このAdminUpnとうのがリセットを要求した管理者ユーザ、そのあとのUserPrincipalNameが対象のユーザでこの2つのUPNが合致しないとリセット・書き戻しは行われません。


ちなみに、対象ユーザが一般ユーザの場合は従来通り問題なく管理者によるパスワード・リセットを行うことが可能です。

つまり、今後は運用を行う上で、ローカルActive Directory上で管理者権限を持っているユーザについては自分自身でしかパスワード・リセットが出来ない、ということになりますので、従来のヘルプデスク等の運用を変えなければなりません。
この点が最大の注意点です。


◆最後に。FIM/MIMユーザへ

今回「脆弱性」として取り上げられた仕組みは基本的にFIM/MIMにおいても同じですので、管理者権限を持つアカウントのパスワードを、悪意のある別の管理者がリセットすることが出来ます。これを製品の脆弱性や不具合と呼ぶのは微妙ですが、FIM/MIMにおいては今回Azure AD Connectが行った対応は入っていませんので、管理者権限を持つユーザについては自分自身でしかパスワードを更新できない様にMPRを工夫する、などの対応が必要となります。


2017年6月26日月曜日

[告知]CDATA API Serverローンチイベントとグローバル企業向けITセミナでIDの話をします

こんにちは、富士榮です。

7月20日(木)と21日(金)に以下2つのセミナで登壇します。
いつも告知が直前すぎるので、今回は早めに告知させていただきます。

1.CDATA Day 2017
 日時  :7月20日(木)15:00~18:00
 申し込み:http://www.cdata.com/jp/events/cdataday17/
 タイトル:アイデンティティAPIとデータ統合プラットフォームの活用
 場所  :日本マイクロソフト株式会社 品川本社 セミナルーム

2.Enterprise IT seminar by professionals from global IT companies
 日時  :7月21日(金)14:30~17:00
 申し込み:https://www.xlsoft.com/jp/products/cdata/seminar.html
 タイトル:Designing cloud-based Identity and Access Management system for global enterprises
 場所  :エクセルソフト株式会社 セミナルーム


それぞれ簡単に内容を紹介します。

まずはCDATA Day 2017からですが、こちらはCDATA社のAPI Serverのローンチイベントということもあり、API Serverを使ってSCIMなどアイデンティティAPIを実装する話をします。(完全SCIM互換にするにはまだ若干機能不足はあるのですが、その部分は今後の期待ということで)
また、元々のCDATAの強みであるデータ統合基盤としてのアダプタの豊富さを利用してプロビジョニングを手軽に実装する方法なども考えられるので、その方面への活用についてもお話しできればと思っています。

先日ドイツで開催されたEuropean Identity & Cloud Conference 2017のKeynoteでOne IdentityのVPであるJackson Shawも話していましたが、現状各種アプリケーションのSCIMへの対応が中々進んでいない中で、ID管理製品側で専用のアダプタを開発するのではなく、データ統合プラットフォーム(クラウドベースのiPaaS/Integration Platform as a Serviceを含む)をID管理システムとターゲットシステムの間に挟む、という構成もあり得ると考えています。

こんな感じです。(出典:European Identity & Cloud Conference 2017 Keynote : When will Identity and Access Management be Digital Transformed – Jackson Shaw / VP One Identity)


この辺りを(できれば)デモを交えながら話せれば、と思います。


次に、翌21日(金)に行われるEnterprise IT Seminarです。
こちらは外資系企業のIT部門や日系企業で現地法人とやり取りをするIT部門の方々を対象として、セキュリティ、ERP/CRM、アプリケーション開発、データ統合の4つのテーマでグローバル・プロジェクトをどのように進めるか、という話があり、私はその中のセキュリティ、アイデンティティ管理のコマを受け持ちます。(全編英語です)

法令の違いはもちろんですが、全体最適に関する考え方のスケールがやはり日本企業の中だけで進めるプロジェクトとは違いますので、利用するツールやサービスの選定を含め色々と考えるべきことが多々あります。また、特にIDaaSの優位性が出やすい領域でもあるので、その辺りの割り切り方などについてもお話しできるといいかな、と思っています。


それでは。会場でお会いしましょう。