GithubHelp home page GithubHelp logo

italia / satosa-saml2spid Goto Github PK

View Code? Open in Web Editor NEW
41.0 8.0 23.0 39.89 MB

SATOSA SAML-to-SAML proxy with Spid compliances

License: Apache License 2.0

Python 21.31% Shell 1.49% HTML 7.19% JavaScript 68.45% Dockerfile 0.17% CSS 1.39%
pysaml2 saml2 authentication proxy satosa-saml2saml satosa spid idp

satosa-saml2spid's Introduction

Satosa-Saml2Spid

A SAML2/OIDC IAM Proxy based on SATOSA for SAML-to-SAML, OIDC-to-SAML and SAML-to-Wallet interoperability with the Italian Digital Identity Systems.

Table of Contents

  1. Glossary
  2. General features
  3. Introduction
  4. Demo components
  5. Setup
  6. For Developers
  7. Author
  8. Credits

Glossary

  • Frontend, SAML2 Identity Provider, OpenID Connect Provider.
  • Backend, SAML2 Service Provider, OpenID Connect Relying Party, Wallet Relying Party.
  • TargetRouting, a SATOSA microservice for selecting the output backend to reach the endpoint (IdP) selected by the user.
  • Discovery Service, interface that allows users to select the authentication endpoint.

General features

Backends:

  • SPID SP
  • CIE SP
  • FICEP SP (eIDAS 1.0)
  • SAML2 SP
  • EUDI Wallet (eIDAS 2.0, experimental and not intended for production use)

Frontends:

This project is tested in Continuous Integration using spid-sp-test, with Metadata, Authn Requests and Responses.

Introduction

Satosa-Saml2 Spid is an intermediate between many SAML2/OIDC Service Providers and many SAML2 Identity Providers. It allows traditional Saml2 Service Providers to communicate with Spid, CIE and eIDAS Identity Providers adapting Metadata and AuthnRequest operations.

Figure1 : Traditional SAML2 Service Providers (SPs) proxied through the SATOSA SPID Backend gets compliances on AuthnRequest and Metadata operations.

This solution configures multiple proxy frontends and backends to get communicating systems that, due to protocol or specific limitations, traditionally could not interact each other.

Demo components

The example project comes with some preconfigured static pages.

for other page screenshots, see here.

These demo pages are static files, available in example/static. To get redirection to these pages, or redirection to third-party services, it is required to configure the files below:

  • file: example/proxy_conf.yml, example value: UNKNOW_ERROR_REDIRECT_PAGE: "https://static-contents.example.org/error_page.html"
  • file: example/plugins/{backends,frontends}/$filename, example value: disco_srv: "https://static-contents.example.org/static/disco.html"

Usage

The average time to set up this project for your needs takes roughly 1 hour. This time may vary depending on your configuration, how many backend and frontend you configure, the machine's resources and the type of network connection for the download of the docker images.

For the setup of this project, the following dependency must be installed in your machine:

  • Python 3.10 or higher
  • Git
  • Docker

Setup

All the setup instructions for your Satosa-Saml2spid configuration are available in README-SETUP.md.

Docker Compose

This project uses Docker, all the instructions to configure this project using the official docker images are available in Docker-compose.

The docker compose may use the enviroment variables to configure Satosa-Saml2Spid.

The official Satosa-Saml2SPID docker image is available at italia/satosa-saml2spid.

To install it, you can execute the following command: sudo docker pull ghcr.io/italia/satosa-saml2spid:latest.

Otherwise you can build the image executing the following command: docker build -t satosa-saml2spid ..

Then you can even inspect the image content, by running the following command: docker run -it -v $(pwd)/example:/satosa_proxy --entrypoint sh satosa-saml2spid.

Setup a Djangosaml2 example Service Provider

This project provides an example SAML2 Service Provider for demo purposes, this Service Provider is executed by default in the Docker Compose.

For any further detail about its configuration, see example_sp/djangosaml2_sp/README.md.

Below the demo using the djangosaml2 Service Provider with the Wallet authentication OpenID4VP .

For Developers

If you're running tests and you don't want to pass through the Discovery page each time you can use idphinting if your SP support it. Below an example using a djangosaml2 Service Provider:

https://localhost/saml2/login/?idp=https://localhost/Saml2IDP/metadata&next=/saml2/echo_attributes&idphint=https%253A%252F%252Flocalhost%253A8080

