Azure AD B2CとShibbolethをカスタムポリシーでSAML認証連携させる


## はじめに

AzureのAzure AD B2Cというサービスを使うと、外部のIdPを使用してユーザがサインアップしたりサインインできるそうです。
https://docs.microsoft.com/ja-jp/azure/active-directory-b2c/

昨今コンシューマ向けサイトでもTwitterやFacebookのようなSNSアカウントでログインできるようになっていますが、そういった設定が比較的簡単にできるよう、プリセットで機能をもったものがこのAzure AD B2Cになります。（例えばFacebookとの連携　https://docs.microsoft.com/ja-jp/azure/active-directory-b2c/identity-provider-facebook）

現状でもプリセットである程度のSNSアカウントやAmazon,Googleアカウントとの連携は使えるのですが、自分で設定ファイル **（ごりごりのxmlファイル）** を書くとOpenID Connect対応のIdPはもちろん、SAMLを話せるIdPともわりかし自由に連携できるということで、

SAML IdPと言えば**Shibboleth**という発想の元この二つを認証連携させてみましたので、簡単にやり方をまとめてみます。 

## 前提条件

* Shibbolethはver.3.4で動作確認済み

* Shibboleth IdPが利用できる状態であること

* Azure AD B2Cがカスタムポリシーを利用できる状態であること
  ※下記手順を一通り進められていれば大丈夫です。
https://docs.microsoft.com/ja-jp/azure/active-directory-b2c/custom-policy-get-started?tabs=applications

## ゴールイメージ

やりたいことは、Azure AD B2C→Shibbolethへ認証連携させ、Shibbolethから取得した属性をもって、Azure AD B2C側でその後のサインインやサインアップの処理を実施できるようにします。

ですので、

* Azure AD B2CがSAML SP
* ShibbolethがSAML IdP

となるよう設定をするイメージです。

## 手順

### 1.Shibboleth側の設定

Shibbolethには、Azure AD B2CをIdPとして認識してもらわなければならないので、その設定を入れてやります。  

**1.Azure AD B2CのIdPメタデータ作成**

下記コマンドでメタデータファイルを作成します。

vi  /opt/shibboleth-idp/metadata/b2c-metadata.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<EntityDescriptor entityID="https://[Azure AD B2Cテナント名].b2clogin.com/[Azure AD B2Cテナント名].onmicrosoft.com/B2C_1A_TrustFrameworkBase"
            xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
            xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
        <AssertionConsumerService index="1" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
            Location="https://[Azure AD B2Cテナント名].b2clogin.com/[Azure AD B2Cテナント名].onmicrosoft.com/B2C_1A_TrustFrameworkBase/samlp/sso/assertionconsumer" />
        <KeyDescriptor>
            <ds:KeyInfo>
                    <ds:X509Data>
                      <ds:X509Certificate>
[後ほどSAML Tracerで証明書を取得し設定します。]
                      </ds:X509Certificate>
                    </ds:X509Data>
            </ds:KeyInfo>
        </KeyDescriptor>
    </SPSSODescriptor>
</EntityDescriptor>
```



**2.Azure AD B2CのIdPメタデータ登録**

作成したAADB2CのメタデータをShibbolethのmetadata-providerに登録してやります。
下記コマンドでB2Cメタデータの情報を追記します。

vi  /opt/shibboleth-idp-b2c/conf/metadata-providers.xml

```xml
<MetadataProvider id="b2c" xsi:type="FilesystemMetadataProvider" metadataFile="/opt/shibboleth-idp-b2c/metadata/b2c-metadata.xml"/>
```



**3.attribute-filter.xmlの編集**

Shibbolethの属性設定関連ファイルを編集します。

設定する属性は各自のSP・IdPの設定に合わせてください。

vi  /opt/shibboleth-idp-b2c/conf/attribute-filter.xml

```xml
<!-- for b2c -->
<AttributeFilterPolicy id="b2c">
  <PolicyRequirementRule xsi:type="Requester" value="https://[Azure AD B2Cテナント名].b2clogin.com/[Azure AD B2Cテナント名].onmicrosoft.com/B2C_1A_TrustFrameworkBase" />
  <!--例としてuidを設定しています。-->
  <AttributeRule attributeID="uid">
    <PermitValueRule xsi:type="ANY" />
  </AttributeRule>
