シングルサインオン（SSO）におけるNameIDとAttribute Statementを具体例と図を使って解説

# はじめに
この記事は、シングルサインオン（SSO）を導入する人事部の方や、情報システム課の方に向けて、SAML（Security Assertion Markup Language）における『NameID』や『AttributeStatement』とは何か？を具体例を用いて解説します。専門用語が飛びかいますが、その都度言葉の意味を正確におさえながら読んで欲しいです。画像等も適宜追加していきます。

## シングルサインオンとは？
シングルサインオン（SSO）は、ユーザーが一度のログインで複数のアプリケーションを利用できる便利な仕組みです。これにより、一度ログインすれば、社内の様々なツールやシステムに追加のログインなしでアクセス可能となります。
シングルサインオンは、実際に認証したいサービス（アプリ）と、認証管理を一元化している認証サーバーが存在することで成り立ちます。これらをService Provider（以下SP）とIdentity Provider（以下IdP）と呼びます。

## SAMLとその役割
SAMLとは異なるシステム間の認証連携を実現する標準プロトコルとして広く使われています。SAMLを使えば、ユーザーは一度のサインオンで**安全に**複数のサービスを利用できるようになります。

:::note info
この記事では、SAMLの認証フローの中でも「NameID」と「Attribute Statement」に焦点を当て、それらがどのように認証情報のマッチングに役立つのかを具体例を交えて解説します。また、認証サーバー（Identity Provider 以下IdP）やサービスプロバイダ（Service Provider 以下SP）が正規表現を用いて認証情報を操作する実例も紹介します。
:::

## SSOのざっくりとした流れ
SSO（SP-initiatedを例とします）は以下の流れでやり取りが行われます

:::note info
最終的に「IdPの認証に成功している」かつ「SPへのログインを許可する」ことが必要です
:::

1. クライアントがSPにアクセスし、SSOがスタート
2. SPは作成した『SAML Request』を付与したHTTPレスポンスをPOSTもしくはRedirect形式でクライアントに返す
3. クライアントは渡された『SAML Request』を、IdPにHTTPリクエストとして渡す
4. IdPは受け取った『SAML Request』を開き、IdPにすでに認証済みか確認する。未確認の場合はクライアントにIdPのログイン画面を返し、認証させる
5. IdPの認証に成功した場合、IdPは作成した『SAML Response』を付与したHTTPレスポンスをPOSTもしくはRedirect形式でクライアントに返す
6. クライアントは渡された『SAML Response』を、SPにHTTPリクエストとして渡す
7. SPは受け取った『SAML Response』を開き、**「IdPの認証に成功している」** ことを確認する
8. SPは認証に成功しているユーザーの情報を参照し、**「SPへのログインを許可する」**
9. SPへのログインに成功すれば、クライアントに対して表示させたい画面を返す
（→別記事として詳しく書く予定です！）

5～6のイメージ図
**『ハートの手紙＝SAML Response』**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/e7d8a459-825e-7481-7a9c-40a2c89bba8c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/d35e521b-938f-f7c0-19f7-e3ca10fe0fb1.png)


**本記事では5で作成された『SAML Response』に含まれる認証情報（SAML Assertion）を、どのように使って、8で「SPへのログインを許可する」のかを掘り下げていきます。**

# SAML ResponseとSAML Assertionの概要
『SAML Response』はIdPがSPに送信するXML形式のデータで、ユーザーの認証情報を含みます。この中には、SAML Assertionと呼ばれる認証情報の要約が含まれています。

## SAML Assertionの構成要素
SAML Assertionは以下の要素で構成されています：

1. Version: SAMLプロトコルのバージョン（通常はSAML 2.0）
2. Issuer: アサーションを発行したIdPの識別子
3. Subject: 認証対象のユーザー情報（NameIDを含む）
4. Conditions: アサーションの有効条件（有効期限、SPのエンティティIDなど）
5. AuthnStatement: 認証方法や認証タイムスタンプ
6. Attribute Statement: ユーザー属性情報（任意項目）

↓イメージ図
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/929e9890-3fb0-6d18-8290-151f8045e7a6.png" width=64%>

