テンプレート処理中にエラーが発生しました。
Java method "com.liferay.portal.json.JSONFactoryImpl.createJSONObject(String)" threw an exception when invoked on com.liferay.portal.json.JSONFactoryImpl object "com.liferay.portal.json.JSONFactoryImpl@2ad66ae2"; see cause exception in the Java stack trace.

----
FTL stack trace ("~" means nesting-related):
	- Failed at: navigationJSONObject = jsonFactoryUti...  [in template "17855804202317#32484267#LEARN-ARTICLE-NAV" at line 4, column 9]
----
1<#assign 
2	groupFriendlyURL = themeDisplay.getScopeGroup().getFriendlyURL() 
3	groupPathFriendlyURLPublic = themeDisplay.getPathFriendlyURLPublic() + groupFriendlyURL 
4	navigationJSONObject = jsonFactoryUtil.createJSONObject(navigation.getData()) 
5	navigationMenuItems = 
6
7			"Analytics Cloud": { 
8				"image": "/documents/d${groupFriendlyURL}/analytics_c-svg", 
9				"title": "Analytics Cloud", 
10				"url": "analytics-cloud" 
11			}, 
12			"Commerce": { 
13				"image": "/documents/d${groupFriendlyURL}/commerce_product-svg", 
14				"title": "Commerce", 
15				"url": "commerce" 
16			}, 
17			"DXP": { 
18				"image": "/documents/d${groupFriendlyURL}/dxp_p-svg", 
19				"title": "DXP / Portal", 
20				"url": "dxp" 
21			}, 
22			"Liferay Cloud": { 
23				"image": "/documents/d${groupFriendlyURL}/dxp_c-svg", 
24				"title": "Liferay Cloud", 
25				"url": "liferay-cloud" 
26			}, 
27			"Reference": { 
28				"image": "/documents/d${groupFriendlyURL}/reference-svg", 
29				"title": "Reference", 
30				"url": "reference" 
31
32
33 
34	breadcrumbJSONArray = navigationJSONObject.getJSONArray("breadcrumb") 
35	childrenJSONArray = navigationJSONObject.getJSONArray("children") 
36	parentJSONObject = navigationJSONObject.getJSONObject("parent") 
37	productJSONObject = breadcrumbJSONArray.getJSONObject(breadcrumbJSONArray.length()-1)!navigationJSONObject.getJSONObject("self") 
38	siblingsJSONArray = navigationJSONObject.getJSONArray("siblings") 
39/> 
40 
41<div class="learn-article-nav"> 
42	<#if productJSONObject?has_content && productJSONObject.getString("title")?has_content && navigationMenuItems[productJSONObject.getString("title")]?has_content && navigationMenuItems[productJSONObject.getString("title")].title?has_content> 
43		<div 
44			class="dropdown learn-article-nav-root learn-dropdown" 
45
46			<div class="learn-article-nav-item"> 
47				<div class="d-flex"> 
48					<div class="learn-article-nav-image"> 
49						<img 
50							class="lexicon-icon lexicon-icon-caret-bottom product-icon" 
51							role="presentation" 
52							src='${navigationMenuItems[productJSONObject.getString("title")].image}' 
53							viewBox="0 0 512 512" 
54						/> 
55					</div> 
56 
57					<span class="learn-article-nav-text">${navigationMenuItems[productJSONObject.getString("title")].title}</span> 
58				</div> 
59 
60				<div id="dropdown-icon"> 
61					<svg 
62						class="lexicon-icon lexicon-icon-caret-bottom" 
63						role="presentation" 
64						viewBox="0 0 512 512" 
65
66						<use xlink:href="/o/admin-theme/images/clay/icons.svg#caret-bottom"></use> 
67					</svg> 
68				</div> 
69			</div> 
70 
71			<ul class="dropdown-menu learn-dropdown-menu"> 
72				<#list navigationMenuItems as key, value> 
73					<li> 
74						<a 
75							class="dropdown-item learn-article-nav-item" 
76							href="/w/${navigationMenuItems[key].url}/index" 
77							tabindex="4" 
78
79							<span class="d-flex"> 
80								<span class="learn-article-nav-image"> 
81									<img 
82										class="lexicon-icon lexicon-icon-caret-bottom product-icon mt-0 mr-2" 
83										role="presentation" 
84										src="${value.image}"height: 25px; margin-left: 5px; max-width: none; width: 25px; 
85										viewBox="0 0 512 512" 
86									/> 
87								</span> 
88								<span class="learn-article-nav-text">${value.title}</span> 
89							</span> 
90 
91							<#if navigationMenuItems[productJSONObject.getString("title")].url == value.url> 
92								<span> 
93									<@clay["icon"] symbol="check" /> 
94								</span> 
95							</#if> 
96						</a> 
97					</li> 
98				</#list> 
99			</ul> 
100		</div> 
101	</#if> 
102 
103	<div class="learn-article-nav-content"> 
104		<#if parentJSONObject?has_content && parentJSONObject.getString("url")?has_content> 
105			<div class="learn-article-nav-item learn-article-nav-parent liferay-nav-item p-2"> 
106				<div class="mr-2"> 
107					<a 
108						href='${parentJSONObject.getString("url")}' 
109
110						<svg 
111							class="lexicon-icon lexicon-icon-angle-left" 
112							role="presentation" 
113							viewBox="0 0 512 512" 
114
115							<use xlink:href="/o/admin-theme/images/clay/icons.svg#angle-left"></use> 
116						</svg> 
117					</a> 
118				</div> 
119 
120				<span>${parentJSONObject.getString("title")}</span> 
121			</div> 
122		</#if> 
123 
124		<#if childrenJSONArray.length() gt 0> 
125			<ul class="m-0 p-2"> 
126				<#list 0..childrenJSONArray.length()-1 as i> 
127					<li class="learn-article-nav-item"> 
128						<a 
129							class='liferay-nav-item ${(navigationJSONObject.getJSONObject("self").url == childrenJSONArray.getJSONObject(i).url)?then("selected", "")}' 
130							href="${childrenJSONArray.getJSONObject(i).url}" 
131
132							<span>${childrenJSONArray.getJSONObject(i).getString("title")}</span> 
133						</a> 
134					</li> 
135				</#list> 
136			</ul> 
137		<#elseif siblingsJSONArray.length() gt 0> 
138			<ul class="m-0 p-2"> 
139				<#list 0..siblingsJSONArray.length()-1 as i> 
140					<li class="learn-article-nav-item"> 
141						<a 
142							class='liferay-nav-item ${(navigationJSONObject.getJSONObject("self").url == siblingsJSONArray.getJSONObject(i).url)?then("selected", "")}' 
143							href="${siblingsJSONArray.getJSONObject(i).url}" 
144
145							<span>${siblingsJSONArray.getJSONObject(i).getString("title")}</span> 
146						</a> 
147					</li> 
148				</#list> 
149			</ul> 
150		</#if> 
151	</div> 
152</div> 

SAML管理

SAML管理パネルは、SAMLインスタンスを構成するのに最適な場所です。 インスタンス設定の代わりにこれを使用すると、SAML管理を効率化できます。

SAML管理により、IDP(アイデンティティプロバイダー)、サービス・プロバイダー、およびサービス・プロバイダー接続を設定できます。 アクセスするには、 [グローバルメニュー](Global Menu) → [コントロールパネル] → [SAML管理] をクリックします。

一般タブ

[一般]タブには、ロールに関係なくSAMLに適用されるオプションが表示されます。

有効: すべての設定が完了した後にこのボックスをオンにして、SAML認証を有効にします。

SAMLロール: SAMLロール(アイデンティティプロバイダーまたはサービス・プロバイダーのいずれか)を選択します。

エンティティ ID: このSAMLエンティティの一意の識別情報(IdPもしくはSP)。 最大1024文字まで使用可能です。

証明書と秘密鍵のセクションには、ここか システム設定でキーストアを設定したときに生成された鍵が表示されます。 ここでは、新しい証明書を生成するか、別の場所で作成した証明書をインポートすることで証明書を置き換えることができ、また、証明書をダウンロードして別の場所にインポートすることもできます。

もし、自動生成された証明書を交換する必要がある場合は、簡単です。

  1. 証明書を置換] をクリックします。

  2. [証明書を作成]タブは、デフォルトで有効になっています。 鍵の必要事項を入力してください。

  3. 完了したら、 [保存] をクリックします。

