Thank you, Simon. I had started down a similar path and got stuck. I will 
use your code code as a basis to continue that work.

On Thursday, December 5, 2024 at 8:57:26 AM UTC-6 simon...@gmail.com wrote:

> 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#levels 
> <https://docs.python.org/3/library/logging.html#levels>import 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/de130107-f0a0-40d5-bfee-4008e56a073en%40googlegroups.com.

Reply via email to