NextcloudにSAML2.0でシングルサインオン

# 概要

Nextcloudと[サテライトオフィス・シングルサインオン](https://www.sateraito.jp/Google_Apps_SSO.html)のSAML認証機能を連携できないか試したところ、かなり手こずったが何とかできたので、もしかしたら他の人の役に立つかもとメモ。

SAMLについての日本語情報が少なく、サテライトオフィスやNextcloudもドキュメントにすべて書いてあるわけではないので、サテライトオフィスが吐くXMLや、Nextcloudのソースコードを見ながら設定した。そのため必ずしもSAMLの規格には沿ってないかもしれない点はご注意を。

# サテライトオフィス・シングルサインオンの設定

## 外部システム連携管理の設定

管理画面の「外部システム連携管理」から、以下のように設定し、「SSO用証明書ファイルの作成＆取得」で証明書をダウンロードする。

* 連係サービスプロバイダ : カスタム設定
* 連携方式 : SAML2.0
* 連携ユーザーID: メールアドレス
* IdPのEntityID: ドメイン固有のEntityID値を使用
* 認証応答メッセージのテンプレート : 後述のテンプレートを使用
* 正規化方式: **チェックを外す**

![image.png](https://qiita-image-store.s3.amazonaws.com/0/197772/ec8f2fe6-2f65-4b58-eef4-100cd45e2226.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/197772/6272f477-97bd-f075-d609-f4a5c0b1b8c8.png)


## メッセージテンプレート

NextcloudでIDやメールアドレスのマッピングに指定するのは、SAML応答の`AttributeStatement`に指定したもの。しかしサテライトオフィスのデフォルトの応答には`AttributeStatement`が含まれていないので、自分で設定する。

下記テンプレートを保存して、「認証応答メッセージのテンプレートをアップロード」で設定する。

~~~XML
<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response ID="[$$ ResponseID $$]" IssueInstant="[$$ IssueInstant $$]" Destination="[$$ AssertionConsumerServiceUrl $$]" InResponseTo="[$$ AuthnRequestID $$]" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
</samlp:Status>
<Assertion ID="[$$ AssertionID $$]" IssueInstant="[$$ IssueInstant $$]" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
<Issuer>[$$ Issuer $$]</Issuer>
<Subject>
<NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress">[$$ AuthUserID $$]</NameID>
<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<SubjectConfirmationData Recipient="[$$ AssertionConsumerServiceUrl $$]" NotOnOrAfter="[$$ NotOnOrAfter $$]" InResponseTo="[$$ AuthnRequestID $$]" />
</SubjectConfirmation>
</Subject>
<Conditions NotBefore="[$$ NotBefore $$]" NotOnOrAfter="[$$ NotOnOrAfter $$]">
<AudienceRestriction>
<Audience>[$$ Audience $$]</Audience>
</AudienceRestriction>
</Conditions>
<AuthnStatement AuthnInstant="[$$ AuthnInstant $$]">
<AuthnContext>
<AuthnContextClassRef>
 urn:oasis:names:tc:SAML:2.0:ac:classes:Password
 </AuthnContextClassRef>
</AuthnContext>
</AuthnStatement>
<AttributeStatement>
   <Attribute Name="emailAddress">
      <AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">[$$ AuthUserID $$]</AttributeValue>
   </Attribute>
</AttributeStatement>
</Assertion>
</samlp:Response>
~~~

2021年12月11日追記: NextCloudのバージョンが上がると`samlp:Response`に`InResponseTo="[$$ AuthnRequestID $$]"`が必要になったので、テンプレートを修正。

# Nextcloud設定

## Nextcloudのインストール

今回は省略。[公式サイト](https://nextcloud.com/install)参照。今回インストールしたバージョンは13.0.1。

## アプリ(user_saml)のインストール

管理者アカウントでログインし、「アプリ」「セキュリティ」から「SSO & SAML authentication」を「有効化」

![image.png](https://qiita-image-store.s3.amazonaws.com/0/197772/f8f6e94d-22a1-ffd3-bf5c-10f33e5f9cab.png)

## SAMLの設定

設定画面で下記のように設定。

* General
  * Optional display name of the identity provider : お好みで  
  * Attribute to map the OID to : `emailAddress`
  * Only allow authentication if an account exists on some other backend. (e.g. LDAP) : 既存のユーザのみ許可するときはチェックを入れる。チェックを入れない場合はSAMLで認証された新規ユーザはNextcloudで自動生成される。
  * Allow the use of multiple user back-ends (e.g. LDAP) : SAML認証以外も使うときはチェックを入れる。テスト中はチェックを入れておいたほうが無難(一度ログアウトしてしまうと、管理者もログインできなくなる)。
  * Use SAML auth for the Nextcloud desktop clients (requires user re-authentication) : デスクトップクライアントもSAML認証を使うときにチェックを入れる。
* Service Provider Data : 空欄
* Identity Provider Data
  * Identifier of the IdP entity (must be a URI) : Sateraito Officeの「IdPのEntity ID」を入力
  * URL Target of the IdP where the SP will send the Authentication Request Message : 「エンドポイントURL（ログイン）」を入力
  * URL Location of the IdP where the SP will send the SLO Request: 「エンドポイントURL（ログアウト）」
  * Public X.509 certificate of the IdP : 「SSO用証明書ファイルの作成＆取得」でダウンロードした証明書ファイルをテキストエディタで開いてペースト
* Attribute Mapping
  * Attribute to map the email address to : `emailAddress` (設定しなくてもOK)
* Security Settings
  * すべてチェックオフでOK

![image.png](https://qiita-image-store.s3.amazonaws.com/0/197772/f89714af-8a6e-8dd1-95dd-05d46acbf88d.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/197772/caf7aafb-5d3e-b134-b9fc-3a7c46b8e397.png)

# 確認

うまく設定できれば、NextcloudのログインページからサテライトオフィスのSSOページにリダイレクトされ、ログインに成功するとNextcloudに戻ってきて自動的に新規ユーザが作成される。

管理者アカウントでログインした場合、以下のように「ユーザーバックエンド」が「`user_saml`」のユーザができているはず。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/197772/0ab1be67-cb3d-8b62-c1d1-ae48f8e7df83.png)

# 備考

現時点ではNextcloudから「ログアウト」すると、CSRFエラーと出てくるが、ログアウトはされている。

GitHubでは同様の事例が何件か報告されているので、今後のアップデートで直っているかも。