1. 記事一覧 >
  2. ブログ記事
category logo

Nginx&SimpleSAMLphpでSAMLのSPを構築 Azure ADで認証

(更新) (公開)

はじめに

この記事に「SSO とは」「SAML とは」「SimpleSAMLphp とは」等々、用語の説明はありません。

Ubuntu 22.04.3 LTS に Nginx 1.18.0 & PHP & SimpleSAMLphp 2.1.1 をインストールして、SAML による SSO(シングルサインオン/Single Sign On)環境を作成しました。
SimpleSAMLphp 2.1.1 は、Service Provider (SP) または、Identity Provider (IdP) として機能しますが、今回は、Service Provider (SP) として使います。
IdP は、Azure AD(Azure Active Directory/Microsoft Entra ID)を利用します。


認証対象の Web アプリケーション環境構築から SimpleSAMLphp デプロイ、Azure AD で Web アプリケーション認証まで全手順を紹介します。

Azure AD(Azure Active Directory)は、Microsoft Entra ID に名称が変わりましたが、この記事では、Azure AD 表記のままでいきます。


Nginx&SimpleSAMLphpでSAMLのSPを構築 Azure ADで認証 構成図


この記事は、2023 年 12 月現在の公式ドキュメント SimpleSAMLphp Installation and Configuration の手順を元に、書かれていない内容まで補完したものです。

時期違いで、手順が異なるかもしれません。ご了承ください。

また、本記事情報の設定不足、誤りにより何らかの問題が生じても、一切責任を負いません。


Web アプリケーション環境構築

Nginx と PHP で認証対象の Web アプリケーション環境を作成します。
アプリケーションと言っても、PHP の関数 phpinfo() を実行して、内部パラメータ等を表示するだけのアプリケーションです。


今回は、
Nginx 1.18.0
PHP 8.3.0
をインストールします。

今回、Web アプリケーションサーバーの URI は、

https://webapps-php.example.com/info.php とします。

SimpleSAMLphp 2.x.x は、PHP version >= 8.0.0 となっていますので、この記事執筆での最新 PHP 8.3.0 をインストールしています。

# apt update
# add-apt-repository ppa:ondrej/php -y
# apt update
# apt -y install php8.3 php8.3-gd php8.3-mbstring php8.3-common php8.3-curl
# php -v
PHP 8.3.0 (cli) (built: Nov 24 2023 08:50:08) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.0, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.0, Copyright (c), by Zend Technologies
# apt list --installed | grep apache2

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

apache2-bin/jammy-updates,jammy-security,now 2.4.52-1ubuntu4.7 amd64 [インストール済み、自動]
apache2-data/jammy-updates,jammy-updates,jammy-security,jammy-security,now 2.4.52-1ubuntu4.7 all [インストール済み、自動]
apache2-utils/jammy-updates,jammy-security,now 2.4.52-1ubuntu4.7 amd64 [インストール済み、自動]
apache2/jammy-updates,jammy-security,now 2.4.52-1ubuntu4.7 amd64 [インストール済み、自動]
libapache2-mod-php8.3/jammy,now 8.3.0-1+ubuntu22.04.1+deb.sury.org+1 amd64 [インストール済み、自動]
# apt -y remove apache2-*
# apt install -y php-fpm
# vi /etc/php/8.3/fpm/pool.d/www.conf
listen = /run/php/php8.3-fpm.sock

listen = /run/php/php8.3-fpm.sockは、最初から設定されています。確認のみです。


Nginx をインストールします。

# apt install nginx -y
# nginx -v
nginx version: nginx/1.18.0 (Ubuntu)
# vi /etc/nginx/fastcgi_params
/etc/nginx/fastcgi_params
fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;

fastcgi_param SCRIPT_FILENAME は必要です。

無い場合、スクリプトの位置を特定できなくて、エラーになります。

FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 192.168.11.5, server: webapps-php.example.com, request: "GET /info.php HTTP/1.1",

upstream: "fastcgi://unix:/run/php/php8.3-fpm.sock:",

