LoginSignup
0
1

More than 5 years have passed since last update.

SPNEGO: apacheのmod_auth_kerbを使わずにDjangoの認証ミドルウエアで認証する

Posted at

Ubuntu/DebianでKerberos関係パッケージいれる(libapache2-mod-auth-kerbいれたらいろいろ入る):

$ sudo apt-get install krb5-user libkrb5-dev -y

python-gssapi をpipで入れる

$ pip install python-gssapi

Djangoのプロジェクトに app/middleware.pyを作る:


    from django.contrib import auth
    from django.contrib.auth.models import User
    from django.conf import settings
    from django.http import HttpResponse
    import uuid
    import gssapi
    import base64

    def create_user_from(peer_name):
        ''' peer_name がKerberosで帰って来た時にユーザーをロード
        もしくは作成するユーティリティ '''

        try:
            return User.objects.get(username=peer_name)

        except User.DoesNotExist:
            user = User.objects.create_user(
                username=peer_name,
                password=uuid.uuid1().hex,    # パスワード適当ランダム
                email=peer_name,)             
            return user
        return None


    class AuthMiddleware(object):
        ''' 認証ミドルウエア本体 '''

        def process_request(self, request):
            out_token = None

            if request.META.get('HTTP_AUTHORIZATION','').startswith('Negotiate '):

                # KDC/Domain ControllerとSPNで接続
                service_name = gssapi.Name(settings.SPN, gssapi.C_NT_HOSTBASED_SERVICE)
                server_cred = gssapi.Credential(service_name, usage=gssapi.C_ACCEPT)
                ctx = gssapi.AcceptContext(server_cred)

             # Negotiateトークンを検証
                in_token = base64.b64decode(request.META['HTTP_AUTHORIZATION'][10:])
                out_token = ctx.step(in_token)

                if ctx.established:     # Negotiatedされた

                    user = create_user_from(str(ctx.peer_name))    #:Djangoのローカルユーザー取得

                    if user:
                        user.backend = 'django.contrib.auth.backends.ModelBackend' 
                        auth.login(request, user)                      # 認証
                        setattr(request, "spnego_token", out_token)    # Responseで使う
                        return None                                   # 処理継続

            # ブラウザにKDC/Domain ControllerにNegatiateした結果を返してもらう
            response = HttpResponse(status = 401)
            response['WWW-Authenticate'] = 'Negotiate %s' % (
                out_token and base64.b64encode(out_token) or ''
            )
            return response


        def process_response(self, request, response):
            ''' トークンがあったらまたブラウザに運んでもらう '''
            out_token = getattr(request, "spnego_token", None)
            if out_token:
                response['WWW-Authenticate'] = 'Negotiate %s' % base64.b64encode(out_token)

            return response

settings.py:


    import os

    INSTALLED_APPS += (
        'todo',
    )

    MIDDLEWARE_CLASSES += (
        'app.middleware.AuthMiddleware',
    )
    os.environ['KRB5_KTNAME'] = '/etc/hdknr.krb5.http.keytab'    #Keytabファイルを $KRB5_KTNAMEに設定
    SPN = 'HTTP@ubuntu.openid.local'                           #サービスプリンシパル名

Active DirectoryでSPNとKeytabファイルの作り方とブラウザの設定はこちらと同じ

0
1
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
0
1