:::note info
***『NameID(Subject)』または、『Attribute Statement』に含まれるユーザー情報を使って、SPのユーザー情報とマッチさせることで「SPへのログインを許可する」を実現させることができます***
:::

### ※NameID(Subject)とAttribute Statementの違い
- NameID：ユーザーを一意に識別するためのID（メールアドレスや社員番号など）で、SAML Responseには必ず存在しないといけない
- Attribute Statement：ユーザーの追加情報（氏名、所属部署、ロールなど）を含む任意設定項目

# 実際に具体的な例を見ながら感覚をつかもう！

例えばSPのユーザ情報（左側）とIdPのユーザー情報（右側）が以下のような状況だとします↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/1cc7426f-93e0-e6b1-2dae-26f1b35ca794.png)

* SPにはユーザーIDとして「12345」を持つユーザーが存在する
* IdPの設定で、『SAMLResponse』の中の『Assertion』に「NameID：12345」「Email：<foo>TaroTanaka</foo>@example.com」「userID：12345」を含んでいる

として具体例をもとに考えてみましょう！

:::note info
一般的にはNameIDを用いてSPの認証を行いますが、Attribute Statementを活用することで様々な状況でSSOによるログインを実現させることができます。
:::

# NameIDの詳細とその役割
### NameIDとは？
NameIDは、SAML Assertion内の<Subject>要素に含まれる必須の識別情報で、主にユーザーを一意に識別するために使用されます。SAMLにおけるNameIDは、一般的にはユーザーのID（メールアドレスや社員番号など）を表します。また、NameIDにはその形式（Format）を指定することが求められます。このFormatにより、NameIDがどのような形式で提供されているかを定義します。

## NameIDのFormat
SAMLでは、NameIDにはいくつかの標準的なフォーマットが定義されています。これにより、SPがどの形式でNameIDを解釈するべきかを指定できます。代表的なNameID Formatには次のものがあります。

### 1. `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`

* 説明：メールアドレス形式のNameID。一般的に、ユーザーのメールアドレスがNameIDとして使用される場合に用いられます

### 2. `urn:oasis:names:tc:SAML:2.0:nameid-format:persistent`

* 説明：ユーザーに対して永続的な一意な識別子を提供します。NameIDの値が変更されることなく、サービス間で一貫性を保つため、特にSSOでよく使用されます

### 3. `urn:oasis:names:tc:SAML:2.0:nameid-format:transient`

* 説明：セッション単位で一時的な識別子を提供します。通常、ログインセッションが終了すると識別子も無効になるため、セッションベースでの認証に利用されます

### 4. `urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified`

* 説明：NameIDの形式が特に指定されていない場合に使用されます。多くのプロバイダーがこの形式を使用し、NameIDの具体的な形式はIdP側で決定されます

## NameIDの例
以下は、SAML Assertion内で使用されるNameIDの例です。Formatを指定することで、SPはNameIDの形式を正しく解釈することができます。

### 1. メールアドレス形式の場合
```xml
<Subject>
    <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">user@example.com</NameID>
</Subject>
```
この例では、NameIDがメールアドレス形式で指定されており、ユーザーの識別子として「<foo>user</foo>@example.com」が使用されています。

### 2. 永続的な識別子の場合
```xml
<Subject>
    <NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">userID12345</NameID>
</Subject>
```

こちらでは、NameIDが永続的な識別子として設定されています。これにより、ユーザーが異なるセッションやサービスにログインしても、同じIDが使用されます。

## NameIDを使って認証してみよう
例えば、企業のイントラネットで複数のアプリケーションにSSOを実装する場合、NameIDを使用してユーザーを一意に識別します。これにより、ユーザーは1回のログインで複数のサービスを利用でき、各サービスがユーザーを正しく認識することができます。

ここでは、IdPの設定でNameIDには社員番号「12345」が設定されているとします。

```xml
<Subject>
    <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:persistent">12345</NameID>
</Subject>
```

これで、SPは「12345」を識別子として認識します。

