SAMLのSPとなるようなアプリケーションが簡単に作れるかどうか、という技術検証で
onelogin/php-samlを触ったので使い方をメモってみましたー。
今回はSalesforceをIdP、phpのアプリをSP(ローカル環境)として
ソースに付随されているサンプルのアプリを動かしてみます。
1. インストール
php使いの人にはお馴染みのComposerを使ってインストールします。Windowsの場合はChocolateyだと何故か上手く行かなかったので、
本家からインストーラでインストールした方が良いかもしれないです。
$ composer init
からの composer.jsonに”onelogin/php-saml”: “master-dev” を追加
{
"name": "hoge/php",
"authors": [
{
"name": "hoge",
"email": "hoge@example.com"
}
],
"require": {
"onelogin/php-saml":"master-dev"
}
}
からの
$ composer install
でvenderディレクトリ配下にインストールされます。
2. 証明書の設定
SP側の証明書を設定します。certsフォルダに秘密鍵と証明書を作成します。
$ cd php-saml/certs
$ openssl genrsa 2048 > sp.key
$ openssl req -new -key sp.key > sp.csr
$ openssl x509 -days 3650 -req -signkey sp.key < sp.csr > sp.crt
3. settings.phpの設定
まずdemo1ディレクトリ配下のsettings_example.phpをコピーしてsettings.phpを作成します。settings.phpの中身は以下の通り。
<?php
$spBaseUrl = 'https://localhost/php-work/vendor/onelogin/php-saml'; //php-samlへのURLをセット
$settingsInfo = array (
'strict' => true,
'debug' => true,
'sp' => array (
'entityId' => $spBaseUrl.'/demo1/metadata.php',
'assertionConsumerService' => array (
'url' => $spBaseUrl.'/demo1/index.php?acs',
),
'singleLogoutService' => array (
'url' => $spBaseUrl.'/demo1/index.php?sls',
),
'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
),
'idp' => array (
'entityId' => 'https://hoge.my.salesforce.com',
'singleSignOnService' => array (
'url' => 'https://hoge.my.salesforce.com/idp/endpoint/HttpRedirect',
),
'singleLogoutService' => array (
'url' => '',
),
'x509cert' => '', //現時点では未設定でOK
),
'security' => array (
'authnRequestsSigned' => true,
)
);
$spBaseUrlにはphp-samlへのURLをセット。
spのNameIDFormatはlib\Saml2\Constants.php のNAMEID_****の定数値から選択します。
idpのentityIdにはマイドメインの値を設定します。
singleSignOnServiceにはSP Initiated SSO用のリダイレクト先URL
(SAML Requestのエンドポイント)を入力します。
ちなみにphp-samlではSAML RequestはRedirectのみ対応しており
SAML AssertionはPOSTのみの対応となっています。
また、debug=trueでエラー時にエラーの理由等の詳細な情報が出力され
strict=trueではIdP、SPのentityId等が正確に合致していないとエラーになります。
逆に、strict=falseだとentityId不一致でもログイン出来てしまうので
特別なことが無ければstrict=trueにすべきです。
authnRequestsSignedはデフォルトfalseになっており
falseだとAuthnRequestでSignatureが発行されません。
4. Salesforceの設定
設定>作成>アプリケーション から接続アプリケーションを以下のように作成します。各項目には3のsettings.phpに設定した値を入力し
開始URLとACS URLにはassertionConsumerServiceの値、エンティティIDにはentityIdの値
名前ID形式にはNameIDFormatの値をそれぞれセットします。
要求署名を確認をチェックして2で作成した証明書をアップロードしてください。
保存後にManageボタンを押下し、有効なプロファイルを設定します。
また、メタデータのダウンロードから出力されるXMLのX509Certificateのテキスト値
(以下のMIIErD********の部分)をコピーします。
<?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://hoge.my.salesforce.com" validUntil="2025-06-27T16:41:32.609Z">
<md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIErD********</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://hoge.my.salesforce.com/idp/endpoint/HttpPost"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://hoge.my.salesforce.com/idp/endpoint/HttpRedirect"/>
</md:IDPSSODescriptor>
</md:EntityDescriptor>
またメタデータの値がsettings.phpの値と整合性が取れているかどうかも確認します。
(entityIdとかsingleSignOnServiceとか)
5. settings.phpにIdPの証明書を設定
settings.phpのidpのx509certに4でコピペした証明書のテキストをセットします。6. デモアプリを動かす
IdP Initiated SSOの場合はSalesforceの接続アプリケーションのIdp-init のログイン URLにアクセスすればOKです。
アプリケーションランチャーを使ってIdP Initiated SSOをする場合は
接続アプリ>manageの開始URLのところに”Idp-init のログイン URL”の値を入れて
対象アプリケーションのリンクやランチャーをクリックすればOK。
SP Initiated SSOの場合は
demo1/index.phpでLoginのリンクをクリックすると
SalesforceにSAML Requestが飛ぶので、Salesforceで認証後に
demo1/index.php?acsにSAML Assertionが返って、認証が出来ます。
署名がミスっている場合はSFDCから以下のようなSAMLResponseが
URLパラメータ経由(リダイレクト)で返却されます。
<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://localhost/php-work/vendor/onelogin/php-saml/demo1/index.php?acs" ID="_5864445b6cb74c19d7b8f837b3eddf671435452699187" InResponseTo="ONELOGIN_9137d2fcb963ddda7f82af1bbfb9225ce9ec659b" IssueInstant="2015-06-28T00:51:39.187Z" Version="2.0">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">hoge.my.salesforce.com</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"/>
</samlp:Status>
</samlp:Response>
7. デモアプリの中身
デモアプリの根幹であるindex.phpの中身は簡潔でSP Initiated SSOをする場合はOneLogin_Saml2_Auth#login
SAML AssertionのverifyはOneLogin_Saml2_Auth#processResponse
SLOしたい場合はOneLogin_Saml2_Auth#processSLO
を叩くだけで、SAML Assertionのverifyが通ったタイミングで
php側のセッションを発行すればOKです。