Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This article uses the https://github.com/fangli/django-saml2-auth library to integrate AM SAML2 authentication into a Django application. We will use https://github.com/atomicsamurai/2do1ist as a sample Django application for this purpose.

Prerequisites

  1. This article assumes CentOS 7. Some steps may vary depending on the OS used.
  2. Python 3 (3.6.8 for this example) installed. To install there are many tutorials available online, on example is [here] (https://www.digitalocean.com/community/tutorials/how-to-install-python-3-and-set-up-a-local-programming-environment-on-centos-7)
  3. A working instance of AM 6.5. Should work with older and newer versions of AM too.
  4. Add a local hosts file entry on the users laptop/desktop:

...

Code Block
<VM ip address>    todo.example.net




High level steps

  1. Deploy, run and test the sample application as-is in a python virtual environment
  2. Create SAML2 federation configuration in AM
  3. Configure the sample application, using django-saml2-auth library to use AM as an IdP

AM is deployed under http://openam.example.com:8080/openam and the django application is deployed under http://todo.example.net:8000

Detailed steps

  1. Deploy, run and test the sample application as-is in a python virtual environment


    a. Create and activate a python virtual environment

    Code Block
    [forgerock@centosvm ~]$ mkdir django-saml2
    [forgerock@centosvm ~]$ cd django-saml2/
    [forgerock@centosvm django-saml2]$ python3.6 -m venv django-saml2-venv
    [forgerock@centosvm django-saml2]$ source django-saml2-venv/bin/activate
    (django-saml2-venv) [forgerock@centosvm django-saml2]$


    b. Installdjangoin the venv

    Code Block
    (django-saml2-venv) [forgerock@centosvm 2do1ist]$ pip3 installDjango==2.1.*
    CollectingDjango==2.1.*
      Using cachedhttps://files.pythonhosted.org/packages/bb/47/a4fdf24409656dc624a802571c3d6bb809e396ebbe6d668b16cb8ae431fa/Django-2.1.9-py3-none-any.whl
    Collecting pytz (fromDjango==2.1.*)
      Using cachedhttps://files.pythonhosted.org/packages/3d/73/fe30c2daaaa0713420d0382b16fbb761409f532c56bdcc514bf7b6262bb6/pytz-2019.1-py2.py3-none-any.whl
    Installing collected packages: pytz,Django
    Successfully installedDjango-2.1.9 pytz-2019.1
    (django-saml2-venv) [forgerock@centosvm 2do1ist]$


    c. Clone the sample appication

    Code Block
    (django-saml2-venv) [forgerock@centosvmdjango-saml2]$ git clonehttps://github.com/sandman0/2do1ist.git
    Cloning into '2do1ist'...
    .
    .


    d. Create DB (sqlite) schema

    Code Block
    (django-saml2-venv) [forgerock@centosvm 2do1ist]$ python3.6 manage.py makemigrations
    Migrations for 'todolist':
      todolist/migrations/0001_initial.py
        - Create model Todo
    (django-saml2-venv) [forgerock@centosvm 2do1ist]$ python3.6 manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, sessions, todolist
    Running migrations:
      Applying contenttypes.0001_initial... OK
      Applying auth.0001_initial... OK
      .
      .
      .
      Applying auth.0009_alter_user_last_name_max_length... OK
      Applying sessions.0001_initial... OK
      Applying todolist.0001_initial... OK
    (django-saml2-venv) [forgerock@centosvm 2do1ist]$


    e. Run the appication

    Code Block
    (django-saml2-venv) [forgerock@centosvm 2do1ist]$ python3.6 manage.py runserver0.0.0.0:8000
    Performing system checks...
    
    System check identified no issues (0 silenced).
    June 10, 2019 - 22:55:15
    Djangoversion 2.1.9, using settings 'mysite.settings'
    Starting development server athttp://0.0.0.0:8000/
    Quit the server with CONTROL-C.


    f. Access the application in your browser. Login screen is shown


    g. Create two users and login and create some sample to do items for both.
    usernames: testuser1 and testuser2
    passwords: s#cret123

  2. Create SAML2 federation configuration in AM

    a. We will use alpha realm for this exercise. Similar steps can be done on bravo realm if desired.
    h. Create a file, called todolist_sp.xml with the content:
    <?xml version="1.0"?>
    <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
    validUntil="2021-06-02T21:08:54Z"
    cacheDuration="PT604800S"
    entityID="todolist">
    <md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
    <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    Location="http://todo.example.net:8000/saml2_auth/acs/"
    index="1" />

    </md:SPSSODescriptor>
    </md:EntityDescriptor>

    b. Go to "Native consoles" -> "Access Management".
    c. Make sure you are working in alpha realm, on the alpha realm's dashboard, click SAML Applications
    d. On "Entity Providers" page, click "Add Entity Provider" -> "Hosted"
    e. Fill in the details:
    Entity ID: forgerockidcloud
    Identity Provider Meta Alias - Optional: idp

    Leave the other settings unchanged. Click "Create"
    f. "forgerockidcloud" entity page will be shown. Click "Assertion Processing" and in the "Attribute Map - optional" list, add the following:
    SAML Attribute = Local Attribute
    uid = userName
    sn = sn
    giveName = givenName
    mail = mail
    g. Click "Save changes"
    h. Click "Entity Providers" on the left and then "Add Entity Provider" -> "Remote"
    i. On "New Remote Entity Provider" page, drag the created XML file to the upload area and click "Create".
    j. A new remote SP should be created, as shown:
    k. Click on the newly created SP entity, then do to "Assertion Processing" tab and add the following entries in "Attribute Map - optional"
    SAML Attribute = Local Attribute
    uid = uid
    sn = sn
    giveName = givenName
    mail = mail

    l. Click "Save changes"
    m. Click "Applications" -> "Federation" -> "Circles of Trust" on the left menu, click "Add Circle of Trust"
    n. Name it "cot1" and click "Create"
    o. Add a description (optional) and add "forgerockidcloud|saml2" and "todolist|saml2" entities in the "Entity Providers" list, then click "Save Changes".

    m. Fetch the IdP metadata from AM from https://openam-forgerock-rcstest2.forgeblocks.com/am/saml2/jsp/exportmetadata.jsp?entityid=forgerockidcloud&realm=/alpha and save it in a file, for example: /home/forgerock/django-saml2/metadata.xml



  1. Configure the sample application, using django-saml2-auth library to use AM as an IdP

    a. Stop the django application if running and install django-saml2-auth in the virtual environment

    (django-saml2-venv) [forgerock@centosvm django-saml2]$ pip3 install django_saml2_auth
    Collecting django_saml2_auth
      Using cached https://files.pythonhosted.org/packages/03/5e/4fda29b8be8e268cbd3aced6ca70987a9efb0a75f42b061461bd63df4d04/django_saml2_auth-2.2.1.tar.gz
    .
    .
    .
    Successfully installed .... long list of libs
    (django-saml2-venv) [forgerock@centosvm django-saml2]$

    b. Edit django-saml2/2do1ist/mysite/urls.py and un-comment the lines starting with re_path, so it reads:

        # These are the SAML2 related URLs. You can change "^saml2_auth/" regex to
        # any path you want, like "^sso_auth/", "^sso_login/", etc. (required)
        re_path(r'^saml2_auth/', include('django_saml2_auth.urls')),

        # The following line will replace the default user login with SAML2 (optional)
        # If you want to specific the after-login-redirect-URL, use parameter "?next=/the/path/you/want"
        # with this view.
        re_path(r'^accounts/login/$', django_saml2_auth.views.signin),

        # The following line will replace the admin login with SAML2 (optional)
        # If you want to specific the after-login-redirect-URL, use parameter "?next=/the/path/you/want"
        # with this view.
        re_path(r'^admin/login/$', django_saml2_auth.views.signin)

    also un-comment the following line:

    import django_saml2_auth.views

    c. Edit 2do1ist/mysite/settings.py and un-comment the SAML2_AUTH section at the very end, so it reads:

    SAML2_AUTH = {
        'METADATA_LOCAL_FILE_PATH': '/home/forgerock/django-saml2/metadata.xml',
        'DEFAULT_NEXT_URL': '/',
        'CREATE_USER': 'FALSE',
        'ATTRIBUTES_MAP': {
            'email': 'mail',
            'username': 'uid',
            'first_name': 'givenName',
            'last_name': 'sn',
        },
        'ENTITY_ID': 'todolist',
        'USE_JWT': False,
        'FRONTEND_URL': 'https://myfrontendclient.com',
    }

    d. Launch the application

    (django-saml2-venv) [forgerock@centosvm 2do1ist]$ python3.6 manage.py runserver 0.0.0.0:8000
    Performing system checks...

    System check identified no issues (0 silenced).
    June 10, 2019 - 23:25:55
    Django version 2.1.9, using settings 'mysite.settings'
    Starting development server at http://0.0.0.0:8000/
    Quit the server with CONTROL-C.


    e. Access the application in the browser again - you should be redirected to AM login page, with URL similar to:

    https://openam-forgerock-rcstest2.forgeblocks.com/am/XUI/?realm=/alpha&forward=true&spEntityID=todolist&goto=/SSORedirect/metaAlias/alpha/idp?ReqID%3Did-07TOxB3yhlo6tAsVg%26index%3Dnull%26acsURL%3Dhttp://todo.example.net:8000/saml2_auth/acs/%26spEntityID%3Dtodolist%26binding%3Durn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST&AMAuthCookie=#login/

    Login as testuser1 or testuser2 in AM. AM should send a POST to http://todo.example.net:8000/saml2_auth/acs/ with SAMLResponse in the POST payload. You should be redirected to the application main page with the todo list for the user you logged in as.

    The decoded SAML assertion will look like:

    <samlp:Response Destination="http://todo.example.net:8000/saml2_auth/acs/"
        ID="s279fe23917842cdc4f50e63249db753daab02561f" InResponseTo="id-hZnmzTaHb2zFEqpUz"
        IssueInstant="2019-06-10T23:31:00Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
        <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">djangoidp</saml:Issuer>
        <samlp:Status xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
            <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"
                xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"></samlp:StatusCode>
        </samlp:Status>
        <saml:Assertion ID="s2d1a5ac225906d844234c47162029ca330ee07ad1" IssueInstant="2019-06-10T23:31:00Z"
            Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
            <saml:Issuer>djangoidp</saml:Issuer>
            <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:SignedInfo>
                    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
                    <ds:Reference URI="#s2d1a5ac225906d844234c47162029ca330ee07ad1">
                        <ds:Transforms>
                            <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </ds:Transforms>
                        <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                        <ds:DigestValue>bBRg5ErGCCi54IuMC9hcjmAE0aY8t6nikhije+VFRJA=</ds:DigestValue>
                    </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>
                    EnxhuogdTSC1YEwyjWlY9WsbpQ89ROec9jp6atnKmDQfLeeO1AgBSrbsyj+phQe05RyiEA/8Dx8Q&#13;
                    bDwjl2t1uuYAizeCp8oWrkGRB9q50Hb3bsPd3FSJUBK+LAgsYo28GAL6cwDx4wYbvnvZ6NeoiaXR&#13;
                    8tihcdDqc/rZpqQ9U4V+U8ajXSF2/ePazhJgml/U0lW+M6LiCvNMB9KFYfB9zGfQ2gNa95zcxQKm&#13;
                    ar5FCBIGvrejFRWEb1GVfAyGVzJG4js0qVZdbxeGbup3sfE5x4QY0Axeab53rUReq3aRtUtlvuUF&#13;
                    hrYb8j3tyrdKhJXs1GpaDzE/yTm+tSimNQ4kEA==
                </ds:SignatureValue>
                <ds:KeyInfo>
                    <ds:X509Data>
                        <ds:X509Certificate>
                            MIIDYTCCAkmgAwIBAgIEFt4OQjANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVSzEQMA4GA1UE&#13;
                            CBMHQnJpc3RvbDEQMA4GA1UEBxMHQnJpc3RvbDESMBAGA1UEChMJRm9yZ2VSb2NrMQswCQYDVQQL&#13;
                            EwJBTTENMAsGA1UEAxMEdGVzdDAeFw0xODA0MDMxNDIwNThaFw0yODAzMzExNDIwNThaMGExCzAJ&#13;
                            BgNVBAYTAlVLMRAwDgYDVQQIEwdCcmlzdG9sMRAwDgYDVQQHEwdCcmlzdG9sMRIwEAYDVQQKEwlG&#13;
                            b3JnZVJvY2sxCzAJBgNVBAsTAkFNMQ0wCwYDVQQDEwR0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC&#13;
                            AQ8AMIIBCgKCAQEAi7t6m4d/02dZ8dOe+DFcuUYiOWueHlNkFwdUfOs06eUETOV6Y9WCXu3D71db&#13;
                            F0Fhou69ez5c3HAZrSVS2qC1Htw9NkVlLDeED7qwQQMmSr7RFYNQ6BYekAtn/ScFHpq8Tx4BzhcD&#13;
                            b6P0+PHCo+bkQedxwhbMD412KSM2UAVQaZ+TW+ngdaaVEs1Cgl4b8xxZ9ZuApXZfpddNdgvjBeeY&#13;
                            QbZnaqU3b0P5YE0s0YvIQqYmTjxh4RyLfkt6s/BS1obWUOC+0ChRWlpWE7QTEVEWJP5yt8hgZ5Me&#13;
                            cTmBi3yZ/0ts3NsL83413NdbWYh+ChtP696mZbJozflF8jR9pewTbQIDAQABoyEwHzAdBgNVHQ4E&#13;
                            FgQUDAvAglxsoXuEwI2NT1hFtVww2SUwDQYJKoZIhvcNAQELBQADggEBADiHqUwRlq1xdHP7S387&#13;
                            vMLOr+/OUgNvDUogeyrpdj5vFve/CBxSFlcoY215eE0xzj2+bQoe5To3s8CWkP9hqB3EdhaRBfCr&#13;
                            d8Vpvu8xBZcxQzmqwNjmeDrxNpKes717t05fDGgygUM8xIBs29JwRzHzf7e0ByJjn9fvlUjDAGZ7&#13;
                            emCTN382F2iOeLC2ibVl7dpmsWZTINhQRbmq5L4ztOcjITk5WZnBF439oRRn68fWZVkOv2UqaKbk&#13;
                            uMjgotNuot+ebHtOchEiwKz8VAK7O3/IgD6rfNBfz+c/WeoPcrfQBR4zfizw/ioR115RSywifzlw&#13;
                            q5yziqyU04eP4wLr3cM=
                        </ds:X509Certificate>
                    </ds:X509Data>
                </ds:KeyInfo>
            </ds:Signature>
            <saml:Subject>
                <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" NameQualifier="djangoidp"
                    SPNameQualifier="djangosp">rAm9eYcvPMlcTpoN3MkHJpacNCp2</saml:NameID>
                <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                    <saml:SubjectConfirmationData InResponseTo="id-hZnmzTaHb2zFEqpUz"
                        NotOnOrAfter="2019-06-10T23:41:00Z" Recipient="http://todo.example.net:8000/saml2_auth/acs/"/></saml:SubjectConfirmation>
            </saml:Subject>
            <saml:Conditions NotBefore="2019-06-10T23:21:00Z" NotOnOrAfter="2019-06-10T23:41:00Z">
                <saml:AudienceRestriction>
                    <saml:Audience>djangosp</saml:Audience>
                </saml:AudienceRestriction>
            </saml:Conditions>
            <saml:AuthnStatement AuthnInstant="2019-06-10T23:31:00Z"
                SessionIndex="s287b483c84580740e2216166d10dd554f1a91e501">
                <saml:AuthnContext>
                    <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
                </saml:AuthnContext>
            </saml:AuthnStatement>
            <saml:AttributeStatement>
                <saml:Attribute Name="uid">
                    <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">testuser1</saml:AttributeValue>
                </saml:Attribute>
                <saml:Attribute Name="sn">
                    <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">user1</saml:AttributeValue>
                </saml:Attribute>
                <saml:Attribute Name="mail">
                    <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">testuser1@example.com</saml:AttributeValue>
                </saml:Attribute>
                <saml:Attribute Name="givenName">
                    <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">test1</saml:AttributeValue>
                </saml:Attribute>
            </saml:AttributeStatement>
        </saml:Assertion>
    </samlp:Response>

...