[PYTHON] Single sign-on to your Django application with AWS SSO

Introduction

AWS SSO is finally available in the Tokyo region, so I tried single sign-on with Django.

Source code-GitHub

Prerequisites and operating environment

Overview

Create a custom SAML 2.0 application with AWS SSO. Error handling is not performed to confirm that it works to the minimum necessary.

Policy etc.

--Use ʻAWS SSO ID Storeas the AWS SSO ID source --SelectPythonas the development language --UseDjango` for web application frameworks --Allow HTTPS communication even during development

setup

#Creating a virtual environment
$ python -m venv ~/envs/example-awssso

#Start-up
$ source ~/envs/example-awssso/bin/activate

Installation, project creation

#Django installation
(example-awssso) $ python -m pip install Django

#Version confirmation
(example-awssso) $ python -m django --version
3.1.1

#Project creation
(example-awssso) $ django-admin startproject webapp .

Install (ssl)

It is for development. Allow SSL communication. Please do not use it in a production environment. I will omit the creation of a self-signed certificate.

(example-awssso) $ pip install django-sslserver

Installation (python3-saml)

There was a lot of support for SAML authentication, but I decided to try python3-saml.
Resolve the dependency of xmlsec before installing python3-saml.

https://github.com/onelogin/python3-saml https://pypi.org/project/xmlsec/

#xmlsec dependency resolution
(example-awssso) $ brew install libxml2 libxmlsec1 pkg-config

#Installation
(example-awssso) $ pip install python3-saml

AWS SSO

Set up your custom application in the AWS Management Console.

  1. Select [Add New Application] from "Applications"
  2. Select Add Custom SAML 2.0 Application from the AWS SSO Application Catalog
  3. Select [Download] of "AWS SSO SAML Metadata File" to download the metadata file.
  4. Enter https: // localhost: 8000 / sso / in [Application Start URL] of "Application Properties".
  5. Under Application Metadata, you can manually enter the metadata values if you do not have a metadata file. ] Is selected
  6. Enter https: // localhost: 8000 / acs / in [Application ACS URL]
  7. Enter https: // localhost: 8000 / metadata / in [Application SAML Target]
  8. Select the registered application and select the [Attribute Mapping] tag.
  9. Enter $ (user: subject}, persistent in Subject
  10. Enter ʻusername, $ {user: name} , ʻunspecified in the attributes
  11. Select Save Changes
  12. Select [Add User] from "Users" to add any user.
  13. Select the [Assigned Users] tab from [Applications] and add the user created from [User Assignment].

※6

image.png

Application setup

Please refer to the sample code of Django on GitHub of python3-saml.

(example-awssso) $ mkdir saml

#Create an empty file for configuration
(example-awssso) $ touch saml/settings.json
(example-awssso) $ touch saml/advanced_settings.json

advanced_settings.json

{
  "security": {
    "nameIdEncrypted": false,
    "authnRequestsSigned": false,
    "logoutRequestSigned": false,
    "logoutResponseSigned": false,
    "signMetadata": false,
    "wantMessagesSigned": false,
    "wantAssertionsSigned": false,
    "wantNameId": true,
    "wantNameIdEncrypted": false,
    "signatureAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
    "digestAlgorithm": "http://www.w3.org/2001/04/xmlenc#sha256"
  },
  "contactPerson": {
    "technical": {
      "givenName": "technical_name",
      "emailAddress": "[email protected]"
    },
    "support": {
      "givenName": "support_name",
      "emailAddress": "[email protected]"
    }
  },
  "organization": {
    "en-US": {
      "name": "sp_test",
      "displayname": "SP test",
      "url": "https://localhost:8000"
    }
  }
}

settings.json

Edit and save the following settings from the contents of the AWS SSO SAML metadata file `.

sp

idp