:::note info
**社員番号「12345」のユーザーがSPに存在しているので、「SPへのログインを許可する」ことができました！！！**
:::

↓イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/923ff1e9-5422-c475-2451-563e908d223a.png)

# AttributeStatementの詳細とその役割
### AttributeStatementとは？
SAML Assertion内の`<AttributeStatement>`は、ユーザーの属性情報を提供する部分で、任意の情報を含むことができます。これは、ユーザーがどのような役職に就いているか、どの部署に所属しているか、アクセス権限がどうなっているかなど、システム内でのユーザーの状態や役割に関する情報です。

## AttributeStatementの役割
AttributeStatementは、主に以下の目的で使用されます：

### 1. ユーザー属性の提供：
ユーザーがどの部署に所属しているか、役職が何か、あるいはどのグループに所属しているかなどの追加情報を提供するために使用されます。これにより、SPはユーザーに対して適切なサービスやリソースを提供できるようになります。

### 2. 柔軟なアクセス制御：
AttributeStatementに含まれる属性情報をもとに、SP側でアクセス制御を動的に変更することができます。例えば、役職に基づいて特定のリソースへのアクセスを許可または制限したり、部署ごとに異なるサービスへアクセスできるように設定できます。

### 3. ユーザー情報の一貫性：
複数のサービスに対して一貫したユーザー情報を提供できるため、SSOを通じて統一されたユーザー認証と属性の提供が可能となります。これにより、システム間でのデータ整合性が保たれ、セキュリティが向上します。


## AttributeStatementに含まれる情報の具体例
`<AttributeStatement>`内には、さまざまなユーザー情報が含まれる可能性があります。これらの情報は、SP側で認証後に使用され、ユーザーの権限管理やアクセス制御に役立ちます。
以下は、一般的なAttributeStatementの例です。
`<AttributeValue>`タグで囲まれている情報が実際にIdPで保持している情報です。

### 例
* email：ユーザーのメールアドレス
```xml
<Attribute Name="Email">
    <AttributeValue>user@example.com</AttributeValue>
</Attribute>
```

* displayName：表示名（氏名）
```xml
<Attribute Name="displayName">
    <AttributeValue>John Doe</AttributeValue>
</Attribute>
```

* employeeNumber: 社員番号
```xml
<Attribute Name="employeeNumber">
    <AttributeValue>12345</AttributeValue>
</Attribute>
```

* department: 所属部署
```xml
<Attribute Name="department">
    <AttributeValue>IT</AttributeValue>
</Attribute>
```

* title: 役職
```xml
<Attribute Name="title">
    <AttributeValue>Manager</AttributeValue>
</Attribute>
```


## AttributeStatementを使って認証してみよう
### メールアドレスを使った認証
NameIDにはIdPのユーザー情報として社員番号が設定されているとします。ただ、SPはメールアドレスをユーザーIDとして設定しており、このユーザーID（メールアドレス）で認証したい場合、NameIDではなく`<Attribute Name = "Email">`の値を参照するようにSP側で設定します。
```xml
<Attribute Name="Email">
  <AttributeValue>TaroTanaka@example.com</AttributeValue>
</Attribute>
```
:::note warn
IdPでもSAML Responseに`"Email"`というAttribute Statementを付与する設定が必要です。
:::

この状態なら、SPは「<foo>TaroTanaka</foo>@example.com」を識別子として認識します。

ただし今回は…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/7c734a87-3818-41b8-6a86-1da52f81600e.png)

:::note alert
SPには「12345」というユーザー情報しかないため「SPへのログインを許可する」ことができませんでした…
:::

**解決策として、以下のいずれかを実施しなければいけません。**
１．参照するAttribute Statementを`"userID"`に設定する
２．SPのユーザー情報に「<foo>TaroTanaka</foo>@example.com」を登録する