host: "webapps-php.example.com"


PHP の Web アプリケーションを作成します。

# mkdir -p /opt/webapps/php
# chown -R www-data: /opt/webapps
# mkdir -p /var/log/webapps/php
# vi /opt/webapps/php/info.php
/opt/webapps/php/info.php
<?php
phpinfo();

自己署名証明書を作成して、/etc/pki/tls 配下に配置します。

# openssl genrsa -out ca.key 2048
# openssl req -new -key ca.key -out ca.csr
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Aichi
Locality Name (eg, city) []:Toyota
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:webapps-php.example.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
# echo "subjectAltName=DNS:*.example.com,IP:192.168.12.200" > san.txt
# openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt -extfile san.txt
Signature ok
subject=C = JP, ST = Aichi, L = Toyota, O = Default Company Ltd, CN = webapps-php.example.com
Getting Private key
# mkdir -p /etc/pki/tls/certs
# mkdir /etc/pki/tls/private
# mv ca.crt /etc/pki/tls/certs/webapps-php.crt
# mv ca.key /etc/pki/tls/private/webapps-php.key
# mv ca.csr /etc/pki/tls/private/webapps-php.csr

Nginx の設定を行います。

# vi /etc/nginx/conf.d/webapps-info.conf
/etc/nginx/conf.d/webapps-info.conf
server  # サーバーブロックの開始
{
  listen 443 ssl; # サーバーが待ち受けるポート番号
  ssl_certificate /etc/pki/tls/certs/webapps-php.crt; # TLS証明書
  ssl_certificate_key /etc/pki/tls/private/webapps-php.key; # TLS秘密鍵
  server_name webapps-php.example.com;  # サーバーの名前
  access_log /var/log/webapps/php/access.log;  # アクセスログのパス
  error_log /var/log/webapps/php/error.log;  # エラーログのパス

  root /opt/webapps/php;  # サーバーのルートディレクトリ

  location /  # ルートディレクトリに対する設定
  {
    index index.html index.htm index.php;  # デフォルトで使用するインデックスファイル
  }

  location ~ [^/]\.php(/|$)  # .phpで終わるリクエストに対する設定
  {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;  # パス情報を分割
    if (!-f $document_root$fastcgi_script_name)  # スクリプトファイルが存在しない場合
    {
      return 404;  # 404エラーを返す
    }

    client_max_body_size 100m;  # クライアントからの最大ボディサイズ

    # Mitigate https://httpoxy.org/ vulnerabilities
    fastcgi_param HTTP_PROXY "";  # HTTP_PROXYを空に設定してhttpoxy脆弱性を緩和

    # fastcgi_pass 127.0.0.1:9000;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;  # FastCGIサーバーへのパス
    fastcgi_index index.php;  # デフォルトのFastCGIスクリプト

    # include the fastcgi_param setting
    include fastcgi_params;  # FastCGIパラメータの設定を含む

    # SCRIPT_FILENAME parameter is used for PHP FPM determining
    #  the script name. If it is not set in fastcgi_params file,
    # i.e. /etc/nginx/fastcgi_params or in the parent contexts,
    # please comment off following line:
    # fastcgi_param  SCRIPT_FILENAME   $document_root$fastcgi_script_name;  # スクリプト名を決定するためのパラメータ
  }
}

# vi /etc/php/8.3/fpm/php.ini
date.timezone = Asia/Tokyo
# 新規設定

display_errors = On
display_startup_errors = On
# 確認(最初から設定されている。)
# vi /etc/hosts
192.168.12.200 webapps-php.example.com

今回、Web アプリケーションサーバーの IP アドレスは、192.168.12.200 とします。

# systemctl restart nginx
# systemctl restart php8.3-fpm

この時点で、 https://webapps-php.example.com/info.php
にアクセスすると、phpinfo() の画面が確認できます。
ただし、当たり前ですが、まだ SAML に関して何もしていませんので、認証はかかりません。

phpinfo()の画面


