catalyst / moodle-auth_saml2

SAML done 100% in Moodle, fast, simple, secure
https://moodle.org/plugins/auth_saml2
72 stars 134 forks source link

Proposed improvements to multiple IDP handling #290

Open mark-webster-catalyst opened 6 years ago

mark-webster-catalyst commented 6 years ago
 1  Add 2 new DB tables
     1.1  auth_saml2_idps
         1.1.1  Fields
             1.1.1.1  id [type int, notnull true, sequence true]
             1.1.1.2  name [type char, notnull true]
             1.1.1.3  shortname [type char, notnull true]
             1.1.1.4  enabled [type int, notnull true, default 1]
         1.1.2  Keys
             1.1.2.1  primary [type primary, field id]
             1.1.2.2  shortcode_unique [type unique, field shortcode]
     1.2  auth_saml2_idpsettings
         1.2.1  Fields
             1.2.1.1  id [type int, notnull true, sequence true]
             1.2.1.2  idpid [type int, notnull true]
             1.2.1.3  key [type char, notnull true]
             1.2.1.4  value [type text]
         1.2.2  Keys
             1.2.2.1  primary [type primary, field id]
             1.2.2.2  idpid_key [type unique, fields idpid + key]
 2  Replace settings page
     2.1  Show tabulated list of configured IDPs
         2.1.1  Table row shows IDP Name and buttons for edit, dis/enable, set default, delete
         2.1.2  Order is alphabetical
     2.2  Initially populated by “SP and IDP Defaults”
         2.2.1  Contains setting page as it currently is (rearranged to separate SP settings from IDP), minus metadata and name. Settings here will be used as defaults for all other configured IDPs.
         2.2.2  Default setting will be saved to the auth_saml2_idpsettings table with idpid of 0
             2.2.2.1  Deletion method will contain checks to ensure idpid 0 cannot be deleted
         2.2.3  The SP settings will be used for all IDPs (SP metadata, certificates etc.)
     2.3  Show “Add New” button
         2.3.1  Goes to settings page as it is now, minus SP settings. Default values are those set in 2.2.1
 3  Enable “autologin” URL param
     3.1  Uses shortcode to pick which IDP will be used for logging in via SSO
     3.2  If no “autologin” param is present, the selected “default” (2.1.1) IDP will be used
         3.2.1  Invalid value will show an error message and default IDP will be selected
 4  Login page IDP selection
     4.1  Login page will have a link to “Change IDP”
     4.2  List of all available IDPs will be hidden until link (4.1) is clicked
         4.2.1  Selecting an alternative IDP will immediately log in using that IDP
brendanheywood commented 5 years ago

I wish moodle just could have multiple instances of auth plugins ...

chrisptree commented 5 years ago

For the first version, I propose, instead of registering many IdPs, to allow multiple IdP definitions in the XML and use an external IdP discovery service. The XML must contain at least one IdP. Here is an example of a XML containing more than one IdP definition that you can find the complete list at http://caf-shib2ops.ca/CoreServices/testbed/caf_test_fed_unsigned.xml

<md:EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xi="http://www.w3.org/2001/XInclude" 
  xmlns:init="urn:oasis:names:tc:SAML:profiles:SSO:request-init" 
  xmlns:ukfedlabel="http://ukfederation.org.uk/2006/11/label" 
  xmlns:elab="http://eduserv.org.uk/labels" 
  xmlns:wayf="http://sdss.ac.uk/2006/06/WAYF" 
  xmlns:idpdisc="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol"   
  xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi" 
  xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute" 
  xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" 
  xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
  xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="prefix-20190508142001" 
  Name="urn:mace:caf-fcga.ca:testfed" validUntil="2019-05-08T14:20:01Z">
<md:EntityDescriptor entityID="https://idp.canarie.ca/idp/shibboleth">
......
</md:EntityDescriptor>
<md:EntityDescriptor entityID="https://id.canarie.ca/simplesaml/saml2/idp/metadata.php">
.....
</md:EntityDescriptor>
</md:EntitiesDescriptor>

Each of entityDescriptor contains IdP's metadata to allow authentication from many IdP. Here is the authentication flow

  1. The user opens a web browser and accesses the Service Provider
  2. The user is redirected to the Discovery Service by the Service Provider Consequently, the web browser sends a new request to the Discovery Service
  3. The Discovery Service responds with the web page that allows the user to select an Identity Provider
  4. On the Discovery Service page, the user submits the Identity Provider selection
  5. The Discovery Service sends a redirect to the SP return destination, including the IdP selection
  6. The browser is redirected to the Service Provider by the Discovery Service
  7. The session initiator of the Service Provider creates an authentification request and returns it within an auto-submit-post-form to the browser. The browser posts the SAML AuthN Request automatically to the Identity Provider using JavaScript
  8. The Identity Provider checks the authentication request. Because the user hasn’t yet been authenticated, the Identity Provider sends a redirect to the appropriate login page (usually: Username/Password)
  9. The user types his username and password credentials and submits them to the Identity Provider
  10. The Identity Provider verifies the credentials. If authentification succeeds, the IdP issues an assertion for the SP and returns it within an autosubmit-post-form to the browser. The web browser immediately posts the SAML Assertion to the Service Provider with use of JavaScript automatically. The Service Provider processes the SAML assertion including the authentication and attribute statements
  11. Finally, the Service Provider starts a new session for the user and redirects the user to the previously requested resource. Now, the user is authenticated and gains access to the resource, depending on the access rules configured for the resource
peterspicer-catalyst commented 5 years ago

The current version today certainly used to actually support multiple IDPs by listing the URLs of the IDP's metadata, and hooking that into the list of IDPs etc. to log in with, though it wasn't obvious and it didn't support different mappings per IDP.

I have to be honest, while integration with a DS could be a useful improvement, it's actually not one we've been asked about, because all of the cases that we've done with multiple IDPs, there isn't a suitable discovery service to cover all the IDPs, and listing the multiple IDPs explicitly seems to work much better. (Especially in the one extreme case where we currently have 21 IDPs configured, with another 20 or so to come)

As for Mark's proposed patch, this was long since implemented mostly as described and is in use in production on several customers now, but it needs patching and ideally being merged. I'm in the middle of rebasing the patch against master, but I'd be interested to know whether I should submit it as smaller incremental patches or one big patch.

brendanheywood commented 5 years ago

@peterspicer-catalyst probably smaller ones are easier to review