### 仮に１を実施した場合
`<Attribute Name = "Email">`ではなく、`<Attribute Name = "useID">`の値を参照するようにSP側で設定します。
```xml
<Attribute Name="userID">
  <AttributeValue>12345</AttributeValue>
</Attribute>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/ea6763c9-1151-0af9-e55d-6a9bf9a80267.png)

:::note info
**SPの設定で、Attribute Statementの参照先をログインしたいユーザー情報が含まれているものに変更することで、「SPへのログインを許可する」ことができました！！！**
:::

### 仮に２を実施した場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/dca73ced-3b86-1fd7-e009-8697c9901afd.png)

:::note info
**ログイン可能なユーザー情報として「<foo>TaroTanaka</foo>@example.com」を設定（作成など）したことにより、「SPへのログインを許可する」ことができました！！！**
:::

### （番外編）役職に基づくアクセス制御
例えば、ある企業内のWebアプリケーションでは、管理者と一般社員でアクセスできるリソースが異なるとします。AttributeStatement内にrole属性を持たせ、その値が「Admin」の場合には管理者向けのリソースにアクセスでき、一般社員の場合には制限されたアクセス権限を付与することができます。

```xml
<Attribute Name="role">
  <AttributeValue>Admin</AttributeValue>
</Attribute>
```
SP側では、roleが「Admin」であれば特定の管理機能を表示し、それ以外の役職の場合には通常のアクセス権限のみを付与します。

みたいなこともできます。


# （応用編）IdPおよびSPによる認証情報の操作
IdPやSPは、SAML Responseに含まれる情報を必要に応じて操作する機能を持ってる場合がほとんどです。
以下では、IdPが正規表現やカスタムルールを使って認証情報を変更する実例を紹介します。
以下の状況で考えてみましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/b181dc4e-1d9a-3f50-a5a5-96b192b82827.png)


## メールアドレスのドメイン部分の削除してみよう
例えばAzure Entra IDは、Attribute Mapping機能を使用して、SAML Assertion内のAttribute Statementを動的に生成したり変更したりできます。これにより、Attribute Statementの値を加工してSPに渡すことが可能です。

:::note alert
現状のままだと、下記図の通り、SPにログインできません。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/384c6d38-beb4-5ab3-e40e-a93f082811ae.png)

:::note info
そこで、Attribute Statementの値を「メールアドレスのドメイン部分（@以下）を削除する」設定を入れた状態で、SSOしてみましょう！
:::

```
IdP: TaroTanaka@example.com
SP : TaroTanaka
```
設定例（正規表現を利用）：

```
Transformation: Replace
Input Pattern: @.*
Replacement: (空白)
```

これで実際のAttribute Statementは以下のようになります

```xml
<Attribute Name="Email">
  <AttributeValue>TaroTanaka</AttributeValue>
</Attribute>
```

こうすることで、SPは「TaroTanaka」を識別子として認識します。


:::note info
**ログイン可能なユーザー情報として「TaroTanaka」が設定されているので、「SPへのログインを許可する」ことができますね！！**
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620187/571024cd-2f78-e2c1-d261-64a64c68c091.png)


# まとめ
SAMLにおける「NameID」と「Attribute Statement」は、SSOにおいてユーザーを適切に識別し、サービスへのアクセスを制御するための重要な構成要素です。

* NameID はユーザーを一意に特定するための基本情報を提供し、シンプルな認証環境でのSSOに最適です。例えば、社員番号やメールアドレスを使用して、異なるサービス間で一貫性のあるユーザー体験を実現できます。

* 一方、Attribute Statement は追加のユーザー属性を提供することで、より高度なアクセス制御を可能にします。役職や所属部署などの情報に基づいて、サービスごとに柔軟なアクセス権限を設定することができるため、複雑なセキュリティ要件を持つ環境で特に有用です。

さらに、IdPやSPが正規表現やカスタムルールを活用することで、SAML Assertion内のユーザー情報を動的に加工し、異なる命名規則や認証要件にスムーズに対応できます。特に、Azure Entra IDのような高度なIdPでは、Attribute Mapping機能を用いることで、様々な認証シナリオをサポートします。

これらの技術を効果的に活用することで、組織はユーザーにとって使いやすく、管理者にとって安全かつ効率的なシングルサインオン（SSO）ソリューションを構築することができます。今後のSSO導入や運用で迷った際には、ぜひこの記事を参考にしてください。