とりあえず、ヨシ!


SimpleSAMLphp Web コンソール環境作成

php8.3-dom、php8.3-xml を最低限必要とするため、インストールします。

SimpleSAMLphp Documentation(英語)では、以下の記述になっているため、この時点で、足りない分をインストールしています。

次の PHP 拡張機能のサポート:

常に必須 : date , dom , fileinfo , filter , hash , json , libxml , mbstring , openssl , pcre , session , simplexml , sodium , SPL and zlib

なお、php8.3-xml は、simplexml のことです。

# apt install -y php8.3-dom php8.3-xml

https://github.com/simplesamlphp/simplesamlphp/releases/tag/v2.1.1
から
simplesamlphp-2.1.1-full.tar.gz
をダウンロード、展開し、/var/simplesamlphp に配置します。

simplesamlphp-2.1.1-full.tar.gzダウンロード


# tar xzf simplesamlphp-2.1.1-full.tar.gz
# mv simplesamlphp-2.1.1 /var/simplesamlphp

-full-full 無しの違いは、-full の方がいろいろモジュールが入っていてオンにすれば使えるよというもののようです。(例:LDAP 連携)

今回、実は、-full である必要はありません。

/var/simplesamlphp は任意ですが、ドキュメントの記述に合わせると、/var/simplesamlphp です。


SimpleSAMLphp Web コンソール用の証明書、秘密鍵を作成します。


今回、SimpleSAMLphp Web コンソールの URL は、
https://ssp2.example.com/simplesaml/ とします。

URL は任意です。/simplesaml というパスもドキュメントの記述に合わせただけで、この限りではありません。

https://ssp2.example.com/ は、404 Not Found になります。

ssp2 は、SimpleSAMLphp 2.x.x を省略して ssp2 にしました。海外のサイトで SimpleSAMLphp 1.x.x のことを SSP, SimpleSAMLphp 2.x.x のことを SSP2 と呼んでいる場合がありました。

# openssl genrsa -out ca.key 2048
# openssl req -new -key ca.key -out ca.csr
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Aichi
Locality Name (eg, city) []:Toyota
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:ssp2.example.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
# echo "subjectAltName=DNS:*.example.com,IP:192.168.12.200" > san.txt
# openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt -extfile san.txt
Signature ok
subject=C = JP, ST = Aichi, L = Toyota, O = Default Company Ltd, CN = ssp2.example.com
Getting Private key
# mv ca.crt /etc/pki/tls/certs/ssp2.example.com.crt
# mv ca.key /etc/pki/tls/private/ssp2.example.com.key
# mv ca.csr /etc/pki/tls/private/ssp2.example.com.csr
# vi /etc/nginx/conf.d/simplesaml.conf
/etc/nginx/conf.d/simplesaml.conf
server {
    listen 443 ssl;
    server_name ssp2.example.com;

    ssl_certificate        /etc/pki/tls/certs/ssp2.example.com.crt;
    ssl_certificate_key    /etc/pki/tls/private/ssp2.example.com.key;
    ssl_protocols          TLSv1.3 TLSv1.2;
    ssl_ciphers            EECDH+AESGCM:EDH+AESGCM;

    location ^~ /simplesaml {
        index index.php;
        alias /var/simplesamlphp/public;

        location ~^(?<prefix>/simplesaml)(?<phpfile>.+?\.php)(?<pathinfo>/.*)?$ {
            include          fastcgi_params;
            # fastcgi_pass     $fastcgi_pass;
            fastcgi_pass     unix:/run/php/php8.3-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$phpfile;

            # Must be prepended with the baseurlpath
            fastcgi_param SCRIPT_NAME /simplesaml$phpfile;

            fastcgi_param PATH_INFO $pathinfo if_not_empty;
        }
    }
}

ドキュメントに書かれていませんでしたが、