新しいキーの詳細が表示されました。

すでにキーを生成している場合、そのキーは PKCS #12 アーカイブに保存して、Liferay DXPにインポートする必要があります。

  1. 証明書を置換] をクリックします。

  2. 証明書をインポート] タブをクリックします。

  3. キーストアのパスワードを入力し、PKCS #12キーファイルをアップロードエリアにドロップするか、ファイルセレクタを使用して選択します。

これで鍵のインポートは完了です。

サービス・プロバイダー

  1. SAMLロールフィールドから サービス・プロバイダー ロールを選択します。

  2. 証明書と秘密鍵セクションは、SAML用のキーストアを作成するためのものです。 [証明書を作成] をクリックし、以下の情報を入力します。

    • 共通名(姓と名)
    • 組織の名称
    • 組織単位の名称
    • 市町村名または地域名
    • 州または地方の名称
    • 国名
    • キーストアが有効である日数(キーストアの有効期限が切れるまでの日数)
    • 鍵のアルゴリズム(デフォルトはRSA)
    • 鍵の長さ(ビット数)(デフォルトは2048)
    • キーのパスワード

    キーストアは、ファイルシステムストレージ(デフォルト)とドキュメントとメディアストレージの2つのストレージオプションがあることを覚えておいてください。 デフォルトでは、証明書は暗号化に SHA256 アルゴリズムを使用し、 MD5SHA256によって指紋認証と自己署名されます 。 必要な情報を入力したら、 [保存] をクリックします。

  3. 保存] をクリックした後、証明書に関する情報の表示や証明書のダウンロードができることを確認します。 確認できれば、キーストアの作成に成功したことになります。 キーストアの作成後、追加のオプションが表示されます。 3つのタブがあります。

    一般 :SAML SPの有効・無効を設定し、必要なキーストアを管理します。

    サービス・プロバイダー :このタブでは、SPの基本設定と詳細設定を管理します。

    アイデンティティ・プロバイダー接続 :このタブでは、IdPへの接続を管理します。 複数のIdP接続が可能です。

  4. また、暗号化証明書を生成することも可能です。 これは、アサーションを暗号化するための別のキーです。 アサーションを暗号化したい場合は、そのためのキーを生成する必要があります。 手順は、上記手順2の証明書作成と全く同じです。

  5. 次に、アイデンティティ・プロバイダー接続を設定する必要があります。 [アイデンティティ・プロバイダー接続] タブをクリックします。 アイデンティティ・プロバイダーの名前、エンティティID、メタデータURLを入力します。 すでに別のLiferay DXPインストールをアイデンティティ・プロバイダーとして設定している場合は、次の情報を入力することになります。

    • 名前: Liferay IdP
    • エンティティ ID:[ID of IdP]
    • 許容時刻誤差(クロックスキュー):SPとIdPの間の許容誤差をミリ秒単位で設定します。
    • Authnを強制する:コンテキストに関わらず、IdPが再認証を強制的に行うかどうか。
    • メタデータURL: http://localhost:8080/c/portal/saml/metadata (最初にこのURLをテストしてください)
    • 名前識別子フォーマット:SAML設定を参照。
    • 属性マッピング:SAML設定を参照。
    • Keep Alive URL:SAML設定を参照。
    important

    Liferay Connector to SAML 2.0アプリでは、SAML IdPメタデータファイルへのURL、 または実際の(アップロードされた)SAMLメタデータXMLファイルの いずれかを使用できます。 メタデータURLフィールドに入力された値は、メタデータURLがあり、指定されたメタデータXMLファイルがない場合にのみ、データベースに永続化されます。 そうでない場合、Liferay DXPはオリジナルのメタデータURL をデータベースに保持します。 この動作により、一度メタデータURLを指定すれば、常にデータベースにメタデータURLが保存されます。 これにより、以前に入力したメタデータURLやそのフォーマットを忘れてしまった場合でも、表示されているメタデータURLを見て、表示されているメタデータURLを修正するか、メタデータXMLファイルを指定して以前に保存したメタデータURLを上書きするかを選択できます。

  6. 最後に、証明書と秘密鍵の情報を保存し、アイデンティティ・プロバイダー接続を設定したら、[一般]タブの上部にある [Enabled] にチェックを入れ、 [保存] をクリックします。 LiferayがSAMLサービス・プロバイダーになりました。

