Project

spid-es

0.0
No commit activity in last 3 years
A long-lived project that still receives updates
SAML toolkit for Ruby programs to integrate with SPID
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

= 0.1.1
>= 1.6.7.2
~> 2.3
 Project Readme

SPID Euro Servizi

La libreria è un fork della libreria Ruby SAML e serve per l'integrazione di un client (Service Provider) con l'autenticazione SPID (Sistema Pubblico di Identità Digitale) Utilizza lo standard SAML 2 come previsto dalla normativa (Regole tecniche v1. http://www.agid.gov.it/sites/default/files/circolari/spid-regole_tecniche_v1.pdf)

Fase iniziale

Azione di partenza in cui viene creata la request da inviare all'idp e viene fatto un redirect all'identity provider.

    def init
        #creo un istanza di Spid::Saml::Authrequest
        saml_settings = get_saml_settings
        #create an instance of Spid::Saml::Authrequest
        request = Spid::Saml::Authrequest.new(saml_settings)
        auth_request = request.create
        # Based on the IdP metadata, select the appropriate binding 
        # and return the action to perform to the controller
        meta = Spid::Saml::Metadata.new(saml_settings)
        signature = get_signature(auth_request.uuid,auth_request.request,"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")
        sso_request = meta.create_sso_request( auth_request.request, {  :RelayState   => request.uuid,
                                                                        :SigAlg       => "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
                                                                        :Signature    => signature } )
        redirect_to sso_request
    end

Generazione della firma

    def get_signature(relayState, request, sigAlg)
        #url encode relayState
        relayState_encoded = escape(relayState)
        #deflate e base64 della samlrequest
        deflate_request_B64 = encode(deflate(request))
        #url encode della samlrequest
        deflate_request_B64_encoded = escape(deflate_request_B64)
        #url encode della sigAlg
        sigAlg_encoded = escape(sigAlg)
        querystring="SAMLRequest=#{deflate_request_B64_encoded}&RelayState=#{relayState_encoded}&SigAlg=#{sigAlg_encoded}"
        #puts "**QUERYSTRING** = "+querystring
        digest = OpenSSL::Digest::SHA256.new(querystring.strip) #sha2 a 256
        chiave_privata = xxxxxx  #path della chiave privata con cui firmare 
        pk = OpenSSL::PKey::RSA.new File.read(chiave_privata) #chiave privata
        qssigned = pk.sign(digest,querystring.strip)
        Base64.encode64(qssigned).gsub(/\n/, "")
    end

Questo metodo è l'endpoint impostato a livello di metadata del service provider come 'assertion consumer', riceve la response saml con i dati di registrazione fatta su SPID dagli utenti.

    def assertion_consumer
        #id dell' idp che manda response (es: 'infocert','poste')
        provider_id = @request.params['ProviderID']
        #response saml inviata dall'idp
        saml_response = @request.params['SAMLResponse'] 
        if !saml_response.nil? 
            #assegno i settaggi
            settings = get_saml_settings
            #creo un oggetto response
            response = Spid::Saml::Response.new(saml_response)
            #assegno alla response i settaggi
            response.settings = settings
            #estraggo dal Base64 l'xml
            saml_response_dec = Base64.decode64(saml_response)
            #puts "**SAML RESPONSE DECODIFICATA: #{saml_response_dec}"

            #validation of response
            if response.is_valid? 
                attributi_utente = response.attributes
                ...
            else
                #autenticazione fallita!
            end
      end
    end  

Questo metodo va a impostare le varie configurazioni che servono per connettersi ad un idp. ( NB: nel caso di SPID ci sono vari idp (Poste, TIM, Info Cert) )

    def get_saml_settings  
        settings = Spid::Saml::Settings.new
        settings.assertion_consumer_service_url    #= ...String, url dell' assertion consumer al quale arriva la response dell' idp.
        settings.issuer                            #= ...String, host del service provider o url dei metadata.
        settings.sp_cert                           #= ...String, path del certificato pubblico in formato pem.
        settings.sp_private_key                    #= ...String, path della chiave privata in formato pem.
        settings.single_logout_service_url         #= ...String, url del servizio di logout dell'idp.
        settings.sp_name_qualifier                 #= ...String, nome qualificato del service provider o url dei metadata.
        settings.idp_name_qualifier                #= ...String, nome qualificato dell' identity provider o url dei metadata dell' idp.
        settings.name_identifier_format            #= ...Array, formato di nomi ( impostare: ["urn:oasis:names:tc:SAML:2.0:nameid-format:transient"] ).
        settings.destination_service_url           #= ...String, url del servizio per l'identity provider, usato come proxy per il sso.
        settings.single_logout_destination         #= ...String, url di destinazione per la request logout. 
        settings.authn_context                     #= ...Array, tipi di autorizzazioni permesse (impostare: ["urn:oasis:names:tc:SAML:2.0:ac:classes:Smartcard", 
                                                                "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"]).
        settings.requester_identificator           #= ...Array con id dei richiedenti (non usato).
        settings.skip_validation                   #= ...Bool, imposta se evitare la validazione della response o delle asserzioni (false).
        settings.idp_sso_target_url                #= ...String, url target del sso dell' identity provider.
        settings.idp_metadata                      #= ...String, url dei metadata dell' idp.
        settings.requested_attribute               #= ...Array, contiene i nomi dei campi richiesti dal servizio nei metadata.
        settings.metadata_signed                   #= ...String, imposta se firmare i metadata.
        settings.organization                      #= ...Hash, contiene nome breve (org_name), nome esteso (org_display_name) e url (org_url) 
                                                               dell' organizzazione fornitore di servizi.
        settings
    end  

Service Provider Metadata

Per una relazione sicura con l'idp, il Service Provider deve fornire i metadata in formato xml. La classe Spid::Saml::Metadata legge i settaggi e fornisce l'xml richiesto dagli idp.

    def sp_metadata
        settings = get_saml_settings
        meta = Spid::Saml::Metadata.new
        
        @response.headers['Content-Type'] = 'application/samlmetadata+xml'
        $out << meta.generate(settings)
    end