NAME

Dancer2::Plugin::SPID - SPID authentication for Dancer2 web applications

VERSION

version 0.11

SYNOPSIS

use Dancer2;
use Dancer2::Plugin::SPID;

hook 'plugin.SPID.after_login' => sub {
    # log assertion:
    info "User " . spid_session->nameid . " logged in";
    info "SPID Assertion: " . spid_session->assertion_xml;
};

hook 'plugin.SPID.after_logout' => sub {
    debug "User " . spid_session->nameid . " logged out";
};

dance;

ABSTRACT

This Perl module is a plugin for the Dancer2 web framework. It allows developers of SPID Service Providers to easily add SPID authentication to their Dancer2 applications. SPID is the Italian digital identity system, which enables citizens to access all public services with single set of credentials.

This module provides the highest level of abstraction and ease of use for integration of SPID in a Dancer2 web application. Just set a few configuration options and you'll be able to generate the HTML markup for the SPID button on the fly (to be completed) in order to place it wherever you want in your templates. This plugin will automatically generate all the routes for SAML bindings, so you don't need to perform any plumbing manually. Hooks are provided for customizing behavior.

See the example/ directory for a demo application.

This is module is based on Net::SPID which provides the lower-level framework-independent implementation of SPID for Perl.

CONFIGURATION

Configuration options can be set in the Dancer2 config file:

plugins:
  SPID:
    sp_entityid: "https://www.prova.it/"
    sp_key_file: "sp.key"
    sp_cert_file: "sp.pem"
    sp_assertionconsumerservice:
      - "http://localhost:3000/spid-sso"
    sp_singlelogoutservice:
      "http://localhost:3000/spid-slo": "HTTP-Redirect"
    idp_metadata_dir: "idp_metadata/"
    login_endpoint: "/spid-login"
    logout_endpoint: "/spid-logout"
    sso_endpoint: "/spid-sso"
    slo_endpoint: "/spid-slo"
sp_entityid

(Required.) The entityID value for this Service Provider. According to SPID regulations, this should be a URI.

sp_key_file

(Required.) The absolute or relative file path to our private key file.

sp_cert_file

(Required.) The absolute or relative file path to our certificate file.

sp_assertionconsumerservice

An arrayref with the URL(s) of our AssertionConsumerService endpoint(s). It is used for metadata generation and for validating the Destination XML attribute of the incoming responses.

sp_singlelogoutservice

A hashref with the URL(s) of our SingleLogoutService endpoint(s), along with the specification of the binding. It is used for metadata generation and for validating the Destination XML attribute of the incoming responses.

sp_attributeconsumingservice

(Optional.) An arrayref with the AttributeConsumingServices to list in metadata, each one described by a servicename and a list of attributes. This is optional as it's only used for metadata generation.

sp_attributeconsumingservice:
  - servicename: "Service 1"
    attributes:
      - "fiscalNumber"
      - "name"
      - "familyName"
      - "dateOfBirth"
idp_metadatadir

(Required.) The absolute or relative path to a directory containing metadata files for Identity Providers in XML format (their file names are expected to end in .xml).

login_endpoint

(Required.) The relative HTTP path we want to use for the SPID button login action. A route handler will be created for this path that generates an AuthnRequest and redirects the user to the chosen Identity Provider using the HTTP-Redirect binding.

logout_endpoint

(Required.) The relative HTTP path we want to use for the logout action. A route handler will be created for this path that generates a LogoutRequest and redirects the user to the current Identity Provider using the HTTP-Redirect binding.

sso_endpoint

(Required.) The relative HTTP path we want to expose as AssertionConsumerService. This must match the URL advertised in the Service Provider metadata.

slo_endpoint

(Required.) The relative HTTP path we want to expose as SingleLogoutService. This must match the URL advertised in the Service Provider metadata.

metadata_endpoint

(Optional.) The relative HTTP path we want to use for publishing our SP metadata. If omitted, no endpoint will be exposed.

jwt_secret

(Optional.) The secret using for encoding relay state data.

KEYWORDS

The following keywords are available.

spid_session

This keyword returns the current Net::SPID::Session object if any. It can be used to check whether we have an active SPID session.

if (spid_session) {
    template 'user';
} else {
    template 'index';
}

This keyword is also available in templates, so you can use it for accessing attributes:

Attribute: [% spid_session.attributes.MyAttribute %]

TEMPLATE KEYWORDS

spid_button

This keyword generates the HTML markup for the SPID login button. Just place it wherever you want the button to appear:

[% spid_button(level => 2, redirect => '/') %]

The following arguments can be supplied:

level

(Optional.) The required SPID level, expressed as an integer (1, 2, or 3). If omitted, 1 will be requested.

redirect

(Optional.) The relative HTTP path where user will be redirected after successful login. If omitted, / will be used.

spid_login

This keyword will return the URL for directing the user to the current Identity Provider in order to perform a SPID level upgrade. The URL is preformatted with the HTTP-Redirect AuthnRequest. It accepts the same arguments described for spid_button. You must check whether the user has an active SPID session before using it.

[% IF spid_session %]
    <a href="[% spid_login(level => 2, redirect => '/') %]">Upgrade to L2</a>
[% END %]

spid_logout

This keyword will return the URL for initiating a Single Logout by directing the user to the current Identity Provider with a LogoutRequest. You must check whether the user has an active SPID session before using it. It accepts an optional redirect argument as described for spid_button.

[% IF spid_session %]
    <a href="[% spid_logout(redirect => '/') %]">Logout</a>
[% END %]

HOOKS

before_login

This hook is called when the login endpoint is called (i.e. the SPID button is clicked or user visited the upgrade URL returned by spid_login) and the AuthnRequest is about to be crafted.

hook 'plugin.SPID.before_login' => sub {
    info "User is initiating SSO";
};

after_login

This hook is called after the user returns to us after a successful SPID login.

hook 'plugin.SPID.after_login' => sub {
    info "User " . spid_session->nameid . " logged in";

    # Here you might want to create the user in your local database or do more
    # things for initializing the session. Make sure everything you do here is
    # idempotent.

    # Log assertion as required by the SPID rules.
    # Warning: in order to comply with rules, this should be logged in a more
    # permanent way than regular Dancer logs, so you'd better use a database
    # or a dedicated log file.
    info "SPID Assertion: " . spid_session->assertion_xml;
};

after_failed_login

This hook is called after the user returns to us after a failed SPID login. The SAML StatusCode value is supplied as first argument. You can use this hook in order to display the correct error message according the error.

hook 'plugin.SPID.after_failed_login' => sub {
    my $statuscode = shift;
    info "SPID login failed: $statuscode";
};

before_logout

This hook is called when the logout endpoint is called and the LogoutRequest is about to be crafted.

hook 'plugin.SPID.before_logout' => sub {
    debug "User " . spid_session->nameid . " is about to logout";
};

after_logout

This hook is called when a SPID session is terminated. Note that this might be triggered also when user initiated logout from another Service Provider or directly within the Identity Provider, thus without calling our logout endpoint and the before_logout hook). spid_session will be cleared after this hook is executed, so you can use it.

hook 'plugin.SPID.after_logout' => sub {
    my $success = shift;  # 'success' or 'partial'
    debug "User " . spid_session->nameid . " logged out";
};

AUTHOR

Alessandro Ranellucci <aar@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2018 by Alessandro Ranellucci.

This is free software, licensed under:

The (three-clause) BSD License