SAMLサービス・プロバイダーのセッションは、アプリケーションサーバー上の通常のセッションに関連付けられていることに注意してください。 アプリケーションサーバーのセッション切れにより、サービス・プロバイダーのセッションは終了しますが、シングルログアウトは開始されません。

サービスプロバイダの設定

サービスプロバイダ]タブには、いくつかの設定オプションが表示されます。

アサーション署名を必須にする: SAMLメッセージ全体に加えて、SAMLアサーションにIdPによる個別の署名を要求する場合は、このボックスをオンにします。

許容時刻誤差(クロックスキュー): SPとIdPの時差の許容誤差をミリ秒単位で設定します。

LDAPインポートを有効にする: このボックスをオンにすると、このSPのインスタンス設定で宣言されたLDAPサーバーからユーザー属性をインポートします。

Authnリクエストに署名しますか?: SP として設定されている場合、Authn リクエストに電子署名をします。

メタデータに署名しますか?: ピアSAMLエンティティに送信されるメタデータに署名します。

SSLを必須にする: このボックスをオンにすると、すべてのSAMLメッセージの転送にSSLが必要になります。 ピアに送信されるメタデータ内のすべてのURLは、 https プロトコルがプレフィックスとして付くようになります。

ログインポートレットの表示を許可する: ログインリクエストにSAML IdPがマッチしない場合に、ログインポートレットの表示を許可します。 このシナリオのユーザーは、Liferay DXPにローカルでログインします。