If you're going to test Satosa-Saml2Spid with spid-sp-test, take a look to .github/workflows/python-app.yml.

Additional information can be found here.

Warnings

Here something that you should know before start.

  • You must enable more than a single IdP (multiple metadata or single metadata with multiple entities) to get Discovery Service working.
  • Proxy doesn't handle SAML2 SLO, so the spidSaml2 backend is configured with Authnforce -> True. For any further information see Single Logout in Satosa.
  • SATOSA Saml2 backend configuration has a policy section that will let us to define specialized behaviours and configuration for each SP (each by entityid). In this example I defined a single "default" behaviour with attributes name_format to urn:oasis:names:tc:SAML:2.0:attrname-format:uri, due to my needs to handle many service providers for which it could be painfull do a static definition each time. An additional "hack" have been made in example/attributes-maps/satosa_spid_uri_hybrid.py, where I adopted a hybrid mapping that works for both URI and BASIC formats. Feel free to customized or decouple these format in different files and per SP.

External references

Satosa-Saml2Spid tutorials

SATOSA Official Documentation

Account Linking

Additional resources

Authors

  • Giuseppe De Marco
  • Andrea Ranaldi and his Team @ ISPRA Ambiente
  • Stefano Colagreco @ CNR

Acknowledgments

  • Salvatore Laiso
  • Fulvio Scorza and his Team @ Università del Piemonte Orientale
  • Paolo Smiraglia (SPID certs)
  • Identity Python Community (pySAML2 and SATOSA)
  • GARR IDEM Community

satosa-saml2spid's People

Contributors

alessiomurru avatar dependabot[bot] avatar ebusi avatar francesco-filicetti avatar gartic99 avatar mdrew avatar peppelinux avatar salvatorelaiso avatar scolagreco avatar sebbalex avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

satosa-saml2spid's Issues

Error in enviroment configuration

SATOSA_CONTACT_PERSON_IPA_CODE

  • is not present in README istruction and is required for SPID

SATOSA_CONTACT_PERSON_MUNICIPALITY

  • is not present in README istruction

Fix example discovery template

  • update to last bootstrap italia template
  • link requested font
  • link spirit.svg for icon
  • move all static link to /static/spid/ path

docker-example directory

the docker-compose file link the nonexistent docker-example directory for the configuration files
In instructions is write that is needed copy the example directory as docker-example.... If both directories are examples why can't jump this step and link directly the example directory?

Static page errors

Hi @peppelinux and each others partecipants,

I would like to go back to talking about the error pages.
With a simple script we can generate the SPID/CIE specific error pages from the generic error page (or also from the discovery page).

With single error pages we can redirect the errors to the right error page.
Vantages:

  • we an remove jinja from requisites
  • We can load the errors messages and other details from a json file
  • Is simple presonalize the template and the messages

example - in the new proposed discovery pages I have assigned an id 'main-errors' in the template:

from bs4 import BeautifulSoup 
soup = BeautifulSoup(open("static/error_page.html", "r").read()) 
errors = {'1.html': 'message_1', '2.html': 'message_2', '3.html': '<p>message 3</p>'} # or better a json file
for key in errors.keys():
  soup.find(id='main-error').string = errors[key]
  open(key, "w").write(soup.prettify())

With six code line we can create all errors pages and is simple add this function on startup script
What don't you think? is it a solution or a complication?

Incompatibilità python alpine3.16

Ci siamo accorti che l'immagine docker con l'update v1.0.1-1, che introduce la versione di alpine 3.16, rompe la compatibilità con python 3.8 in quanto la versione correntemente installata è la 3.10.

come riprodurre:

  • cd compose-Satosa-Saml2Spid
  • docker compose up