ʻSet from the contents of the AWS SSO SAML metadata file. The values in ()` are the attribute values of the metadata file.

{
  "strict": true,
  "debug": true,
  "sp": {
    "entityId": "https://localhost:8000/metadata/",
    "assertionConsumerService": {
      "url": "https://localhost:8000/acs/",
      "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    },
    "singleLogoutService": {
      "url": "https://localhost:8000/sls/",
      "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
    },
    "NameIDFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
    "x509cert": "",
    "privateKey": ""
  },
  "idp": {
    "entityId": "https://portal.sso.ap-northeast-1.amazonaws.com/saml/assertion/<AWS SSO ID>",
    "singleSignOnService": {
      "url": "https://portal.sso.ap-northeast-1.amazonaws.com/saml/assertion/<AWS SSO ID>",
      "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
    },
    "singleLogoutService": {
      "url": "https://portal.sso.ap-northeast-1.amazonaws.com/saml/logout/<AWS SSO ID>",
      "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
    },
    "x509cert": "<AWS SSO certificate>"
  }
}

webapp/settings.py

Add template directory settings.

  TEMPLATES = [
      {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
-       'DIRS': [],
+       'DIRS': [
+           os.path.join(BASE_DIR, 'templates')
+       ],

Add other settings to the file

+ INSTALLED_APPS += ['sslserver']
+
+ # session
+ SESSION_ENGINE = 'django.contrib.sessions.backends.file'
+
+ # ssl
+ SECURE_SSL_REDIRECT = True
+ SESSION_COOKIE_SECURE = True
+ CSRF_COOKIE_SECURE = True
+
+ # python3-saml
+ SAML_FOLDER = os.path.join(BASE_DIR, 'saml')
+
+ # login, logout
+ LOGIN_REDIRECT_URL = '/'
+ LOGOUT_REDIRECT_URL = '/'

webapp/urls.py

Define the URL required for SSO. views.py will be newly created after this.

  from django.contrib import admin
  from django.urls import path
+ from django.contrib.auth.views import LogoutView
+ from .views import index, sso, acs, metadata

  urlpatterns = [
      path('admin/', admin.site.urls),
+     path('', index, name='index'),
+     path('sso/', sso, name='sso'),
+     path('acs/', acs, name='acs'),
+     path('logout/', LogoutView.as_view(), name='logout'),
+     path('metadata/', metadata),
  ]

webapp/views.py

As mentioned in the source comment, create the following view.

(example-awssso) $ touch webapp/views.py
from django.conf import settings
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseServerError
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from onelogin.saml2.auth import OneLogin_Saml2_Auth
from onelogin.saml2.settings import OneLogin_Saml2_Settings
from onelogin.saml2.utils import OneLogin_Saml2_Utils


def init_saml_auth(params):
    """SAML client initialization

Client initialization parameters, saml/settings.json ・ saml/advanced_settings.Initialize with json file
    """
    auth = OneLogin_Saml2_Auth(params, custom_base_path=settings.SAML_FOLDER)
    return auth


def prepare_django_request(request):
    """Get SAML client initialization parameters

Generate SAML client initialization parameters from HTTP request object
    """
    params = {
        'https': 'on' if request.is_secure() else 'off',
        'http_host': request.META['HTTP_HOST'],
        'script_name': request.META['PATH_INFO'],
        'server_port': request.META['SERVER_PORT'],
        'get_data': request.GET.copy(),
        'post_data': request.POST.copy()
    }
    return params


def index(request):
    """TOP page display

Render the TOP page
    """

    #Context parameter initialization
    attributes = False

    if 'samlUserdata' in request.session:
        if len(request.session['samlUserdata']) > 0:
            attributes = request.session['samlUserdata'].items()

    return render(request, 'index.html', { 'attributes': attributes, })


@csrf_exempt
def sso(request):
    """AWS SSO redirect

Redirect to AWS SSO
    """

    #Get initialization parameters
    prepare_params = prepare_django_request(request)
    #Initialization
    auth = init_saml_auth(prepare_params)

    return HttpResponseRedirect(auth.login())


@csrf_exempt
def acs(request):
    """Assertion verification

Verify that the user has permission to access the application
    """

    #Get initialization parameters
    prepare_params = prepare_django_request(request)
    #Initialization
    auth = init_saml_auth(prepare_params)

    request_id = None
    if 'AuthNRequestID' in request.session:
        request_id = request.session['AuthNRequestID']

    auth.process_response(request_id=request_id)
    errors = auth.get_errors()

    if not errors:
        if 'AuthNRequestID' in request.session:
            del request.session['AuthNRequestID']
        request.session['samlUserdata'] = auth.get_attributes()
        request.session['samlNameId'] = auth.get_nameid()
        request.session['samlNameIdFormat'] = auth.get_nameid_format()
        request.session['samlNameIdNameQualifier'] = auth.get_nameid_nq()
        request.session['samlNameIdSPNameQualifier'] = auth.get_nameid_spnq()
        request.session['samlSessionIndex'] = auth.get_session_index()

    return HttpResponseRedirect(auth.redirect_to('/'))


def metadata(request):
    """SP metadata display

Output metadata
    """
    saml_settings = OneLogin_Saml2_Settings(settings=None, custom_base_path=settings.SAML_FOLDER, sp_validation_only=True)
    metadata = saml_settings.get_sp_metadata()
    errors = saml_settings.validate_metadata(metadata)

    if len(errors) == 0:
        return HttpResponse(content=metadata, content_type='text/xml')
    else:
        return HttpResponseServerError(content=', '.join(errors))

Operation check

# SECRET_KEY setting
(example-awssso) $ export DJANGO_SECRET_KEY='01234567890123456789012345678901234567890123456789'
#Start Django
(example-awssso) $ python ./manage runsslserver 0.0.0.0:8000 --certificate ./certs/localhost.crt.pem --key ./certs/localhost.key.pem

Go to https: // localhost: 8000 /.

image.png

Select [Login]. Since it will be redacted to AWS SSO, log in as the user created in the ID store.

image.png

The user information recorded in the session from the SAML response is displayed on the screen.

at the end

It's now possible to centrally manage what IAM users used to access the AWS Management Console, and easily manage access and users to all the accounts that hang from AWS Organizations.

In addition, AWS SSO account assignment API and CloudFormation support have been added the other day, so it seems that automation can be flexibly supported.

Recommended Posts

Single sign-on to your Django application with AWS SSO
Steps to develop Django with VSCode
Measure Django application coverage with Coverage.py
Register your Django application in your project
Deploy a Django application with Docker
Common html to rent with Django
Deploy your Django application on Heroku
How to get started with Django
Build a web application with Django
Launched a web application on AWS with django and changed jobs
Manage your data with AWS RDS
How to authenticate with Django Part 2
How to authenticate with Django Part 3
Build your Django app on Docker and deploy it to AWS Fargate
Until you publish your Django application (+ MySQL) on AWS EC2 (+ RDS (+ S3))
How to do arithmetic with Django template
Step notes to get started with django
Your own Twitter client made with Django
I want to play with aws with python
To import your own module with jupyter
Application development using SQLite with Django (PTVS)
Create your first app with Django startproject
Connect to s3 with AWS Lambda Python
I made a WEB application with Django
[Python] Introduce UIKit3 to your Django project
Try to make your own AWS-SDK with bash
The easiest way to get started with Django
Divide your data into project-like units with Django (3)
How to develop a cart app with Django
Bring your life to life procedurally with Blender scripts
How to implement "named_scope" of RubyOnRails with Django
Easily log in to AWS with multiple accounts
Divide your data into project-like units with Django
Create a one-file hello world application with django
AWS Step Functions to learn with a sample
[Introduction to Udemy Python3 + Application] 9. First, print with print
Steps to install your own library with pip
Beginners try to make an online battle Othello web application with Django + React + Bootstrap (1)
[Learning memo] How to make an application with Django ~ Until Hello World is displayed ~
[Learning memo] How to make an application with Django ~ From virtual environment to pushing to github ~