LoginSignup
1
0

More than 3 years have passed since last update.

Django + Shibboleth with RemoteUserMiddleware

Last updated at Posted at 2020-05-04

背景

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を追加

httpd.conf
<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を追加(下記)。

settigs.py
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を追加(下記)。

settings.py
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.RemoteUserBackend',
)

attribute-mapの設定

IdPからのassertionのうち、アプリ側で使いたいID情報をキャッチするように設定する。今回は、日本語における「(姓に対する)名」をキャッチするため下記のようにした。

attribute-map.xml
...
    <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を使うことにした。

shibboleth2.xml
...
    <ApplicationDefaults entityID="https://localhost/"
        REMOTE_USER = "givenName"
        cipherSuites="DEFAULT:!EXP:!LOW:!aNULL:!eNULL:!DES:!IDEA:!SEED:!RC4:!3DES:!kRSA:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1">
...

以上。

関連記事
- RemoteUserMiddlewareとDjango認証を併用する方法
- Django RemoteUserMiddleware ログイン時にユーザ情報を更新する方法
- Shibboleth SPにおけるIdP独自attributeへの対応方法

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0