* Starting uWSGI 2.0.21 (64bit) on [Tue Jul 25 16:21:30 2023] *
compiled with version: 11.2.1 20220219 on 20 July 2023 14:47:18
os: Linux-5.19.0-46-generic [#47](tg://search_hashtag?hashtag=47)~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Jun 21 15:35:31 UTC 2
nodename: 9dc0569bf802
machine: x86_64
clock source: unix
detected number of CPU cores: 3
current working directory: /satosa_proxy
detected binary path: /usr/bin/uwsgi
!!! no internal routing support, rebuild with pcre support !!!
* WARNING: you are running uWSGI without its master process manager *
your memory page size is 4096 bytes
detected max file descriptor number: 1048576
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uwsgi socket 0 bound to TCP address [0.0.0.0:10000](https://0.0.0.0:10000/) fd 3
Python version: 3.10.12 (main, Jun  9 2023, 02:30:25) [GCC 11.2.1 20220219]
Python main interpreter initialized at 0x7f4645452960
python threads support enabled
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 562880 bytes (549 KB) for 8 cores
* Operational MODE: preforking+threaded *
failed to open python file /usr/lib/python3.8/site-packages/satosa/[wsgi.py](https://wsgi.py/)
unable to load app 0 (mountpoint='') (callable not found or import error)
* no app loaded. going in full dynamic mode *
* uWSGI is running in multiple interpreter mode *
spawned uWSGI worker 1 (pid: 182, cores: 2)
spawned uWSGI worker 2 (pid: 183, cores: 2)
spawned uWSGI worker 3 (pid: 184, cores: 2)
spawned uWSGI worker 4 (pid: 185, cores: 2)

Satosa-Saml2Spid v2.0

  • example_sp/djangosaml2_sp preconfigured for demo in docker-compose, with a bootstrap italia template
  • script that finds all localhosts throughout the project (docker-example) and replaces them with the given FQDN
  • fix docker compose ENV variable loading -> remove setup scripts of string replacement. Remove apply_conf.py and use placeholders/tags in yaml to load values from docker ENV (like documented by @MdreW and @scolagreco)
  • add support and pre-configuration for pyeudiw
  • add pyeudiw documentation ref in the README/Setup sections
  • documentation review (WiP in branch eudi)

Error in requirements.txt

On pip install -r repository/requirements.txt I receive the follow error:

ERROR: jinja2 3.0.1 has requirement MarkupSafe>=2.0, but you'll have markupsafe 1.1.1 which is incompatible.

Errors page single with localization (js version)

New proposal for errors page.

Use the same errors page for all errors and add more detail and localization with javascript.

For security reason the errors details can't be add from with a simple string, but must be decoded from the error's code.

With a javascript we read a json with all codes and his error details and add this in the error box.

Vantage:

  • we an remove jinja from requisites
  • We can load the errors messages and other details from simple a json file
  • Is simple presonalize the template and the messages
  • don't require an asyncronous page generation (like #82)

example json:

en:
  '20':  ''Destination is not valid'
  '30': 'Issuer NameFormat is invalid'
it:
  '20': 'Destinazione di ritorno non valida'
  '30': 'issuer non valido'

path error for satosa configuration in readme

During the installation, the configuration files are copied from the repository with the command cp -R repository/example/* .
with this command the correct path is without example.

es: proxy_conf.yaml and not example/proxy_conf.yaml

OIDC rp client error

with instruction present in jwtconnect_python_oidcrp directory, return this error:

python3 -m flask_rp.wsgi ../../sso_isprambiente_it.json 
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/ranaldi/tmp/satosa_tmp/jwt/JWTConnect-Python-OidcRP/example/flask_rp/wsgi.py", line 30, in <module>
    context = create_context(dir_path, _web_conf)
  File "/home/ranaldi/tmp/satosa_tmp/jwt/env/lib/python3.10/site-packages/oidcrp/util.py", line 467, in create_context
    _fname = lower_or_upper(config, "server_cert")
  File "/home/ranaldi/tmp/satosa_tmp/jwt/env/lib/python3.10/site-packages/oidcrp/util.py", line 410, in lower_or_upper
    res = config.get(param.lower(), default)
AttributeError: 'NoneType' object has no attribute 'get'

metadata url ambiguous

Every url that start with metadata url is a metadata url.
Example: https://sso.test.it/Saml2IDP/metadata is like https://sso.test.it/Saml2IDP/metadataboh/everything_wrong

I think that is not pretty...

Apertura pagina di scelta

Richiesta di supporto.

Ho utilizzato il plugin satosa.micro_services.ldap_attribute_store.LdapAttributeStore
ma la ricerca per codice fiscale nel nostro LDAP restituire più risultati con ruoli (realm) diversi ad esempio staff e stud.

Come si può aprire una pagina di scelta dei record di LDAP dal plugin di LdapAttributeStore o da MultiLdapAttributeStore, esiste un esempio?

Improve CIE support

CIE Backend is a variation of SPID Backend but CIE don't have an unique code like "spidCode" to set an "user_id".
I propose to use "fiscalNumber" for valorize "edupersontargetedid" (default user_id ) when "eduPersonTargetedID", "eduPersonTargetedId" and "spidCode" haven't a value.
With this solution CIE can gain an secure and unique "user_id"

Old repository in Readme

the setup guide contain the old official repository git clone https://github.com/peppelinux/Satosa-Saml2Spid.git repository

bootstrap italia 2

Hi @peppelinux,
I would like to update static pages and errors pages with bootstrap italia 2.x.
If is ok for you I can migrate from spid-button to ita-button (spid button is not compatible with bootstrap italia 2).
If is usefull I can add the eudi wallet button to ita-button.
What do you think about this idea?

New SPID idp

default IDP metadata are old and target_based_routing.yml must be updated

Accesso con spid e persone giuridiche

Sarebbe utile implementare la gestione dell'accesso tramite spid di persone giuridiche.

Aggiornamento delle authnRequests per la gestione dell'attributo "Purpose" (P,LP,PG,PF,PX):
<samlp:Extensions xmlns:spid=" [https://spid.gov.it/saml‐extensions](https://spid.gov.it/saml%E2%80%90extensions) "> [...] <spid:Purpose>P</spid:Purpose> [...] </samlp:Extensions>

Estensione degli attributi:

  • Ragione o denominazione sociale
  • Sede legale
  • Codice fiscale Persona Giuridica
  • Partita IVA

Gestione dell'errore "nr30" al tentativo dell’utente di utilizzare una tipologia di identità digitale diversa da quanto richiesto dal SP.

CIE Backend

Starting from a SAML2 vanilla backend like the default one available in Satosa
https://github.com/italia/Satosa-Saml2Spid/blob/master/example/plugins/backends/saml2_backend.yaml

i believe that it would be trivial to configure, without any code customization, a CIE backend and also have it in the TargetRouting map, here:
https://github.com/italia/Satosa-Saml2Spid/blob/master/example/plugins/microservices/target_based_routing.yaml

@MdreW are you looking also for a CIE backend?
That's a good issue for newcomers if you agree

Configurazione iniziale automatica

Con l'arrivo di CIE e probabilmente anche di IDEM la configurazione dei backend puo` diventare un po lunga e ripetitiva.
Faccio una proposta: sostituire le chiavi descrittive di configurazione nei file yaml, es:

organization:
  displayname: 
    - saml authentication proxy'
    - it

con dei nomi brevi chiusi con un carattere predefinito, es:

organization:
  displayname: 
    - %/displayname%
    - %lang%

Poi con un semplice bash script andiamo a sostituire le stringhe in tutte le configurazioni con delle variabili d'ambiente, es:

sed -i "s/%displayname%/$displayname/g" plugin/**/*
sed -i "s/%lang%/$lang/g" plugin/**/*

In questo modo con un semplice eseguibile si puo configurare una discreta parte del sistema, quantomeno quella piu ripetitiva.
Essendo uno script eseguibile a piacere non influirebbe su chi volesse fare configurazioni piu` particolari o manuali.

Richiedere differenti "AttributeConsumingService" in base alla decisione del client

Ciao. Sto lavorando ad un progetto per un proxy OIDC e/o SAML verso gli IDP Spid (quindi backend SAML) ed ho preso il vostro progetto come traccia.
Avrei l'esigenza che i client che contattano i frontend possano richiedere più o meno attributi dell'utente (visto che per i privati alcune informazioni rilasciate dagli idp sono gratuite ed altre no).

Ho letto la documentazione di SATOSA. In alcuni punti è un po' lacunosa quindi mi sono guardato anche il codice di SATOSA e delle sue dipendenze. Non definirei Python il mio linguaggio di punta ma penso di aver capito grosso modo quanto letto e non ho trovato un modo per risolvere la mia esigenza. Quindi ho optato per estendere le funzionalità del vostro spidSaml2 backend.

La mia idea era quindi di definire un mapping tra richiesta arrivata al frontend e Authn request che poi parte dal backend SAML.
Nel concreto stavo pensando di:

  • definire nel backend multipli AttributeConsumingService, ad esempio uno "base" e uno "full". Questa parte dovrei aver capito come farla customizzando un po' il file di configurazione del backend (questo tra l'altro dovrebbe anche permettere di configurare gli ACS per eidas, quelli con index 99 e 100 che al momento sono hardcoded);
  • prevedere degli scope e ACS nei frontend, ad esempio per OIDC "profile" e "full_profile", per SAML "base" e "full";
  • ora dovrei in qualche modo nel metodo authn_request del spidsaml2.py capire cosa mi è arrivato in ingresso e (probabilmente passando sempre dal file di configurazione del backend) prevedere un mapping del tipo
[...]
attribute_mapping:
    OIDC:
        # <backend> : <frontend>
        'profile': 'base' (o invece di profile solo '' o default per definire il mapping predefinito ed essere coerente con altri tipi di configurazioni che ho visto in SATOSA)
        'full_profile': 'full'
    SAML:
        'base': 'base'
        'full': 'full'

Secondo voi ha senso? Oppure esiste già qualche feature che mi è sfuggita che risolve una parte e/o tutti i miei problemi?
Per le modifiche che invece vi sembrano sensate potrei anche prevedere una PR invece.

[Backend] SPID/CIE id OIDC support

Assumptions

  1. Satosa-Saml2Spid support OIDC and OAuth2 in its Frontend called satosa-oidcop
  2. SPID and CIE id now supports OIDC, following OpenID Federation 1.0 and iGov
  3. The italian implementation profile adopts security best practices and requires a full compliances to both SPID and CIE id test plans

Requirements

  1. Satosa-Saml2Spid needs a OIDC RP backend complaiant to SPID and CIE id
  2. the SPID and CIE OIDC Backed have to support OIDC Federation 1.0
  3. The authentication button in the discovery page should be built automatically, following the OIDC Federation API and the list of Metadata (if local files or MQD query to /entities)

E' una soluzione completa e funzionante?

Ciao a tutti, sto cercando una soluzione per integrare lo spid nella mia applicazione java spring boot e reactjs. Questa soluzione andrebbe bene nel mio caso? E' attualmente completa e funzionante? Grazie

Homogeneous environment for dockerfile and .env

docker-compose call some configuration from .env file and some other are called locally. This process require more time to find the configuration.
If we want use .env file I propose to set all the configuration with an environment with a default. Example

environment:
  MONGO_INITDB_DATABASE: ${MONGO_DB:-oidcop}
  MONGO_INITDB_ROOT_USERNAME: "${MONGO_DBUSER:-satosa}"
  MONGO_INITDB_ROOT_PASSWORD: "${MONGO_DBPASSWORD:-password}"

import keys from enviroments errors

Hi all,
I have find two errors relative of the satosa keys import in run.sh script.

if [[ -v SATOSA_PRIVATE_KEY && -v SATOSA_PUBLIC_KEY ]]; then
  echo $SATOSA_PRIVATE_KEYS > pki/privkey.pem
  echo $SATOSA_PUBLIC_KEY > pki/cert.pem
  echo "Satosa keys imported"
else
  echo "satosa has loaded default keys"
fi
  1. at first line is checked that the enviroments SATOSA_PRIVATE_KEY and SATOSA_PUBLIC_KEY are present but in second line is imported SATOSA_PRIVATE_KEYS, i think thath is a my old typo error.
  2. when echo print an anviroment read the new line symbol as a space and this make not valid the certificate.

Fix

Make omogeneus the enviroments name ad insert the echo's enviroments in duble apex for respect the new lines

if [[ -v SATOSA_PRIVATE_KEY && -v SATOSA_PUBLIC_KEY ]]; then
  echo "$SATOSA_PRIVATE_KEY" > pki/privkey.pem
  echo "$SATOSA_PUBLIC_KEY" > pki/cert.pem
  echo "Satosa keys imported"
else
  echo "satosa has loaded default keys"
fi

I write a pull request for this errors

A better pyff example

that's ready to be implemented with this
https://github.com/peppelinux/spid-pyff

We just have to fill some examples with httpd static serve with nginx and a lua script for urlencoded values as lookup parameters.
pyff stores its metadata in sha1, as currently shown here:

location ~ /entities/\{sha1\}(.*) {

Using a httpd script will give us a faster approach to deploy a MDQ server, otherwise we should implement a real MDX/MDQ server like:

@MdreW does this sounds good to you?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.