Docker Shibboleth IDP

Darrera actualització: 24-01-2015

Objectiu

  • Donar una resposta a l’autenticació d’aplicacions a Cloud Públic, que s’integri amb l’Active Directori Corporatiu

  • Tecnològicament s’opta per containeritzar la solució, per facilitat de la configuració, proves i portabilitat de la solució

Imatges utilitzades:

IdP - Identity Provider (servidor)

  1. Construcció de la imatge a partir del projecte anterior:

     $ docker build -t shibboleth-idp . 
    

    NOTA: abans de crear la imatge, tenir present el “host” que resoldrà el contenidor que arrenqui l’IDP. Paràmetre: -Didp.host.name=localhost

  2. Per a personalitzar l’entorn IDP, és necessari arrencar el contenidor a partir de la imatge anterior amb un volum compartit amb el host per a poder recuperar els directoris de configuració que ens interessen.

     $ docker run -d -p 443:443 -p 8443:8443 --name shibboleth-idp -v /home/shibboleth/idp/conf:/external-mount shibboleth-idp
    

    Mentre no es disposi de contenidors i balancejadors amb IP i DNS assignats, pot ser necessari afegir els hosts a resoldre amb el flag –add-host de Docker.

  3. Copiar els directoris que ens interessen del contenidor i que es troben a /opt/shibboleth-idp (conf, credentials, messages, metadata, views, webapp). Amb aquests directoris podrem personalitzar la nostra aplicació IDP

     $ docker exec shibboleth-idp cp -R /opt/shibboleth-idp/conf/ /external-mount
     $ docker exec shibboleth-idp cp -R /opt/shibboleth-idp/credentials/ /external-mount
     $ docker exec shibboleth-idp cp -R /opt/shibboleth-idp/messages/ /external-mount
     $ docker exec shibboleth-idp cp -R /opt/shibboleth-idp/metadata/ /external-mount
     $ docker exec shibboleth-idp cp -R /opt/shibboleth-idp/views/ /external-mount
     $ docker exec shibboleth-idp cp -R /opt/shibboleth-idp/webapp/ /external-mount
    
  4. S’ha de modificar el fitxer /container_scripts/import.sh dins el projecte “Docker Identity Provider - IdP” per a que importi la webapp i messages, que no estan inclosos.

  5. Fitxers de configuració i dades de configuració clau:

    1. /conf/idp.properties

      • idp.entityID= https://[host]/idp/shibboleth
    2. /conf/metadata-providers.xml, amb el mecanisme que es vulgui per a recuperar les dades dels SP. Per exemple, per http amb filesystem backup:

       <MetadataProvider
           id="gencatMetadata"
           xsi:type="FileBackedHTTPMetadataProvider"
           metadataURL="http://[host]/sp-metadata.xml"
           backingFile="%{idp.home}/metadata/sp-metadata.xml">
       </MetadataProvider>
      

      Si l’entorn on es posen els contenidors no té visibilitat directe a internet, es pot configurar un proxyhost i proxyport per a recuperar el fitxer de metadades. Exemple:

       <MetadataProvider
           id="gencatMetadata"
           xsi:type="FileBackedHTTPMetadataProvider"
           metadataURL="http://[host]/sp-metadata.xml"
           backingFile="%{idp.home}/metadata/sp-metadata.xml"
       	proxyHost="100.64.227.11"
           proxyPort="3128"
           >
       </MetadataProvider>
      
    3. /conf/attribute-resolver.xml

       <resolver:AttributeDefinition id="employeeId" xsi:type="ad:PrincipalName">
           <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:mace:dir:attribute-def:employeeId" encodeType="false" />
           <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:0.9.2342.19200300.100.1.1" friendlyName="employeeId" encodeType="false" />
       </resolver:AttributeDefinition>
      
       <resolver:AttributeDefinition id="mail" xsi:type="ad:Simple" sourceAttributeID="mail">
           <resolver:Dependency ref="myLDAP" />
           <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:mace:dir:attribute-def:mail" encodeType="false" />
           <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:0.9.2342.19200300.100.1.3" friendlyName="mail" encodeType="false" />
       </resolver:AttributeDefinition>
      
       <resolver:AttributeDefinition id="CODIINTERN" xsi:type="ad:Simple" sourceAttributeID="sAMAccountName">
           <resolver:Dependency ref="myLDAP" />
           <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:mace:dir:attribute-def:sAMAccountName" encodeType="false" />
           <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:0.9.2342.19200300.100.1.99" friendlyName="CODIINTERN" encodeType="false" />
       </resolver:AttributeDefinition>
      
       <resolver:AttributeDefinition id="UNITAT_MAJOR" xsi:type="ad:Simple" sourceAttributeID="department">
           <resolver:Dependency ref="myLDAP" />
           <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:mace:dir:attribute-def:department" encodeType="false" />
           <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:0.9.2342.19200300.100.1.2" friendlyName="UNITAT_MAJOR" encodeType="false" />
       </resolver:AttributeDefinition>
      
       <resolver:AttributeDefinition id="UNITAT_MENOR" xsi:type="ad:Simple" sourceAttributeID="company">
           <resolver:Dependency ref="myLDAP" />
           <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:mace:dir:attribute-def:company" encodeType="false" />
           <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:0.9.2342.19200300.100.1.98" friendlyName="UNITAT_MENOR" encodeType="false" />
       </resolver:AttributeDefinition>
      
       <resolver:AttributeDefinition id="GICAR" xsi:type="ad:Template">
           <resolver:Dependency ref="employeeId" />
           <resolver:Dependency ref="mail" />
           <resolver:Dependency ref="CODIINTERN" />
           <resolver:Dependency ref="UNITAT_MAJOR" />
           <resolver:Dependency ref="UNITAT_MENOR" />
           <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="https://gencat.cat/GICAR" friendlyName="GICAR" />
           <ad:Template>
             <![CDATA[
                  CODIINTERN=${CODIINTERN};NIF=${employeeId};EMAIL=${mail};UNITAT_MAJOR=${UNITAT_MAJOR};UNITAT_MENOR=${UNITAT_MENOR}
             ]]>
           </ad:Template>
           <ad:SourceAttribute>employeeId</ad:SourceAttribute>
           <ad:SourceAttribute>mail</ad:SourceAttribute>
           <ad:SourceAttribute>CODIINTERN</ad:SourceAttribute>
           <ad:SourceAttribute>UNITAT_MAJOR</ad:SourceAttribute>
           <ad:SourceAttribute>UNITAT_MENOR</ad:SourceAttribute>
       </resolver:AttributeDefinition>
      
       <!-- ========================================== -->
       <!--      Data Connectors                       -->
       <!-- ========================================== -->
      
       <resolver:DataConnector id="myLDAP" xsi:type="dc:LDAPDirectory"
               ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"
               baseDN="%{idp.attribute.resolver.LDAP.baseDN}"
               principal="%{idp.attribute.resolver.LDAP.bindDN}"
               principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"
               useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS:false}">
               <dc:FilterTemplate>
                   <![CDATA[
                       %{idp.attribute.resolver.LDAP.searchFilter}
                   ]]>
               </dc:FilterTemplate>
       </resolver:DataConnector>
      
    4. /conf/ldap.properties

       idp.authn.LDAP.authenticator                   = bindSearchAuthenticator
      
       --------
       idp.authn.LDAP.ldapURL                          = ldap://192.168.119.14:389
       idp.authn.LDAP.useStartTLS                     = false
       idp.authn.LDAP.useSSL                          = false
       --------
      
       ó
      
       --------
       idp.authn.LDAP.ldapURL                          = ldaps://wndca08.prepdc.gencat.intranet:636 --> 
       idp.authn.LDAP.useStartTLS                     = false
       idp.authn.LDAP.useSSL                          = true
       --------
      
       #idp.authn.LDAP.connectTimeout                  = 3000
      
       idp.authn.LDAP.sslConfig                       = certificateTrust
       idp.authn.LDAP.trustCertificates                = %{idp.home}/credentials/ldap-server.crt --> s'hauria de posar la ruta del certificat del ldap si estem anant per SSL
       																						  --> el certificat s'ha d'importar des del directoris de configuració o bé injectar 
       																						      en la creació de la imatge	
       idp.authn.LDAP.trustStore                       = %{idp.home}/credentials/ldap-server.truststore
      
       idp.authn.LDAP.returnAttributes                 = employeeId
      
       idp.authn.LDAP.baseDN                           = ou=Persones,ou=DIRECTORI,dc=prepdc,dc=gencat,dc=intranet
       idp.authn.LDAP.userFilter                       = (employeeId={user})
       idp.authn.LDAP.bindDN                           = SMAdmin@prepdc.gencat.intranet
       idp.authn.LDAP.bindDNCredential                 = ********************************************
      
       idp.authn.LDAP.dnFormat                         = %s@prepdc.gencat.intranet
      
       idp.attribute.resolver.LDAP.ldapURL             = %{idp.authn.LDAP.ldapURL}
       idp.attribute.resolver.LDAP.baseDN              = %{idp.authn.LDAP.baseDN}
       idp.attribute.resolver.LDAP.bindDN              = %{idp.authn.LDAP.bindDN}
       idp.attribute.resolver.LDAP.bindDNCredential    = %{idp.authn.LDAP.bindDNCredential}
       #idp.attribute.resolver.LDAP.useStartTLS         = %{idp.authn.LDAP.useStartTLS:true}
       #idp.attribute.resolver.LDAP.trustCertificates   = %{idp.authn.LDAP.trustCertificates}
       idp.attribute.resolver.LDAP.searchFilter        = (employeeId=$requestContext.principalName)
      
       #idp.pool.LDAP.minSize                          = 3
       #idp.pool.LDAP.maxSize                          = 10
       #idp.pool.LDAP.validateOnCheckout               = false
       #idp.pool.LDAP.validatePeriodically             = true
       #idp.pool.LDAP.validatePeriod                   = 300
       #idp.pool.LDAP.prunePeriod                      = 300
       #idp.pool.LDAP.idleTime                         = 600
       #idp.pool.LDAP.blockWaitTime                    = 3000
       #idp.pool.LDAP.failFastInitialize               = false
      
    5. /conf/attribute-filter.xml

      Utilitzarem el camp employeeId com a identificador de l’Active Directory.

           <afp:AttributeFilterPolicy id="gencat_attrib_policy">
               <afp:PolicyRequirementRule xsi:type="basic:ANY" />
      
               <afp:AttributeRule attributeID="employeeId">
                   <afp:PermitValueRule xsi:type="basic:ANY" />
               </afp:AttributeRule>
      
               <afp:AttributeRule attributeID="mail">
                   <afp:PermitValueRule xsi:type="basic:ANY" />
               </afp:AttributeRule>
      
               <afp:AttributeRule attributeID="CODIINTERN">
                   <afp:PermitValueRule xsi:type="basic:ANY" />
               </afp:AttributeRule>
      
               <afp:AttributeRule attributeID="UNITAT_MAJOR">
                   <afp:PermitValueRule xsi:type="basic:ANY" />
               </afp:AttributeRule>
      
               <afp:AttributeRule attributeID="UNITAT_MENOR">
                   <afp:PermitValueRule xsi:type="basic:ANY" />
               </afp:AttributeRule>
      
               <afp:AttributeRule attributeID="GICAR">
                   <afp:PermitValueRule xsi:type="basic:ANY" />
               </afp:AttributeRule>
      
           </afp:AttributeFilterPolicy>
      
    6. /conf/logback.xml si es volen canviar els nivell de log

    7. /messages/* per a configurar els textos de l’aplicació

    8. /metadata/idp-metadata.xml

      • revisar que s’ha configurat correctament el host domain
      • aquest fitxer s’ha de copiar als service providers
    9. /views per a personalitzar les vistes de les diferents pantalles de l’aplicació

    10. /webapp per a personalitzar la presentació de l’aplicació (css, imatges, …)

    11. Un cop configurats aquests fitxers, cal fer

       $ docker exec shibboleth-idp import.sh
      

      per a reconstruir el idp.war i carregar la nova configuració. Caldrà reiniciar el contenidor.

       $ docker restart shibboleth-idp
      

SP - Service Provider (client Apache)

  1. Construcció de la imatge a partir del projecte:

     $ docker build -t shibboleth-sp . 
    
  2. Arrencar el contenidor

     $ docker run -d -p 81:80 -v /home/shibboleth/sp/conf:/tmp --name shibboleth-sp shibboleth-sp
    
  3. Copiar fitxers de configuració per a poder adaptar-los

     $ docker exec shibboleth-sp cp /etc/shibboleth/shibboleth2.xml /tmp
     $ docker exec shibboleth-sp cp /etc/shibboleth/attribute-map.xml /tmp
    
  4. Copiar el fitxer idp-metadata.xml de l’IDP a la ruta que estigui configurada al fitxer shibboleth2.xml

  5. shibboleth2.xml

    • modificar les uris i entityId que apuntin a l’IDP: https://[idp host]/idp/shibboleth

    • adaptar el metadata provider segons les necessitats (en aquest exemple s’han deshabilitat les propietats de signatura):

        <MetadataProvider type="XML" validate="true"
              uri="https://[idp-host]/idp/shibboleth"
              backingFilePath="/tmp/idp-metadata.xml" reloadInterval="7200">
            <!--MetadataFilter type="RequireValidUntil" maxValidityInterval="2419200"/-->
            <!--MetadataFilter type="Signature" certificate="idp-cert.pem"/-->
            <!--DiscoveryFilter type="Blacklist" matcher="EntityAttributes" trimTags="true" 
              attributeName="http://macedir.org/entity-category"
              attributeNameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
              attributeValue="http://refeds.org/category/hide-from-discovery" /-->
        </MetadataProvider>	
      
    • Modificar el REMOTE_USER amb el valor GICAR_ID:

        <ApplicationDefaults entityID="https://sp1.locahost/shibboleth" REMOTE_USER="GICAR_ID"> 
      
  6. attribute-map.xml

    • Com que estem optant pel employeeId com a camp de l’AD a utilitzar, necessitem afegir les següents línies (posem com a id “GICAR_ID”, que és la capçalera actual de GICAR):

        <Attribute name="urn:mace:dir:attribute-def:employeeId" id="GICAR_ID" />
        <Attribute name="urn:oid:0.9.2342.19200300.100.1.1" id="GICAR_ID" />
      
        <Attribute name="urn:mace:dir:attribute-def:mail" id="mail" />
        <Attribute name="urn:oid:0.9.2342.19200300.100.1.3" id="mail" />
      
        <Attribute name="urn:mace:dir:attribute-def:sAMAccountName" id="CODIINTERN" />
        <Attribute name="urn:oid:0.9.2342.19200300.100.1.99" id="CODIINTERN" />
      
        <Attribute name="urn:mace:dir:attribute-def:department" id="UNITAT_MAJOR" />
        <Attribute name="urn:oid:0.9.2342.19200300.100.1.2" id="UNITAT_MAJOR" />
      
        <Attribute name="urn:mace:dir:attribute-def:company" id="UNITAT_MENOR" />
        <Attribute name="urn:oid:0.9.2342.19200300.100.1.98" id="UNITAT_MENOR" />
      
        <Attribute name="https://gencat.cat/GICAR" id="GICAR" />
      

    Tenint present que estem agafant la referència de l’uid, aquest camp no hauria d’estar activat.

  7. Obtenir el fitxer de metadata per a informar al IDP (no utilitzar localhost!!!)

     http(s)://[service provider host]/Shibboleth.sso/Metadata
    
  8. El fitxer recuperat, s’hauria d’afegir al fitxer complet de metadata que recupera l’IDP.

Tips and tricks

  1. Configurar els contenidors amb un DNS. En arrencar contenidors de prova

     $ docker run -d -p 80:80 --name shibboleth-sp --add-host idp.extranet.gencat.cat:172.17.0.2 -v $BASE_PATH/Dockers/docker-images/centos-shib-sp/conf/:/tmp/ jtgasper3/centos-shibboleth-sp
    
  2. En recuperar la metadata del SP, fer-ho amb el DNS assignat.

  3. Exemple de fitxer de metadata complet, amb el idp-metadata i dos sp-metadata: https://dl.dropboxusercontent.com/u/17397489/idp/metadata.xml

TODO

  1. Modificar l’interval de refresc del fitxer configurat a IDP/conf/metadata-providers.xml

  2. Possibilitats de clúster

  3. Traduïr els fitxers de configuració a català

  4. Evitar que surti el missatge de redirecció a l’aplicació SP