location ^~ /simplesaml {

index index.php;

index index.php;

は重要です。これが無い場合、/simplesaml/admin/(ファイル名無し)にアクセスで、/var/simplesamlphp/admin/index.php が読み込まれず、404 Not found になります。


# chown -R www-data: /var/simplesamlphp
# vi /etc/hosts
192.168.12.200	ssp2.example.com
# systemctl restart nginx
# systemctl restart php8.3-fpm

.php.dist.php にして有効にします。
.php.dist.php は設定ファイル .conf 的な位置付けで、デフォルトの設定が入っています。
とりあえず、ドキュメント記載の手順だけ実施します。

# cd /var/simplesamlphp
# cp config/config.php.dist config/config.php
# cp config/authsources.php.dist config/authsources.php
# cp metadata/saml20-idp-hosted.php.dist metadata/saml20-idp-hosted.php
# cp metadata/saml20-idp-remote.php.dist metadata/saml20-idp-remote.php
# cp metadata/saml20-sp-remote.php.dist metadata/saml20-sp-remote.php

いろいろ設定がありますが、今回は、必要最低限の設定しかしません。以降、設定の書き換えについても同様です。


https://ssp2.example.com/simplesaml/ へアクセスして、SimpleSAMLphp のコンソール画面が表示されれば、成功です。

SimpleSAMLphpのコンソール画面

この画面は、設定画面ではないため、何もできません。

この後、設定画面に入るための初期設定を行います。


SimpleSAMLphp Web コンソール初期設定

管理者パスワードとsecretsaltとタイムゾーンを設定します。

# apt install composer -y
# composer install
# openssl rand -base64 32
RCN2jfGolAsfOb1J4UXQrbrwevYIyz/O/o9sJWRzxTc=
# vi /var/simplesamlphp/config/config.php
/var/simplesamlphp/config/config.php
//'secretsalt' => 'defaultsecretsalt',
// ↓ 変更
'secretsalt' => 'RCN2jfGolAsfOb1J4UXQrbrwevYIyz/O/o9sJWRzxTc=',

//'auth.adminpassword' => '123',
// ↓ 変更
'auth.adminpassword' => 'admin',

//'timezone' => null,
// ↓ 変更
'timezone' => 'Asia/Tokyo',

// 'technicalcontact_name' => 'Administrator',
// 'technicalcontact_email' => 'na@example.org',
// ↓ 変更
'technicalcontact_name' => 'Administrator',
'technicalcontact_email' => 'admin@ssp2.example.com',

https://ssp2.example.com/simplesaml/admin にアクセスして動作確認します。
とりあえず、設定したパスワード admin で管理者でログインできることを確認します。

管理者名は、admin です。

管理者ログイン


管理者ログイン成功後


管理者ログイン ヨシ!


SimpleSAMLphp SP 設定

設定ファイル config/authsources.php に SP の設定をします。
SP(SAML 認証を使うアプリ)は複数設定できますが、今回は一つですし、一番最初になるので、 default-sp のところに設定します。

# cd /var/simplesamlphp
# vi config/authsources.php
/var/simplesamlphp/config/authsources.php
//    'default-sp' => [
//        'saml:SP',
//        'entityID' => 'https://myapp.example.org/',
// ↓ 変更
    'default-sp' => [
        'saml:SP',
        'entityID' => 'https://webapps-php.example.com',

saml:SP のところは、文字通り、SAML の SP の設定であることを意味するため、このままにします。

entityID =アプリの URL ではありません。IdP と連携するための識別子を任意に決めればよいですが、通常は、アプリケーションの URL のため、https://webapps-php.example.com とします。


SP の証明書を作成し、設定します。

# cd /var/simplesamlphp
# cd cert
# openssl req -newkey rsa:3072 -new -x509 -days 3652 -nodes -out saml.crt -keyout saml.pem
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Aichi
Locality Name (eg, city) []:Toyota
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:ssp2.example.com
Email Address []:
# cd ../
# vi config/authsources.php
/var/simplesamlphp/config/authsources.php
//        'entityID' => 'https://webapps-php.example.com',
// ↓ 変更
        'entityID' => 'https://webapps-php.example.com',
        'privatekey' => 'saml.pem', // 追記
        'certificate' => 'saml.crt',// 追記

SP から IdP へ送信される SAML リクエストなどに付けられる署名の検証に使われます。

証明書が無いまま進めると、以下のエラーになりました。

未処理例外が投げられました。

SimpleSAML\Error\Error: UNHANDLEDEXCEPTION

Backtrace:

2 src/SimpleSAML/Error/ExceptionHandler.php:32 (SimpleSAML\Error\ExceptionHandler::customExceptionHandler)

1 vendor/symfony/error-handler/ErrorHandler.php:541 (Symfony\Component\ErrorHandler\ErrorHandler::handleException)

0 [builtin] (N/A)

Caused by: Exception: Unable to validate Signature

Backtrace:

10 vendor/simplesamlphp/saml2/src/SAML2/Utils.php:196 (SAML2\Utils::validateSignature)

9 vendor/simplesamlphp/saml2/src/SAML2/Assertion.php:674 (SAML2\Assertion::validate)

8 modules/saml/src/Message.php:168 (SimpleSAML\Module\saml\Message::checkSign)

7 modules/saml/src/Message.php:646 (SimpleSAML\Module\saml\Message::processAssertion)

6 modules/saml/src/Message.php:613 (SimpleSAML\Module\saml\Message::processResponse)

5 modules/saml/src/Controller/ServiceProvider.php:310 (SimpleSAML\Module\saml\Controller\ServiceProvider::assertionConsumerService)

4 vendor/symfony/http-kernel/HttpKernel.php:163 (Symfony\Component\HttpKernel\HttpKernel::handleRaw)

3 vendor/symfony/http-kernel/HttpKernel.php:75 (Symfony\Component\HttpKernel\HttpKernel::handle)

2 vendor/symfony/http-kernel/Kernel.php:202 (Symfony\Component\HttpKernel\Kernel::handle)

1 src/SimpleSAML/Module.php:234 (SimpleSAML\Module::process)

0 public/module.php:17 (N/A)


SP のメタデータ(XML)取得

SP のメタデータ(XML ファイル)を取得します。取得したメタデータは、次のステップで、IdP(Azure AD)に登録します。


https://ssp2.example.com/simplesaml/admin/ にアクセスして、
連携 タブをクリックします。

連携タブクリック


You can get the metadata XML on a dedicated URL:
のところのダウンロードアイコンをクリックして、ダウンロードします。

ダウンロードアイコンをクリック


default-sp.xmlダウンロード


メタデータ(例)
<?xml version="1.0" encoding="utf-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="https://webapps-php.example.com">
  <md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <md:KeyDescriptor use="signing">
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:X509Data>
          <ds:X509Certificate>MIIEtzCCAx+gAwIBAgIUNOok9kycnt+3+p45fjn8omQot7UwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBUFpY2hpMQ8wDQYDVQQHDAZUb3lvdGExITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAwwPaWRwLmV4YW1wbGUuY29tMB4XDTIzMTIwNjA1NTQwNFoXDTMzMTIwNTA1NTQwNFowazELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBUFpY2hpMQ8wDQYDVQQHDAZUb3lvdGExITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAwwPaWRwLmV4YW1wbGUuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0XyeOdgaI/OmCiXa2cIrCOr6oB5GXH6X1DctxVZewIvf6zbjJzbl+G9EEUCrm8uCww0Va8JLpyTG7b3ZgjRrpfEmIgj1Jm6Zxpnsv+LuQozC08vcASENn4vBEmm7B/jTxXaqZm8A1/N8VbIvGuUtVrxTkii02ez6FxSlJAWxDgB4WYg5rVAu2P+rkPwvr70EvcSh5BinDuX5m04oAPrtTZ/hBt3AAGYAqK8+VVAF8G7qqApjz690ntNCwAZLoDZ1lsO3tEaOXFmDqZwf9GGqy+X0UHazH200/xpGSiQm029qAuIQe7VB+l08RQj/3sHAPYlBMu8q5bQmK1b/xiYXF+/42l8aeyUQChBofDgfqMUHYhP4ozmajMaCnI9nbeKbCahFnq3pvEKyjhbu6ziCV5QixBcn+c5biYgLW++gCQcB6/4gXFEMxHDOtm4lg0UN4r34npcVoIKknRQN0Ht1rl+jGZxB3L9JRi1CCa8APXsQwUFVvxhT/zWqGvDEqWF/AgMBAAGjUzBRMB0GA1UdDgQWBBSSebFYBsuEZcVdeVDXcGXx7+WQrjAfBgNVHSMEGDAWgBSSebFYBsuEZcVdeVDXcGXx7+WQrjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBgQA6FmMPNKm381GJfs/HFI584N7FA1R2M4RqXmKgSkSJlPsDky2H81V7wllKI8JA4ULnOpV7zoIjgrlaHW5lg970UkxBe2vx1Zmb295mT5bFcCVXadNNgmSO7MRJqy4DzzQAxr51xxyCYLwpEoPjq3JQTjfXj+wE/LBKO25hIkAVPRBNK2rXYFV+eRG83005UxDx2k9qhMnHXx08DuePS+WShNLfEFIg/xToiOvbkgyPsyyxI2xqgxA4VNZ0ICj7azi5wmEyAsPdOM74S8tY5IQP8wIG3JhOgowTptU3JoiPCuqWikZR8O2UELCFHnLBU/9eEuZ3XxICUqe3Vf1Tringp7zl3dbkytllPVFGvNwdCp0Jf5cY2Y2x75w/o1L/6HIFelItpxAlio58gf4Q0GgaDSANUVFcQ7sHjnq1LsSTZe76ombYfKpyOEy3dzMjb8AjcbOAxbE5zKubZIjd1rYoSyHy010v0d1jcyJKo5Du0pzKbmXL0KRrWznlsTRJYYc=</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:KeyDescriptor use="encryption">
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:X509Data>
          <ds:X509Certificate>MIIEtzCCAx+gAwIBAgIUNOok9kycnt+3+p45fjn8omQot7UwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBUFpY2hpMQ8wDQYDVQQHDAZUb3lvdGExITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAwwPaWRwLmV4YW1wbGUuY29tMB4XDTIzMTIwNjA1NTQwNFoXDTMzMTIwNTA1NTQwNFowazELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBUFpY2hpMQ8wDQYDVQQHDAZUb3lvdGExITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAwwPaWRwLmV4YW1wbGUuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0XyeOdgaI/OmCiXa2cIrCOr6oB5GXH6X1DctxVZewIvf6zbjJzbl+G9EEUCrm8uCww0Va8JLpyTG7b3ZgjRrpfEmIgj1Jm6Zxpnsv+LuQozC08vcASENn4vBEmm7B/jTxXaqZm8A1/N8VbIvGuUtVrxTkii02ez6FxSlJAWxDgB4WYg5rVAu2P+rkPwvr70EvcSh5BinDuX5m04oAPrtTZ/hBt3AAGYAqK8+VVAF8G7qqApjz690ntNCwAZLoDZ1lsO3tEaOXFmDqZwf9GGqy+X0UHazH200/xpGSiQm029qAuIQe7VB+l08RQj/3sHAPYlBMu8q5bQmK1b/xiYXF+/42l8aeyUQChBofDgfqMUHYhP4ozmajMaCnI9nbeKbCahFnq3pvEKyjhbu6ziCV5QixBcn+c5biYgLW++gCQcB6/4gXFEMxHDOtm4lg0UN4r34npcVoIKknRQN0Ht1rl+jGZxB3L9JRi1CCa8APXsQwUFVvxhT/zWqGvDEqWF/AgMBAAGjUzBRMB0GA1UdDgQWBBSSebFYBsuEZcVdeVDXcGXx7+WQrjAfBgNVHSMEGDAWgBSSebFYBsuEZcVdeVDXcGXx7+WQrjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBgQA6FmMPNKm381GJfs/HFI584N7FA1R2M4RqXmKgSkSJlPsDky2H81V7wllKI8JA4ULnOpV7zoIjgrlaHW5lg970UkxBe2vx1Zmb295mT5bFcCVXadNNgmSO7MRJqy4DzzQAxr51xxyCYLwpEoPjq3JQTjfXj+wE/LBKO25hIkAVPRBNK2rXYFV+eRG83005UxDx2k9qhMnHXx08DuePS+WShNLfEFIg/xToiOvbkgyPsyyxI2xqgxA4VNZ0ICj7azi5wmEyAsPdOM74S8tY5IQP8wIG3JhOgowTptU3JoiPCuqWikZR8O2UELCFHnLBU/9eEuZ3XxICUqe3Vf1Tringp7zl3dbkytllPVFGvNwdCp0Jf5cY2Y2x75w/o1L/6HIFelItpxAlio58gf4Q0GgaDSANUVFcQ7sHjnq1LsSTZe76ombYfKpyOEy3dzMjb8AjcbOAxbE5zKubZIjd1rYoSyHy010v0d1jcyJKo5Du0pzKbmXL0KRrWznlsTRJYYc=</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://ssp2.example.com/simplesaml/module.php/saml/sp/saml2-logout.php/default-sp"/>
    <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://ssp2.example.com/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" index="0"/>
    <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://ssp2.example.com/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" index="1"/>
  </md:SPSSODescriptor>
  <md:ContactPerson contactType="technical">
    <md:GivenName>Administrator</md:GivenName>
    <md:EmailAddress>mailto:admin@ssp2.example.com</md:EmailAddress>
  </md:ContactPerson>
</md:EntityDescriptor>

Azure AD エンタープライズアプリケーション作成

IdP(Azure AD)側の設定を行います。
Azure ポータルから、Microsoft Entra ID に移動して、エンタープライズ アプリケーション をクリックします。

Microsoft Entra ID


エンタープライズ アプリケーション


+新しいアプリケーション をクリックします。

+新しいアプリケーション


+独自のアプリケーション作成 をクリックします。

+独自のアプリケーション作成


お使いのアプリの名前は何ですか?
のところを SimpleSAMLphpIdP とします。
ギャラリーに見つからないその他のアプリケーションを統合します (ギャラリー以外) にチェックが入った状態とし、作成 をクリックします。

アプリの名前SimpleSAMLphpIdP

アプリの名前は任意です。


シングル サインオンの設定 のところの 作業の開始 をクリックします。

シングル サインオンの設定


SAML をクリックします。

SAML


メタデータ ファイルをアップロードする をクリックして、SP のメタデータ(XML)をアップロードし、保存 をクリックします。

メタデータ ファイルをアップロードする


メタデータ ファイル参照→追加


基本的な SAML 構成


ユーザーとグループ をクリックし、+ユーザーまたはグループの追加 をクリックします。

+ユーザーまたはグループの追加


割り当ての追加 画面に切り替わり、選択されていません をクリックします。

選択されていません


SAML 認証を使うユーザー/グループを選択し、選択 をクリックします。
今回は、すべてのユーザー にします。

すべてのユーザー


割り当て をクリックします。

割り当て


割り当て完了後


IdP のメタデータ(XML)取得

IdP(Azure AD)のメタデータ(XML ファイル)を取得します。取得したメタデータは、次のステップで、SP(SimpleSAMLphp)に登録します。


シングル サインオン をクリックして、
フェデレーション メタデータ XML のところの ダウンロード をクリックします。 これにより、SimpleSAMLphpIdP.xml を入手します。

フェデレーション メタデータXMLダウンロード


SP に IdP のメタデータ(XML)登録

https://ssp2.example.com/simplesaml/module.php/admin/federation/metadata-converter
にアクセスして、SimpleSAMLphpIdP.xml を読み込み、パースします。

SimpleSAMLphpIdP.xml読み込み


SimpleSAMLphpIdP.xmlパース


パースした結果、以下のように $metadata['... が得られますので、コピーします。

パースした結果をコピー


コピーした PHP 形式のメタデータを saml20-idp-remote.php に設定します。

# cd /var/simplesamlphp
# vi metadata/saml20-idp-remote.php
/var/simplesamlphp/metadata/saml20-idp-remote.php
// メタデータ例
$metadata['https://sts.windows.net/0******2-f**7-4**c-9**4-1**********b/'] = [
    'entityid' => 'https://sts.windows.net/0******2-f**7-4**c-9**4-1**********b/',
    'contacts' => [],
    'metadata-set' => 'saml20-idp-remote',
    'SingleSignOnService' => [
        [
            'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
            'Location' => 'https://login.microsoftonline.com/0******2-f**7-4**c-9**4-1**********b/saml2',
        ],
        [
            'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
            'Location' => 'https://login.microsoftonline.com/0******2-f**7-4**c-9**4-1**********b/saml2',
        ],
    ],
    'SingleLogoutService' => [
        [
            'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
            'Location' => 'https://login.microsoftonline.com/0******2-f**7-4**c-9**4-1**********b/saml2',
        ],
    ],
    'ArtifactResolutionService' => [],
    'NameIDFormats' => [],
    'keys' => [
        [
            'encryption' => false,
            'signing' => true,
            'type' => 'X509Certificate',
            'X509Certificate' => 'MIIC8DC...(long string)...YzKYfFIvL',
        ],
    ],
];

IdP(Azure AD)を設定します。
このとき、$metadataentityid の URL を設定します。

# vi config/authsources.php
/var/simplesamlphp/config/authsources.php
//    'default-sp' => [
//        'saml:SP',
//...
//        'idp' => null,
// ↓ 変更
    'default-sp' => [
        'saml:SP',
//...
        'idp' => 'https://sts.windows.net/0******2-f**7-4**c-9**4-1**********b/',

Test

https://ssp2.example.com/simplesaml/admin にて、
Test タブをクリックして、
default-sp をクリックします。

Testタブクリック


default-spをクリック


Azure ADサインイン画面


Test成功画面


OK!


Azure AD のアカウントでサインインできれば、ひとまず問題なしです。


Web アプリ(info.php)SSO 対応

Azure AD - エンタープライズアプリケーション - SimpleSAMLphpIdP

応答 URL (Assertion Consumer Service URL)
https://webapps-php.example.com/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp
を追加します。

シングル サインオン→編集


応答 URL (Assertion Consumer Service URL)追加


Web アプリを SSO 対応に改修します。

# vi /opt/webapps/php/info.php
/opt/webapps/php/info.php
<?php
require_once('/var/simplesamlphp/lib/_autoload.php');
use SimpleSAML\Auth\Simple;
$as = new Simple('default-sp');
$as->requireAuth();
phpinfo();
# vi /etc/nginx/conf.d/webapps-info.conf
/etc/nginx/conf.d/webapps-info.conf
# location / の上に追記
  location ^~ /simplesaml {
    index index.php;
    alias /var/simplesamlphp/public;

    location ~^(?<prefix>/simplesaml)(?<phpfile>.+?\.php)(?<pathinfo>/.*)?$ {
      include      fastcgi_params;
      # fastcgi_pass   $fastcgi_pass;
      fastcgi_pass   unix:/run/php/php8.3-fpm.sock;
      fastcgi_param SCRIPT_FILENAME $document_root$phpfile;

      # Must be prepended with the baseurlpath
      fastcgi_param SCRIPT_NAME /simplesaml$phpfile;

      fastcgi_param PATH_INFO $pathinfo if_not_empty;
    }
  }
  location /
# systemctl restart nginx

https://webapps-php.example.com/info.php にアクセスします。

Azure ADサインイン画面

Test でログインしたままブラウザを再起動していない場合、再認証はかかりません。


phpinfo()の画面


ヨシっ!


loading...