はじめに
私は現在、主に認証を担当しています。
昨今ではSSO(シングルサインオン)を導入されるお客様も多く、単純なID/パスワード方式を始めとする独自の認証だけでは要件を満たすことは非常に難しくなってきています。
SSOには様々な手法がありますが、このSaaS時代においてはほぼSAMLの独壇場と言っても過言ではないでしょう。(もちろん5~10年後には廃れていてもおかしくないですが)
そんな中、最近Shibboleth(学術認証基盤)の案件があり、教育機関のお客様への対応として今後も継続的にShibbolethが必要だと感じたため、社内に導入してみました。
この記事はその際の記録です。
少しでも、似たようなシステム連携業務に携わる方の力になればと思います。
そもそもShibbolethとは
Shibbolethとは、IDフェデレーションを実現するための認証・認可基盤アーキテクチャです。
高等教育機関や学術出版社で用いられ(というかほぼそういうとこでしか利用されてない)、日本の大学・国立情報学研究所が共同で運営している「学術認証フェデレーション」通称『学認』は、このShibbolethを基盤として動いています。
(『学認』という名称は私も学生時代何度か耳にし、実際PubMedやKULASISなんかにアクセスするときに使っていたのでしょうが、その中身について意識したことはありませんでした。)
このShibbolethを基盤にした学認を利用することで、ユーザーは論文を読むことができたり、学内システムで交通費を申請したり、顕微鏡を予約したり、果ては別の大学でWi-fiに接続出来たりもするわけです。
素晴らしいですね。へー。
Shibbolethの構成
Shibbolethは以下2つのパーツによって構成されています。
- IdP
- SP
Shibbolethは全体として広義の「アイデンティティプロバイダ」としての役割を果たしますが、その内部ではSAML的な意味で「IdP」として働くサーバーと、IdPからアサーションを受け取って他のアプリケーションへ情報を受け渡す「SP」というサーバーが存在します。
SAML的には確かにIdPとSPではあるものの多分にミドルウェア的な役割を担っているので、今までWebアプリケーションとの直接的な連携ばかりを見てきた人間としては理解に時間が掛かりました。
(また余談ですが、日本の教育機関の場合、学認に参加している=他のIdPに切り替える選択肢がほぼ無いため、「Shibboleth IdP」ではなく単に「IdP」と呼ばれてしまうこともあるようで、「IdPってどこの何…?」となりかねず、その点も意思疎通の妨げになりかねないなぁと感じています。)
今回は、この内「IdP」と自社製品を連携することを目標にしました。
導入してみて分かった、Shibbolethの良いところ
- かなりカスタマイズできる。高機能な印象。
- ドキュメントが整備されている。
Shibbolethの問題点
GUIがねぇ!!!
これに尽きます。vimは友達。
yumで簡単にインストール出来るのはありがたいんですが、設定方法がはっきり言って分かりづらい。
メタデータを渡さないと設定できないのはなかなか不親切な設計。
あと細かいところだとGoogleやMSでも利用されてないtransientがNameIDのデフォルト設定になっているのはやはりこう、ビジネス・コミュニティとの乖離を感じました。
実際の導入手順
IdPはLDAPとtomcatで構成されますので、その二つを立てていきます。
LDAP
同一インスタンス上に、LDAPを立てます。
基本的にこちらの通りです。
- OpenLDAP
yumでインストールし、
# yum install openldap-clients openldap-servers
パスワードを作成
# slappasswd -h {CRYPT} -c '$6$%s$' -s {任意のパスワード}
{CRYPT}パスワード文字列
test-idp.ldifを以下の内容で作成し
dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn={任意},o={任意},dc={任意},c=JP" read by * none
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: o={任意},dc={任意},c=JP
-
replace: olcRootDN
olcRootDN: cn={任意},o={任意},dc={任意},c=JP
-
add: olcRootPW
olcRootPW: {CRYPT}パスワード文字列
ドメイン情報を登録
# ldapmodify -Y EXTERNAL -H ldapi:// -f test-idp.ldif
edupersonファイルを以下の内容で作成
include /etc/openldap/schema/eduperson.schema
eduperson.ldifを作成
# slapcat -f eduperson -F /tmp -n0 -s "cn={0}eduperson,cn=schema,cn=config" > /etc/openldap/schema/eduperson.ldif
作成されたeduperson.ldifを手順通りに修正( ファイルの後方にある「structuralObjectClass: olcSchemaConfig」以降を全て削除
も忘れずに!)
dn: cn=eduperson,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: eduperson
edupersonスキーマを登録。その際、必要な他のスキーマ(cosine, inetorgperson)も一緒に登録する。
# ldapadd -Y EXTERNAL -H ldapi:// -f /etc/openldap/schema/cosine.ldif
# ldapadd -Y EXTERNAL -H ldapi:// -f /etc/openldap/schema/inetorgperson.ldif
# ldapadd -Y EXTERNAL -H ldapi:// -f /etc/openldap/schema/eduperson.ldif
3. LDAPのテストデータ作成
の通り、test.ldifファイルを作成する。この時、オブジェクト名などは先に作成したtest-idp.ldifと一致させる必要がある。
そしてテストデータを登録する。
# ldapadd -x -h localhost -D "cn={任意},o={任意},dc={任意},c=JP" -w {任意のパスワード} -f test.ldif
tomcat
以下の構成。
- CentOS7 (VirtualBox上)
- openjdk 1.8.0
- tomcat 7
基本的な手順はこちらを参考にしています。
まずここからパッケージ(執筆時点で3.4.7)をダウンロードし、
# tar xzvf shibboleth-identity-provider-3.?.?.tar.gz
# cd shibboleth-identity-provider-3.?.?
# ./bin/install.sh -Didp.conf.filemode=640
でインストール。EntityIDは参考リンクにある通り、 https://ホスト名/idp/shibboleth
にしました。
3. パーミッションの調整
も行い、 4. jakarta-taglibs-core.jar と jakarta-taglibs-standard.jar の配置
でidp.warをリビルドします。
5. idp.war の登録
でtomcatにwarを配置。
事前に
# chown root:tomcat /opt/shibboleth-idp/credentials/server.key
# chmod 640 /opt/shibboleth-idp/credentials/server.key
でtomcatユーザに鍵ファイルへの権限を与えておき、idp.propertiesを編集していきます。
こちらを参考のこと。
そして先に立てたLDAPと接続するための設定をしていきます。
ldap.propertiesを編集。
idp.authn.LDAP.ldapURL = ldap://localhost
idp.authn.LDAP.useStartTLS = false
(省略)
idp.authn.LDAP.baseDN = o={任意},dc={任意},c=JP
idp.authn.LDAP.subtreeSearch = true
idp.authn.LDAP.userFilter = (uid={user})
# bind search configuration
# for AD: idp.authn.LDAP.bindDN=adminuser@domain.com
idp.authn.LDAP.bindDN = cn={任意},o={任意},dc={任意},c=JP
idp.authn.LDAP.bindDNCredential = {任意のパスワード}
これで、
systemctl restart tomcat
するととりあえずLDAPと繋がったIdPが立ち上がります。
SPの登録
SPを登録するためには、SPのmetadataが必要です。
用意したmetadataファイルを /opt/shibboleth-idp/metadata
辺りに sp-metadata.xml として配置し、 /opt/shibboleth-idp/conf/metadata-providers.xml
に以下を追記。
<MetadataProvider id="LocalMetadata(任意の名称)" xsi:type="FilesystemMetadataProvider" metadataFile="/opt/shibboleth-idp/metadata/sp-metadata.xml"/>
Attributeの設定
差し当たり、接続確認したいだけなので以下のようにしたい。
- AssertionはEncryptしない
- AttributeStatementにユーザーIDを渡す
そのため、 relaying-party.xml
で id="shibboleth.DefaultRelyingParty" を以下の様に設定。
<bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty">
<property name="profileConfigurations">
<list>
<bean parent="Shibboleth.SSO" />
<ref bean="SAML1.AttributeQuery" />
<ref bean="SAML1.ArtifactResolution" />
<bean parent="SAML2.SSO" p:includeAttributeStatement="true" p:encryptAssertions="never" p:encryptNameIDs="never" />
<ref bean="SAML2.ECP" />
<ref bean="SAML2.Logout" />
<ref bean="SAML2.AttributeQuery" />
<ref bean="SAML2.ArtifactResolution" />
<ref bean="Liberty.SSOS" />
</list>
</property>
</bean>
attribute-filter.xml
で以下のように設定。
<!-- Release an additional attribute to an SP. -->
<AttributeFilterPolicy id="filter1">
<PolicyRequirementRule xsi:type="Requester" value="{SPのEntityID}" />
<AttributeRule attributeID="uid" permitAny="true" />
</AttributeFilterPolicy>
完了後、tomcatを再起動。SP側に設定を渡し、SSOを行うと・・・
おわりに
とりあえずGUIだけでもなんとかしてくれないかなぁ。
設定を色々弄れるのでやりたいようにやれるっぽいのですが、少し複雑なことをやろうとすると途端に取っつきにくくなる感じですね…。
あれ?これどっかで聞いたような
SAMLは設定方法や項目名がIdPによってバラバラで、仕様もそれなりにバラつきがあり苦労させられますが、
実際ちゃんと設定できれば利便性は非常に高いもので、SPを何個も同一IdPに連携して運用すると戻れません。
ユーザー認証周りの利便性はユーザーエクスペリエンスと明確に繋がっているので、そういう意味で非常にやりがいがあります。
みんなもっと認証に携わろうぜ!
了