Important

SAML 応答自体が署名されている限り、個々のアサーションが署名される必要はない。 SPとIdPは、トランスポートレベルで暗号化するために、常にhttpsで通信する必要があります。

Liferay DXP は署名された SAML 応答を必要とします。 中間者攻撃が可能であり、アサーション内の情報が機密であると考えられる場合、署名と暗号化の両方を行うことができる。

複数のIdP接続を追加できます。 別のアイデンティティ・プロバイダーを追加するには、 [アイデンティティ・プロバイダーを追加] を再度クリックして、他のプロバイダーの詳細を入力します。 ユーザーがログインする際に、アイデンティティ・プロバイダーを選択するよう求められるので、ユーザーが認識できるようにプロバイダー名を記載しておいてください。

クラスター環境で、Liferay DXPをSAMLサービス・プロバイダーとしてセットアップする

Liferay Connector to SAML 2.0アプリは、クラスター環境のSSOソリューションとして使用することができます。 複数ノードのクラスターがロードバランサーの背後にある場合、すべてのノードをSPとして有効にし、同じキーストアマネージャーを共有する必要があります。

ファイルシステム・キーストアマネージャーを使用する場合(デフォルト)、以下を行います。

  1. 上記のように Liferayクラスターの各ノードをSAMLサービス・プロバイダーとして設定します。

  2. キーストアファイル([Liferay Home]/data/keystore.jks、デフォルト)を、最初のノードから残りのノードにコピーします。 このファイルは、SAMLプロバイダーアプリで作成されるJavaキーストアです。 キーストアには、SAMLコネクターアプリが管理する有効な証明書または自己署名証明書が含まれます。

  3. サービス・プロバイダーのメタデータが、URLまたはXMLファイルとして使用できるように生成されていることを確認します。 データベースのバックエンドが同じなので、メタデータは全ノードで共通です。 IdPのリクエストはロードバランサーを経由します。

  4. この時点で、すべてのノードが同じSAML SP構成を持ち、各ノードがWeb要求に応答して、SAMLプロトコルを処理できるようになります。 SSOソリューションをテストするには、ロードバランサー経由でLiferayにサインインし、いくつかの異なるサイトのいくつかのページに移動し、ログアウトしてください。

ドキュメントライブラリ・キーストアマネージャーを使用する場合、キーストアファイルは全ノードで共有されるデータベースに保存されるため、手順2をスキップします。

これで、Liferay DXPをSAMLアイデンティティ・プロバイダーまたはサービス・プロバイダーとして設定する方法がわかりました。 また、クラスター環境でSAMLを構成する方法もわかりました。

アイデンティティ・プロバイダー

SAMLロールとしてIdP(アイデンティティ・プロバイダー)を選択した場合、ここで設定することができます。 これらのフィールドは、同じものを設定できる インスタンス設定 の同様のフィールドに対応しています。

メタデータに署名しますか?: ピアSAMLエンティティに送信されるメタデータに署名します。

