#背景
Shibboleth認証でDjangoアプリにログインしたい。
RemoteUserMiddlewareを使えばできると聞いてやってみたらいろいろぶち当たったので解決方法を書く。
#環境
- Windows Server 2016
- Django 3.0
- Python 3.7.7(後々のために、3.8系は避けること!)
- Apache 2.4 + mod_shib + mod_wsgi
- Shibboleth Service Provider 3.x
#前提
- かんたんなDjangoアプリはあるものとする。
- createsuperuserで管理者権限ユーザを作ってあるものとする。
- Shibbolethはインストールしてあるものとする。(関連記事参照)
関連記事:Apache + OneLogin SSO with Shibboleth
#流れ
Shibboleth認証が通ったらID情報が環境変数REMOTE_USERに入る場合を想定(この想定についていけない人はこの記事から)。このREMOTE_USERをusernameとしてDjangoアプリに(自動で)ログインする(Djangoアプリ側ではユーザ名もパスワードも要求されない)。デフォルトの設定では、REMOTE_USERのID情報がUserオブジェクトに存在しない(初見の)場合、自動的にUserオブジェクトを作成してログインする(この設定は変更できる)。
詳細:Django Documentation - Authentication using REMOTE_USER
#ApacheのLocationを追加
<Location /Shibboleth.sso>
SetHandler shib
</Location>
<Location /> # ←'/'でなく、'/secure/'などとすれば、secure以下が管理下に置かれる。
AuthType shibboleth
ShibRequestSetting requireSession true
Require shibboleth
Require shib-session
ShibUseHeaders On
</Location>
#DjangoにRemoteUserMiddlewareを設定
詳細:https://docs.djangoproject.com/en/3.0/howto/auth-remote-user/
MIDDLEWAREにRemoteUserMiddlewareを追加(下記)。
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware', # ←ここに追加
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
AUTHENTICATION_BACKENDSにRemoteUserBackendを追加(下記)。
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.RemoteUserBackend',
)
#attribute-mapの設定
IdPからのassertionのうち、アプリ側で使いたいID情報をキャッチするように設定する。今回は、日本語における「(姓に対する)名」をキャッチするため下記のようにした。
...
<Attribute name="urn:oid:2.5.4.42" id="givenName"/> # ← 追加
<!-- New standard identifier attributes for SAML. -->
<Attribute name="urn:oasis:names:tc:SAML:attribute:subject-id" id="subject-id">
<AttributeDecoder xsi:type="ScopedAttributeDecoder" caseSensitive="false"/>
</Attribute>
...
name=urn:oid:2.5.4.42
って何ぞや、という話はなんだか難しい話のようなのでかいつまんで理解しておく。できるだけ平たく言うと、日本語における「(姓に対する)名」、英語における「Given name」や「First name」、フランス語における「Prénom」、アラビア語における「الاسم الخاص」といった概念を、共通の識別子としてurn:oid
形式であらわすとurn:oid:2.5.4.42
になるようだ(ムツカシイこと考える人がいるなあ…)。このほか、「メールアドレス」「email address」「L'adresse courriel」「عنوان البريد الإلكتروني」が指す概念を共通の識別子としてurn:oid
形式で表すとurn:oid:0.9.2342.19200300.100.1.3
と決められている。
ともかく、IdPからのSAML Assertionにはこういったurnで表されるAttribute nameをkeyとして、それぞれのvalueが送られてくる。それをShibboleth SP側で何と呼ぶかを決めるのがid
であり、これは勝手に決めてよい。
まとめると、<Attribute name="urn:oid:2.5.4.42" id="givenName"/>
は、IdPから送られてくるurn:oid:2.5.4.42
をkeyとするvalueを、今後givenName
というid
で表す、という記述。
#REMOTE_USERの設定
IdPからのassertionのうち、アプリ側のログインに使いたいID情報をREMOTE_USERに格納するように設定する。今回はgivenName
と名付けたassertionを使うことにした。
...
<ApplicationDefaults entityID="https://localhost/"
REMOTE_USER = "givenName"
cipherSuites="DEFAULT:!EXP:!LOW:!aNULL:!eNULL:!DES:!IDEA:!SEED:!RC4:!3DES:!kRSA:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1">
...
以上。
関連記事: