Hello Fred,

I had a legacy web2py app until recently that worked with SAML2 
authentication and Azure AD as Identity Provider. In my particular case, 
all users already existed in my app, only authentication was handled via 
SAML2.
The following example code was working in my app.
I also recommend to enable python logging and use a browser plugin to 
inspect saml2 requests for debugging.

1) setup saml2 as authentication method somewhere in the model (db.py in my 
case). I also disabled some of the other actions.




































*# 
---------------------------------------------------------------------------# 
Enable SAML login# 
---------------------------------------------------------------------------from 
gluon.contrib.login_methods.saml2_auth import Saml2Authimport os# logging:# 
https://docs.python.org/3/library/logging.html#levelsimport logginglogger = 
logging.getLogger('saml2')logger.setLevel(logging.DEBUG)# Session Cookies 
is not passed in POST to SP after authenticatoin if samesite is not "none" 
(must be combined with "secure")session.samesite('none')session.secure()if 
not request.is_local:    
auth.settings.actions_disabled.append('change_password')    
auth.settings.actions_disabled.append('request_reset_password')    
auth.settings.actions_disabled.append('reset_password')    
auth.settings.actions_disabled.append('profile')    
auth.settings.actions_disabled.append('logout')    
auth.settings.actions_disabled.append('retrieve_username')    
auth.settings.cas_create_user = False    auth.settings.use_username = True  
  auth.settings.logout_next = ''    auth.settings.login_form = Saml2Auth(  
  config_file=os.path.join(request.folder, 'private', 'sp_conf'),    
maps=dict(        username=lambda v: v['NameID'][0],        
first_name=lambda v: v['First Name'][0],        last_name=lambda v: v['Last 
Name'][0],    ),    entityid='[entidyId of your security token service 
provider]',)*

2)  put the make_metadata.py in your private-folder

3) add a controller to view / create the metadata, in my case in default.py:

def metadata():
    import os.path
    if os.path.exists(request.folder + '/private/sp.xml'):
        f = open(request.folder + '/private/sp.xml', 'r')
        response.headers['Content-Type']='application/xml'
        return f.read()
    else:
        import subprocess
        command = 'make_metadata.py ' +  request.folder + 
'/private/sp_conf.py > ' + request.folder + '/private/sp.xml'
        #In production should be shell=False
        p=subprocess.Popen(command, stdout=subprocess.PIPE, 
stderr=subprocess.PIPE,shell=True)
        stdout,stderr = p.communicate()
        status = p.poll()
        if status == 0:
            f = open(request.folder + '/private/sp.xml', 'r')
            response.headers['Content-Type']='application/xml'
            return f.read()
        return str(stderr)

4) add sp_conf.py to "private" folder for configuring the metadata. add 
your specific hostnames, appname, certificate and path to federation 
metadata (I had that stored locally):

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT
import os.path
import requests
import tempfile

BASEDIR = os.path.abspath(os.path.dirname(__file__))


def full_path(local_file):
    return os.path.join(BASEDIR, local_file)


# Web2py SP url and application name
HOST = '[FQDN of your host]'
APP = '[web2py application name]'
# To load the IDP metadata...
IDP_METADATA = full_path('FederationMetadata.xml')  # the name of the 
FederationMEtadata of your STS

CONFIG = {
    # your entity id, usually your subdomain plus the url to the metadata 
view.
    'entityid': '%s/%s/default/metadata' % (HOST, APP),
    'service': {
        'sp': {
            'name': '[name of your app]',
            'endpoints': {
                'assertion_consumer_service': [
                    ('%s/%s/default/user/login' % (HOST, APP), 
BINDING_HTTP_REDIRECT),
                    ('%s/%s/default/user/login' % (HOST, APP), 
BINDING_HTTP_POST),
                ],
            },
            'signing_algorithm': 
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
            'authn_requests_signed': True,
            'want_response_signed': False,
            'want_assertions_signed': True,
            'allow_unsolicited': False,
        },
    },
    
    # # Your private and public key, here in a subfolder of "private"
    'key_file': full_path('pki/privateKey.key'),
    'cert_file': full_path('pki/certificate.crt'),

    'attribute_map_dir': full_path('attribute_map_dir'),

    # where the remote metadata is stored
    'metadata': {
        'local': [IDP_METADATA],
    },
}

5) add an "attribute_map_dir" folder with a "saml_unspecified.py" that 
mapps the field names of your app to the field names of your identity 
provider, e.g:
MAP = {
    "identifier": "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified",
    "fro": {
        'Last Name': 'last_name',
        'First Name': 'first_name',
        'NameID': 'username',
        'Email': 'email',
        },
    "to": {
        'last_name': 'Last Name',
        'first_name': 'First Name',
        'username': 'NameID',
        'email': 'Email'
    }
}

6) call the metadata-controller to create the sp.xml

That should do it.

Simon

fre...@gmail.com schrieb am Mittwoch, 4. Dezember 2024 um 17:14:40 UTC+1:

> I have a legacy web2py app that's been using LDAP since 2010 when I 
> created it. We are changing our IT systems to use SAML2 via OneLogin.com 
> for authentication where possible and so I'd like to convert my app from 
> from LDAP to SAML2 authentication. Can anyone provide some examples of 
> SAML2 auth in web2py? 
>
> I've found a few examples but they are old and don't quite give me enough 
> basis to get SAML2 working. I don't want to go through any intermediary 
> like Jainrain. I've looked over gluon/contrib/login_methods/saml2_auth.py 
> but haven't been able to work out all that I need to do to use it.
>
> I'm also concerned about how converting to SAML would work with all the 
> auth_user records already created via the LDAP authentication.
>
> -Fred
>
>

-- 
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
--- 
You received this message because you are subscribed to the Google Groups 
"web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to web2py+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/web2py/1e04b8b5-d83c-4cb5-9e74-28769bd41706n%40googlegroups.com.

Reply via email to