From e122942d80e0272b6ca7d8af2d958e7936efc96d Mon Sep 17 00:00:00 2001 From: Tim Sheerman-Chase Date: Thu, 1 Jun 2023 09:16:15 +0100 Subject: [PATCH] Add azure AD example --- examples/pubic_idps/sp_azure.py | 108 ++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 examples/pubic_idps/sp_azure.py diff --git a/examples/pubic_idps/sp_azure.py b/examples/pubic_idps/sp_azure.py new file mode 100644 index 0000000..1c671ee --- /dev/null +++ b/examples/pubic_idps/sp_azure.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +from flask import Flask, url_for + +from flask_saml2.sp import ServiceProvider, IdPHandler, AuthData +from tests.idp.base import CERTIFICATE as IDP_CERTIFICATE +from tests.sp.base import CERTIFICATE, PRIVATE_KEY +from flask_saml2.utils import certificate_from_string, certificate_from_file, private_key_from_file +from flask_saml2.signing import RsaSha256Signer, Sha256Digester + +# How to configure IdP https://learn.microsoft.com/en-gb/azure/active-directory/saas-apps/saml-toolkit-tutorial + +class AzureServiceProvider(ServiceProvider): + def get_logout_return_url(self): + print (url_for('index', _external=True)) + return url_for('index', _external=True) + + def get_default_login_return_url(self): + print (url_for('index', _external=True)) + return url_for('index', _external=True) + + def get_sp_digester(self): + return Sha256Digester() + + def get_sp_signer(self): + private_key = self.get_sp_private_key() + return RsaSha256Signer(private_key) + + def get_sp_entity_id(self): + return "your-application-id-from-azure" #Application ID + +class AzureIdPHandler(IdPHandler): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def get_auth_data(self, response) -> AuthData: + + #Skip validating data? + + return AuthData( + handler=self, + nameid=response.nameid, + nameid_format=response.nameid_format, + attributes=response.attributes, + ) + +sp = AzureServiceProvider() + +app = Flask(__name__) +app.debug = True +app.secret_key = 'fhu6b4WtvgDxvt8PWsu' + +app.config['SERVER_NAME'] = 'localhost:9000' +app.config['SAML2_SP'] = { + #Generate with openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:4096 -keyout privateKey.key -out certificate.crt + 'certificate': certificate_from_file("examples/pubic_idps/certificate.crt"), + 'private_key': private_key_from_file("examples/pubic_idps/privateKey.key"), +} + +tenant_id = 'your-tenant-id-from-azure' + +app.config['SAML2_IDENTITY_PROVIDERS'] = [ + { + 'CLASS': 'examples.sp_galehead.AzureIdPHandler', + 'OPTIONS': { + 'entity_id': 'https://my.domain.com', #Same as you specified on azure + 'display_name': 'Azure AD', + 'sso_url': 'https://login.microsoftonline.com/{}/saml2'.format(tenant_id), + 'slo_url': 'https://login.microsoftonline.com/{}/saml2'.format(tenant_id), + 'certificate': certificate_from_string("""-----BEGIN CERTIFICATE----- +cut-and-paste-saml-certificate-here +-----END CERTIFICATE-----"""), + }, + }, +] + + +@app.route('/') +def index(): + if sp.is_user_logged_in(): + auth_data = sp.get_auth_data_in_session() + + message = f''' +

You are logged in as {auth_data.nameid}. + The IdP sent back the following attributes:

+ ''' + + attrs = '

{}
'.format(''.join( + f'
{attr}
{value}
' + for attr, value in auth_data.attributes.items())) + + logout_url = url_for('flask_saml2_sp.logout') + logout = f'
' + + return message + attrs + logout + else: + message = '

You are logged out.

' + + login_url = url_for('flask_saml2_sp.login') + link = f'

Log in to continue

' + + return message + link + + +app.register_blueprint(sp.create_blueprint(), url_prefix='/saml/') + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=9000)