SSLを必須にする: このボックスをオンにすると、すべてのSAMLメッセージの転送にSSLが必要になります。 ピアに送信されるメタデータ内のすべてのURLは、 https プロトコルがプレフィックスとして付くようになります。

Authnリクエスト署名を要求する: このボックスをオンにすると、各Authnリクエストに送信元のサービス・プロバイダーによる署名が必要となります。 ほとんどの場合、これは有効になっているはずです。

セッション有効期間: IdPが管理するSSOセッションが継続する時間(秒)です。

セッション・アイドル・タイムアウト: アイドルセッションが期限切れとなるまでの時間(秒)。

サービス・プロバイダー接続

このインターフェイスを使用して、1つまたは複数のサービス・プロバイダー接続を設定することができます。 開始するには、 [サービス・プロバイダーを追加] をクリックします。 フォームに入力し、完了後、 [保存] をクリックします。

名前: SPに名前を付けます。 これは単なる説明用の名前であり、設定には使用されません。

エンティティID: このSPがここに接続するIdPのエンティティIDを入力します。 サービス・プロバイダーのメタデータで宣言されたエンティティIDと一致する必要があります。

有効: サービス・プロバイダー接続を有効にするには、このボックスをオンにします。

アサーション有効期間: アサーションが有効なセクション数を入力します。

強制暗号化: SPがアサーションを暗号化するための公開鍵を提供しない場合、シングルサインオンを中止します。

メタデータ: サービス・プロバイダーのメタデータXMLファイルのURLを指定するか、サービス・プロバイダーのメタデータXMLファイルを手動でアップロードしてください。 URLを指定すると、XMLファイルを取得し、定期的に更新のためのポーリングを行います。 更新間隔は、システム設定で、秒数を指定するランタイム メタデータの更新間隔 (saml.metadata.refresh.interval if using a config file) プロパティを使用して設定できます。 URLによるメタデータXMLファイルの取得に失敗した場合、サービス・プロバイダー接続を有効にすることはできません。 アイデンティティ・プロバイダーサーバーがURL経由でメタデータにアクセスできない場合、XMLファイルを手動でアッ プロードできます。 この場合、メタデータXMLファイルの自動更新は行われません。

名前識別子フォーマット: SAML応答で使用される名前識別子フォーマットを選択します。 サービス・プロバイダーが受信することを想定する内容に従って設定します。 Liferayサービス・プロバイダーの場合、メールアドレス以外の選択は、名前識別子がスクリーン名を指していることを示します。 これらのフォーマットは、Liferayアイデンティティ・プロバイダーにとって特別な意味を持ちません。 NameID の値は、名前識別子属性で定義されます。 次のオプションを参照してください。

名前識別子属性名: Liferay ユーザー オブジェクトのどの属性を NameID 値として使用するのかを指定します。 指定できる値は、 emailAddressscreenNameuuidです。 名前の前にstatic:もしくはexpando:を付けることができます。 staticという接頭辞を使うと、 static:の後に来るものが値になります。 expandoという接頭辞を使用すると、 expando:の後に指定したカスタムフィールドが値になります。 例えば、 expando:SSN は、 SSNという名前のユーザー カスタムフィールドを検索します。

属性が有効です: アサーション属性を含めて、解決します。

ネームスペース属性が有効です: このボックスをオンにすると、下記のように属性にネームスペースを付与することができます。

urn:liferay:user:expando: urn:liferay:user: urn:liferay:groups: urn:liferay:organizationRole: urn:liferay:organization: urn:liferay:roles: urn:liferay:siteRole: urn:liferay:userGroupRole: urn:liferay:userGroups:

属性: アサーションに含める属性のリストを、1行に1つずつ入力します。 各行はパースされる式です。 例:

organizations organizationRoles roles siteRoles userGroups static:[attributeName]=[attributeValue] expando:[userCustomFieldName]

完全なネームスペースは属性名に依存することに注意してください。 属性ネームスペースが役立つ場合があります。 異なるネームスペースからの属性名が競合する可能性がある場合に使用します。 例えば、 expando:user vs urn:liferay:roles:userです。

Keep Alive URL: ユーザーがLiferay IdP経由で複数のLiferay SPインスタンスにログインしている場合、そのうちの1つのブラウザウィンドウを開いたままであれば、セッションを維持することができます。 SPがLiferay DXPの場合のみ設定します。 URLは、https://[SP host name]/c/portal/saml/keep_aliveです。