</AttributeFilterPolicy>

```



これでShibboleth側の設定は一旦終了です。

### 2.Azure AD B2C側の設定

続いてAzure AD B2CにShibbolethをIdPとして認識する設定をします。

**1.証明書の作成・登録**

その前段階として、SAML認証時にB2C側で使用する証明書を作成します。Powershellで下記コマンドを入力します。

```powershell
$tenantName = "[Azure AD B2Cテナント名].onmicrosoft.com"
$pwdText = "[任意のパスワード]"

$Cert = New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My -DnsName "SamlIdp.$tenantName" -Subject "B2C SAML Signing Cert" -HashAlgorithm SHA256 -KeySpec Signature -KeyLength 2048

$pwd = ConvertTo-SecureString -String $pwdText -Force -AsPlainText

Export-PfxCertificate -Cert $Cert -FilePath C:\temp\B2CSigningCert.pfx -Password $pwd
```

作成できた「B2CSigningCert.pfx」をAADB2Cに設定します。Azure PortalのAzure AD B2C設定画面から
[Identity Experience Framework]→[ポリシーキー]→[追加]を選択して下記内容を入力します。


* オプション：アップロード
* 名前：B2CSigningCert ※任意の名前
* ファイルのアップロード：B2CSigningCert.pfx
* パスワード：証明書作成時に入力したパスワード


最後に[作成]を押してエラーなく作成できましたら登録完了です。


**2.ポリシーファイルの作成**

では、本題のAADB2CポリシーファイルにShibbolethの設定を加えていきます。
※細かなフロー設定部分は割愛させていただき、Shibbolethに必要な部分のみ記載します。

まずはClaimProviderの設定をします。<ClaimProviders>ブロックの中に下記を追記します。

```xml
    <ClaimsProvider>
      <Domain>Shibboleth</Domain>
      <DisplayName>Shibboleth</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="Shibboleth-SAML2">
          <DisplayName>Shibboleth</DisplayName>
          <Description>Shibbolethでログイン</Description>
          <Protocol Name="SAML2"/>
          <Metadata>
            <Item Key="RequestsSigned">false</Item>
            <Item Key="WantsEncryptedAssertions">false</Item>
            <Item Key="WantsSignedAssertions">false</Item>
            <Item Key="PartnerEntity">[ShibbolethのIdPメタデータ設置URL]</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="SamlAssertionSigning" StorageReferenceId="B2C_1A_B2CSigningCert"/>
            <Key Id="SamlMessageSigning" StorageReferenceId="B2C_1A_B2CSigningCert"/>
            <Key Id="SamlAssertionDecryption" StorageReferenceId="B2C_1A_B2CSigningCert"/>
          </CryptographicKeys>
          <OutputClaims>
            <!--属性設定は各自環境に合わせて変更ください-->
            <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="uid" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin"/>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

```

これでUserJourny内のClaimExchangeでShibbolethを使用できるようになりました。

最後に後で設定するとしていたAADB2CのSPメタデータの証明書部分を編集します。



### 3.証明書内容の追記

一度AADB2CからShibbolethを呼び出すフローが設定できましたら、SAML Tracerなどを使用して認証フローをトレースします。

B2C→ShibbolethへのAuth Requestの中に証明書情報があるので、そちらをコピーしてメタデータファイルに設定します。

再度メタデータファイルを編集します。

vi  /$IDP/metadata/b2c-metadata.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!--省略-->
        <KeyDescriptor>
            <ds:KeyInfo>
                    <ds:X509Data>
                      <ds:X509Certificate>
[取得した証明書データを貼り付け]
                      </ds:X509Certificate>
                    </ds:X509Data>
            </ds:KeyInfo>
        </KeyDescriptor>
    </SPSSODescriptor>
</EntityDescriptor>

```

これで接続部分は完了です。属性設定など環境によって異なる部分はトレースしながら調整頂ければと思います。