Configuração do Shibboleth IDP 4.1+ para Uso de Múltiplas Bases de Usuários

Em algumas situações excepcionais pode-se justificar a não integração de bases de usuários, nesses casos é necessário que seja feita uma integração do IDP com múltiplas bases de usuários.

Esse roteiro apresenta os passos necessários para a implementação de tal medida.

Configuração do Shibboleth IDP 4.1+ para Uso de Múltiplas Bases de Usuários

1. Introdução

O fluxo de ingresso de uma instituição como membro da Federação CAFe passa por uma etapa de consolidação de bases de usuários. Nessa etapa é realizado um trabalho onde os dados que estejam dispersos em diferentes bases de dados possam ser consolidados e passem a integrar uma base única.Tal medida visa garantir o adequado gerenciamento de identidades.

ATENÇÃO - O uso de múltiplas bases de usuários pode fazer com que o processo de autenticação fique mais lento.

2. Arquivos Manipulados

Os seguintes arquivos de configuração serão manipulados ao longo deste roteiro:

  • /opt/shibboleth-idp/conf/attribute-resolver.xml

  • /opt/shibboleth-idp/conf/ldap.properties

  • /opt/shibboleth-idp/conf/authn/password-authn-config.xml

  • /opt/shibboleth-idp/credentials/secrets.properties

Os exemplos apresentados também estão disponíveis no repositório https://svn.cafe.rnp.br/repos/CAFe/idp-files-v421/multiplas_bases_idpv4.1/

Ao longo do roteiro é possível encontrar links diretos para os arquivos no repositório.

3. Configurações

O princípio básico da adequação que será realizada consiste em gerar múltiplas configurações de acesso às bases de dados. Para tanto, os parâmetros de configuração são definidos tantas vezes quanto for necessário.

Cabe destacar que as configurações apresentadas neste roteiro não são uma solução pronta e devem ser analisadas e personalizadas para atender ao cenário existente em cada implantação.

O primeiro arquivo que deve ser manipulado é o /opt/shibboleth-idp/conf/ldap.properties que deve ficar com o uma configuração similar a que é apresentada a seguir:

# LDAP authentication (and possibly attribute resolver) configuration
# Note, this doesn't apply to the use of JAAS authentication via LDAP

## Authenticator strategy, either anonSearchAuthenticator, bindSearchAuthenticator, directAuthenticator, adAuthenticator
idp.authn.LDAP.authenticator                    = bindSearchAuthenticator

## Connection properties ##
idp.authn.LDAP.ldapURL.1                          = ldap://ldap_1.exemplo.local:389
idp.authn.LDAP.useStartTLS.1                      = false
idp.authn.LDAP.ldapURL.2                          = ldap://ldap_2.exemplo.local:389
idp.authn.LDAP.useStartTLS.2                      = false
idp.authn.LDAP.ldapURL.3                          = ldap://AD_3.exemplo.local:389
idp.authn.LDAP.useStartTLS.3                      = false
# Time in milliseconds that connects will block
idp.authn.LDAP.connectTimeout                   = PT3S
# Time in milliseconds to wait for responses
idp.authn.LDAP.responseTimeout                  = PT3S
# Connection strategy to use when multiple URLs are supplied, either ACTIVE_PASSIVE, ROUND_ROBIN, RANDOM
#idp.authn.LDAP.connectionStrategy              = ACTIVE_PASSIVE

## SSL configuration, either jvmTrust, certificateTrust, or keyStoreTrust
idp.authn.LDAP.sslConfig                        = certificateTrust
## If using certificateTrust above, set to the trusted certificate's path
idp.authn.LDAP.trustCertificates                = %{idp.home}/credentials/ldap-server.crt
## If using keyStoreTrust above, set to the truststore path
#idp.authn.LDAP.trustStore                      = %{idp.home}/credentials/ldap-server.truststore

## Return attributes during authentication
idp.authn.LDAP.returnAttributes.1                 = uid
idp.authn.LDAP.returnAttributes.2                 = uid
idp.authn.LDAP.returnAttributes.3                 = sAMAccountName

## DN resolution properties ##

# Search DN resolution, used by anonSearchAuthenticator, bindSearchAuthenticator
# for AD: CN=Users,DC=example,DC=org
idp.authn.LDAP.baseDN.1                           = ou=people_1,dc=homolog,dc=rnp
idp.authn.LDAP.subtreeSearch.1                    = true
idp.authn.LDAP.userFilter.1                       = (uid={user})
idp.authn.LDAP.baseDN.2                           = ou=people_2,dc=homolog,dc=rnp
idp.authn.LDAP.subtreeSearch.2                    = true
idp.authn.LDAP.userFilter.2                       = (uid={user})
idp.authn.LDAP.baseDN.3                           = ou=people_3,dc=homolog,dc=rnp
idp.authn.LDAP.subtreeSearch.3                    = true
idp.authn.LDAP.userFilter.3                       = (sAMAccountname={user})
# bind search configuration
# for AD: idp.authn.LDAP.bindDN=adminuser@domain.com
idp.authn.LDAP.bindDN.1                           = uid=leitor-shib,ou=Admins,dc=homolog,dc=rnp
idp.authn.LDAP.bindDN.2                           = cn=leitor-shib,dc=homolog,dc=rnp
idp.authn.LDAP.bindDN.3                           = app.shibboleth@homolog.rnp

# Format DN resolution, used by directAuthenticator, adAuthenticator
# for AD use idp.authn.LDAP.dnFormat=%s@domain.com
idp.authn.LDAP.dnFormat.1                         = mail=%s,ou=people_1,dc=homolog,dc=rnp
idp.authn.LDAP.dnFormat.2                         = mail=%s,ou=people_2,dc=homolog,dc=rnp
idp.authn.LDAP.dnFormat.3                         = %s@homolog.rnp

# pool passivator, either none, bind or anonymousBind
#idp.authn.LDAP.bindPoolPassivator              = none

# LDAP attribute configuration, see attribute-resolver.xml
# Note, this likely won't apply to the use of legacy V2 resolver configurations
idp.attribute.resolver.LDAP.ldapURL.1             = %{idp.authn.LDAP.ldapURL.1}
idp.attribute.resolver.LDAP.connectTimeout.1      = %{idp.authn.LDAP.connectTimeout:PT3S}
idp.attribute.resolver.LDAP.responseTimeout.1     = %{idp.authn.LDAP.responseTimeout:PT3S}
idp.attribute.resolver.LDAP.connectionStrategy.1  = %{idp.authn.LDAP.connectionStrategy:ACTIVE_PASSIVE}
idp.attribute.resolver.LDAP.baseDN.1              = %{idp.authn.LDAP.baseDN.1:undefined}
idp.attribute.resolver.LDAP.bindDN.1              = %{idp.authn.LDAP.bindDN.1:undefined}
idp.attribute.resolver.LDAP.useStartTLS.1         = %{idp.authn.LDAP.useStartTLS.1:true}
idp.attribute.resolver.LDAP.trustCertificates.1   = %{idp.authn.LDAP.trustCertificates:undefined}
idp.attribute.resolver.LDAP.searchFilter.1        = (uid=$resolutionContext.principal)

idp.attribute.resolver.LDAP.ldapURL.2             = %{idp.authn.LDAP.ldapURL.2}
idp.attribute.resolver.LDAP.connectTimeout.2      = %{idp.authn.LDAP.connectTimeout:PT3S}
idp.attribute.resolver.LDAP.responseTimeout.2     = %{idp.authn.LDAP.responseTimeout:PT3S}
idp.attribute.resolver.LDAP.connectionStrategy.2  = %{idp.authn.LDAP.connectionStrategy:ACTIVE_PASSIVE}
idp.attribute.resolver.LDAP.baseDN.2              = %{idp.authn.LDAP.baseDN.2:undefined}
idp.attribute.resolver.LDAP.bindDN.2              = %{idp.authn.LDAP.bindDN.2:undefined}
idp.attribute.resolver.LDAP.useStartTLS.2         = %{idp.authn.LDAP.useStartTLS.2:true}
idp.attribute.resolver.LDAP.trustCertificates.2   = %{idp.authn.LDAP.trustCertificates:undefined}
idp.attribute.resolver.LDAP.searchFilter.2        = (uid=$resolutionContext.principal)

idp.attribute.resolver.LDAP.ldapURL.3             = %{idp.authn.LDAP.ldapURL.3}
idp.attribute.resolver.LDAP.connectTimeout.3      = %{idp.authn.LDAP.connectTimeout:PT3S}
idp.attribute.resolver.LDAP.responseTimeout.3     = %{idp.authn.LDAP.responseTimeout:PT3S}
idp.attribute.resolver.LDAP.connectionStrategy.3  = %{idp.authn.LDAP.connectionStrategy:ACTIVE_PASSIVE}
idp.attribute.resolver.LDAP.baseDN.3              = %{idp.authn.LDAP.baseDN.3:undefined}
idp.attribute.resolver.LDAP.bindDN.3              = %{idp.authn.LDAP.bindDN.3:undefined}
idp.attribute.resolver.LDAP.useStartTLS.3         = %{idp.authn.LDAP.useStartTLS.3:true}
idp.attribute.resolver.LDAP.trustCertificates.3   = %{idp.authn.LDAP.trustCertificates:undefined}
idp.attribute.resolver.LDAP.searchFilter.3        = (sAMAccountname=$resolutionContext.principal)

# LDAP pool configuration, used for both authn and DN resolution
#idp.pool.LDAP.minSize                          = 3
#idp.pool.LDAP.maxSize                          = 10
#idp.pool.LDAP.validateOnCheckout               = false
#idp.pool.LDAP.validatePeriodically             = true
#idp.pool.LDAP.validatePeriod                   = PT5M
#idp.pool.LDAP.validateDN                       =
#idp.pool.LDAP.validateFilter                   = (objectClass=*)
#idp.pool.LDAP.prunePeriod                      = PT5M
#idp.pool.LDAP.idleTime                         = PT10M
#idp.pool.LDAP.blockWaitTime                    = PT3S

Este arquivo está disponível para download em: https://svn.cafe.rnp.br/repos/CAFe/idp-files-v421/multiplas_bases_idpv4.1/ldap.properties-multiplas-bases

Observe que uma parcela considerável dos parâmetros foram copiados e renomeados através da adição de um sufixo que é um número de ordem utilizado para identificar as diferentes bases de usuários. Este processo é necessário apenas para os parâmetros cujo valor difere entre as bases de dados. No caso da configuração acima, os parâmetros idp.authn.LDAP.bindDN.1 e idp.authn.LDAP.bindDN.2 possuem o mesmo valor, ou seja, poderia-se ter utilizado apenas um parâmetro como, por exemplo, idp.authn.LDAP.bindDN. Sempre que se optar pela criação ou exclusão de parâmetros é importante certificar-se que tal medida seja propagada nos demais arquivos de configuração.

Após, o arquivo a ser alterado é o /opt/shibboleth-idp/credentials/secrets.properties que deve ficar com o uma configuração similar a que é apresentada a seguir:

# Access to internal AES encryption key
idp.sealer.storePassword = changeit
idp.sealer.keyPassword = changeit

# Default access to LDAP authn and attribute stores.
idp.authn.LDAP.bindDNCredential.1              = senha_ldap_1
idp.attribute.resolver.LDAP.bindDNCredential.1 = %{idp.authn.LDAP.bindDNCredential.1:undefined}
idp.authn.LDAP.bindDNCredential.2              = senha_ldap_2
idp.attribute.resolver.LDAP.bindDNCredential.2 = %{idp.authn.LDAP.bindDNCredential.2:undefined}
idp.authn.LDAP.bindDNCredential.3              = senha_AD_3
idp.attribute.resolver.LDAP.bindDNCredential.3 = %{idp.authn.LDAP.bindDNCredential.3:undefined}

# Salt used to generate persistent/pairwise IDs, must be kept secret
idp.persistentId.salt  = [aqui deve ficar o seu hash salt]

idp.cafe.computedIDsalt = [aqui deve ficar o seu hash salt]

Este arquivo está disponível para download em: https://svn.cafe.rnp.br/repos/CAFe/idp-files-v421/multiplas_bases_idpv4.1/secrets.properties-multiplas-bases

A seguir, o arquivo a ser alterado é o /opt/shibboleth-idp/conf/authn/password-authn-config.xml que deve ficar com o uma configuração similar a que é apresentada a seguir:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"

       default-init-method="initialize"
       default-destroy-method="destroy">

    <!--
    Ordered list of CredentialValidators to apply to a request.

    The four supplied variants are shown below; the HTPasswd option
    is an OOB default for demo account purposes, and you will
    want to remove it after initial install and testing.
    -->
    <!--
    <util:list id="shibboleth.authn.Password.Validators">
        <ref bean="shibboleth.LDAPValidator" /> -->
        <!-- <ref bean="shibboleth.KerberosValidator" /> -->
        <!-- <ref bean="shibboleth.JAASValidator" /> -->
        <!-- <bean parent="shibboleth.HTPasswdValidator" p:resource="%{idp.home}/credentials/demo.htpasswd" /> -->
    <!--    </util:list> -->

    <!--
    Arquivo exemplo para autenticacao um duas bases de usuarios.
    -->

    <util:list id="shibboleth.authn.Password.Validators">
        <bean p:id="ldap_1" parent="shibboleth.LDAPValidator">
            <property name="authenticator">
                <bean parent="shibboleth.LDAPAuthenticationFactory"
                    p:ldapUrl="%{idp.authn.LDAP.ldapURL.1:undefined}"
                    p:baseDn="#{'%{idp.authn.LDAP.baseDN.1:undefined}'.trim()}"
                    p:bindDn="#{'%{idp.authn.LDAP.bindDN.1:undefined}'.trim()}"
                    p:bindDnCredential="%{idp.authn.LDAP.bindDNCredential.1:undefined}"
                    p:userFilter="#{'%{idp.authn.LDAP.userFilter.1:undefined}'.trim()}"
                    p:useStartTLS="%{idp.authn.LDAP.useStartTLS.1:undefined}" />
            </property>
        </bean>
        <bean p:id="ldap_2" parent="shibboleth.LDAPValidator">
            <property name="authenticator">
                <bean parent="shibboleth.LDAPAuthenticationFactory"
                    p:ldapUrl="%{idp.authn.LDAP.ldapURL.2:undefined}"
                    p:baseDn="#{'%{idp.authn.LDAP.baseDN.2:undefined}'.trim()}"
                    p:bindDn="#{'%{idp.authn.LDAP.bindDN.2:undefined}'.trim()}"
                    p:bindDnCredential="%{idp.authn.LDAP.bindDNCredential.2:undefined}"
                    p:userFilter="#{'%{idp.authn.LDAP.userFilter.2:undefined}'.trim()}"
                    p:useStartTLS="%{idp.authn.LDAP.useStartTLS.2:undefined}" />
            </property>
        </bean>
         <bean p:id="ldap_3" parent="shibboleth.LDAPValidator">
            <property name="authenticator">
                <bean parent="shibboleth.LDAPAuthenticationFactory"
                    p:ldapUrl="%{idp.authn.LDAP.ldapURL.3:undefined}"
                    p:baseDn="#{'%{idp.authn.LDAP.baseDN.3:undefined}'.trim()}"
                    p:bindDn="#{'%{idp.authn.LDAP.bindDN.3:undefined}'.trim()}"
                    p:bindDnCredential="%{idp.authn.LDAP.bindDNCredential.3:undefined}"
                    p:userFilter="#{'%{idp.authn.LDAP.userFilter.3:undefined}'.trim()}"
                    p:useStartTLS="%{idp.authn.LDAP.useStartTLS.3:undefined}" />
            </property>
            <!--
            Usar o bloco abaixo para situacoes em que o uso de uma segunda base de autenticacao dependa do RP (condicao de ativacao).
            Ex.: autenticacao de contas departamentais/sinteticas (não pertencentes a pessoas naturais) no Google Workspace.
            -->
            <!--
            <property name="activationCondition">
                <bean parent="shibboleth.Conditions.RelyingPartyId"
                      c:candidate="google.com/a/instituicao" />
            </property>
            -->
        </bean>
    </util:list>

    <!-- Apply any regular expression replacement pairs to username before validation. -->
    <util:list id="shibboleth.authn.Password.Transforms">
        <!--
        <bean parent="shibboleth.Pair" p:first="^(.+)@example\.org$" p:second="$1" />
        -->
    </util:list>

    <!-- Uncomment to configure account lockout backed by in-memory storage. -->
    <!--
    <bean id="shibboleth.authn.Password.AccountLockoutManager"
        parent="shibboleth.StorageBackedAccountLockoutManager"
        p:maxAttempts="5"
        p:counterInterval="PT5M"
        p:lockoutDuration="PT5M"
        p:extendLockoutDuration="false" />
    -->

    <!--
    Define entries here to map error messages detected by validation actions and classify them as particular
    kinds of errors for use in your templates and as events in flows.

    Keys are events to signal, values are error codes.
    -->
    <util:map id="shibboleth.authn.Password.ClassifiedMessageMap">
        <entry key="UnknownUsername">
            <list>
                <value>NoCredentials</value>
                <value>UnknownUsername</value>
                <value>CLIENT_NOT_FOUND</value>
                <value>Client not found</value>
                <value>Cannot get kdc for realm</value>
                <value>Client not found in Kerberos database</value>
                <value>DN_RESOLUTION_FAILURE</value>
                <value>Cannot authenticate dn, invalid dn</value>
                <value>Cannot authenticate dn, invalid credential</value>
                <value>AcceptSecurityContext error, data 525</value>
            </list>
        </entry>
        <entry key="InvalidPassword">
            <list>
                <value>InvalidCredentials</value>
                <value>PREAUTH_FAILED</value>
                <value>INVALID_CREDENTIALS</value>
                <value>Checksum failed</value>
                <value>Integrity check on decrypted field failed</value>
                <value>Pre-authentication information was invalid</value>
                <value>Key bytes cannot be null</value>
                <value>AcceptSecurityContext error, data 52e</value>
            </list>
        </entry>
        <entry key="AccountLocked">
            <list>
                <value>AccountLocked</value>
                <value>Clients credentials have been revoked</value>
                <value>AcceptSecurityContext error, data 775</value>
            </list>
        </entry>
        <entry key="AccountDisabled">
            <list>
                <value>AcceptSecurityContext error, data 533</value>
            </list>
        </entry>
        <entry key="ExpiredPassword">
            <list>
                <value>PASSWORD_EXPIRED</value>
                <value>CLIENT KEY EXPIRED</value>
                <value>AcceptSecurityContext error, data 532</value>
                <value>AcceptSecurityContext error, data 773</value>
                <value>AcceptSecurityContext error, data 701</value>
            </list>
        </entry>
        <entry key="ExpiringPassword">
            <list>
                <value>ACCOUNT_WARNING</value>
            </list>
        </entry>
        <entry key="RequestUnsupported">
            <list>
                <value>RequestUnsupported</value>
            </list>
        </entry>
    </util:map>

    <!--
    WARNING: This set of features is generally discouraged in favor of the MFA flow,
    and while not deprecated, is not recommended for new deployments.

    Configuration of "extended" login methods to offer in the password login form.

    The String bean is a regular expression identifying the flows to offer. These flows
    must also be enabled at the "top" level to be available for use.

    The ExtendedFlowParameters bean can be used to transfer custom parameters from the
    login form into the context tree for use later by other flows.

    The last bean provides the set of custom Principals to use for results produced by the
    Password flow itself. You would use this if you need the Password flow to run as a shell
    to run the "extended" login methods, but want to limit its own results more narrowly.
    -->
    <!--
    <bean id="shibboleth.authn.Password.ExtendedFlows" class="java.lang.String" c:_0="" />

    <util:list id="shibboleth.authn.Password.ExtendedFlowParameters">
    </util:list>

    <util:list id="shibboleth.authn.Password.PrincipalOverride">
        <bean parent="shibboleth.SAML2AuthnContextClassRef"
            c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" />
        <bean parent="shibboleth.SAML2AuthnContextClassRef"
            c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:Password" />
        <bean parent="shibboleth.SAML1AuthenticationMethod"
            c:method="urn:oasis:names:tc:SAML:1.0:am:password" />
    </util:list>
    -->

</beans>

Este arquivo está disponível para download em: https://svn.cafe.rnp.br/repos/CAFe/idp-files-v421/multiplas_bases_idpv4.1/password-authn-config-multiplas-bases.xml

Por fim, deve-se alterar o arquivo /opt/shibboleth-idp/conf/attribute-resolver.xml que deve ficar com o uma configuração similar a que é apresentada a seguir:

<?xml version="1.0" encoding="UTF-8"?>

<AttributeResolver xmlns="urn:mace:shibboleth:2.0:resolver"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd">

    <!-- ========================================== -->
    <!--      Attribute Definitions                 -->
    <!-- ========================================== -->

    <!-- CAFe - uid -->
    <AttributeDefinition id="uid" xsi:type="Simple">
        <InputDataConnector ref="dcLDAP1" attributeNames="uid" />
        <InputDataConnector ref="dcLDAP2" attributeNames="uid" />
        <InputDataConnector ref="dcLDAP3" attributeNames="sAMAccountName" />
    </AttributeDefinition>

    <!-- CAFe - uidMD5 A -->
    <AttributeDefinition id="uidMD5A" xsi:type="ScriptedAttribute" dependencyOnly="true">
        <InputDataConnector ref="dcLDAP1" attributeNames="%{idp.authn.LDAP.returnAttributes.1}" />
        <Script>
            <![CDATA[
                uidMD5A.getValues().clear();
                logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.attribute");
                if (typeof %{idp.authn.LDAP.returnAttributes.1} != "undefined" && %{idp.authn.LDAP.returnAttributes.1} != null ){
                    localpart = org.apache.commons.codec.digest.DigestUtils.md5Hex(%{idp.authn.LDAP.returnAttributes.1}.getValues().get(0));
                    uidMD5A.getValues().add(localpart);
                    logger.info("%{idp.authn.LDAP.returnAttributes.1}: "+%{idp.authn.LDAP.returnAttributes.1}.getValues().get(0)+" md5: "+localpart);
                }
            ]]>
        </Script>
    </AttributeDefinition>

    <!-- CAFe - uidMD5 B -->
    <AttributeDefinition id="uidMD5B" xsi:type="ScriptedAttribute" dependencyOnly="true">
        <InputDataConnector ref="dcLDAP2" attributeNames="%{idp.authn.LDAP.returnAttributes.2}" />
        <Script>
            <![CDATA[
                uidMD5B.getValues().clear();
                logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.attribute");
                if (typeof %{idp.authn.LDAP.returnAttributes.2} != "undefined" && %{idp.authn.LDAP.returnAttributes.2} != null ){
                    localpart = org.apache.commons.codec.digest.DigestUtils.md5Hex(%{idp.authn.LDAP.returnAttributes.2}.getValues().get(0));
                    uidMD5B.getValues().add(localpart);
                    logger.info("%{idp.authn.LDAP.returnAttributes.2}: "+%{idp.authn.LDAP.returnAttributes.2}.getValues().get(0)+" md5: "+localpart);
                }
            ]]>
        </Script>
    </AttributeDefinition>

    <!-- CAFe - uidMD5 C -->
    <AttributeDefinition id="uidMD5C" xsi:type="ScriptedAttribute" dependencyOnly="true">
        <InputDataConnector ref="dcLDAP3" attributeNames="%{idp.authn.LDAP.returnAttributes.3}" />
        <Script>
            <![CDATA[
                uidMD5C.getValues().clear();
                logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.attribute");
                if (typeof %{idp.authn.LDAP.returnAttributes.3} != "undefined" && %{idp.authn.LDAP.returnAttributes.3} != null ){
                    localpart = org.apache.commons.codec.digest.DigestUtils.md5Hex(%{idp.authn.LDAP.returnAttributes.3}.getValues().get(0));
                    uidMD5C.getValues().add(localpart);
                    logger.info("%{idp.authn.LDAP.returnAttributes.3}: "+%{idp.authn.LDAP.returnAttributes.3}.getValues().get(0)+" md5: "+localpart);
                }
            ]]>
        </Script>
    </AttributeDefinition>

    <!-- CAFe - commonName -->
    <AttributeDefinition id="cn" xsi:type="Simple">
        <InputDataConnector ref="dcLDAP1" attributeNames="cn" />
        <InputDataConnector ref="dcLDAP2" attributeNames="cn" />
        <InputDataConnector ref="dcLDAP3" attributeNames="cn" />
    </AttributeDefinition>

    <!-- CAFe - displayName -->
    <AttributeDefinition id="displayName" xsi:type="Template">
        <InputDataConnector ref="dcLDAP1" attributeNames="givenName sn" />
        <InputDataConnector ref="dcLDAP2" attributeNames="givenName sn" />
        <InputDataConnector ref="dcLDAP3" attributeNames="givenName sn" />
        <Template>${givenName} ${sn}</Template>
    </AttributeDefinition>

    <!-- CAFe - givenName -->
    <AttributeDefinition id="givenName" xsi:type="Simple">
        <InputDataConnector ref="dcLDAP1" attributeNames="givenName" />
        <InputDataConnector ref="dcLDAP2" attributeNames="givenName" />
        <InputDataConnector ref="dcLDAP3" attributeNames="givenName" />
    </AttributeDefinition>

    <!-- CAFe - surName -->
    <AttributeDefinition id="sn" xsi:type="Simple">
        <InputDataConnector ref="dcLDAP1" attributeNames="sn" />
        <InputDataConnector ref="dcLDAP2" attributeNames="sn" />
        <InputDataConnector ref="dcLDAP3" attributeNames="sn" />
    </AttributeDefinition>

    <!-- CAFe - mail -->
    <AttributeDefinition id="mail" xsi:type="Simple">
        <InputDataConnector ref="dcLDAP1" attributeNames="mail" />
        <InputDataConnector ref="dcLDAP2" attributeNames="mail" />
        <InputDataConnector ref="dcLDAP3" attributeNames="mail" />
    </AttributeDefinition>

    <!-- CAFe - eduPersonEntitlement -->
    <AttributeDefinition id="eduPersonEntitlement" xsi:type="Simple">
        <InputDataConnector ref="staticAttributes" attributeNames="eduPersonEntitlement" />
    </AttributeDefinition>

    <!-- CAFe - brPersonCPF -->
    <AttributeDefinition id="brPersonCPF" xsi:type="Simple">
        <InputDataConnector ref="dcLDAP1" attributeNames="brPersonCPF" />
        <InputDataConnector ref="dcLDAP2" attributeNames="brPersonCPF" />
        <InputDataConnector ref="dcLDAP3" attributeNames="employeeType" />
    </AttributeDefinition>

    <!-- CAFe - schacDateOfBirth -->
    <AttributeDefinition id="schacDateOfBirth" xsi:type="Simple">
        <InputDataConnector ref="dcLDAP1" attributeNames="schacDateOfBirth" />
        <InputDataConnector ref="dcLDAP2" attributeNames="schacDateOfBirth" />
        <InputDataConnector ref="dcLDAP3" attributeNames="employeeNumber" />
    </AttributeDefinition>

    <!-- CAFe - eduPersonPrincipalName A -->
    <AttributeDefinition id="eduPersonPrincipalName" xsi:type="Scoped" scope="%{idp.scope}">
        <InputAttributeDefinition ref="uidMD5A" />
        <InputAttributeDefinition ref="uidMD5B" />
        <InputAttributeDefinition ref="uidMD5C" />
    </AttributeDefinition>

    <!-- CAFe - eduPersonTargetedID -->
    <AttributeDefinition id="eduPersonTargetedID" xsi:type="SAML2NameID" nameIdFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">
        <InputDataConnector ref="ComputedIDConnector" attributeNames="ComputedID" />
    </AttributeDefinition>

    <!-- CAFe - brEduAffiliationType -->
    <AttributeDefinition id="brEduAffiliationType" xsi:type="Simple">
        <InputDataConnector ref="dcLDAPBrEduPerson1" attributeNames="brEduAffiliationType" />
        <InputDataConnector ref="dcLDAPBrEduPerson2" attributeNames="brEduAffiliationType" />
        <InputDataConnector ref="dcLDAPBrEduPerson3" attributeNames="brEduAffiliationType" />
    </AttributeDefinition>

    <!-- CAFe - eduPersonAffiliation -->
    <AttributeDefinition id="eduPersonAffiliation" xsi:type="Mapped">
        <InputAttributeDefinition ref="brEduAffiliationType" />
        <DefaultValue passThru="true" />
        <ValueMap>
            <ReturnValue>affiliate</ReturnValue>
            <SourceValue>other</SourceValue>
            <SourceValue>position</SourceValue>
            <SourceValue>scholarshipAwardee</SourceValue>
        </ValueMap>
    </AttributeDefinition>

    <!-- ========================================== -->
    <!--      Data Connectors                       -->
    <!-- ========================================== -->

    <DataConnector id="dcLDAP1" xsi:type="LDAPDirectory" ldapURL="%{idp.attribute.resolver.LDAP.ldapURL.1}" baseDN="%{idp.attribute.resolver.LDAP.baseDN.1}" principal="%{idp.attribute.resolver.LDAP.bindDN.1}" principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential.1}" useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS.1:true}" noResultIsError="%{idp.attribute.resolver.LDAP.noResultsIsError:false}" multipleResultsIsError="%{idp.attribute.resolver.LDAP.multipleResultsIsError:true}">
        <FilterTemplate>
            <![CDATA[
                %{idp.attribute.resolver.LDAP.searchFilter.1}
            ]]>
        </FilterTemplate>
        <ReturnAttributes>%{idp.authn.LDAP.returnAttributes.1} mail cn givenName sn brPersonCPF schacDateOfBirth</ReturnAttributes>
    </DataConnector>

    <DataConnector id="dcLDAP2" xsi:type="LDAPDirectory" ldapURL="%{idp.attribute.resolver.LDAP.ldapURL.2}" baseDN="%{idp.attribute.resolver.LDAP.baseDN.2}" principal="%{idp.attribute.resolver.LDAP.bindDN.2}" principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential.2}" useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS.2:true}" noResultIsError="%{idp.attribute.resolver.LDAP.noResultsIsError:false}" multipleResultsIsError="%{idp.attribute.resolver.LDAP.multipleResultsIsError:true}">
        <FilterTemplate>
            <![CDATA[
                %{idp.attribute.resolver.LDAP.searchFilter.2}
            ]]>
        </FilterTemplate>
        <ReturnAttributes>%{idp.authn.LDAP.returnAttributes.2} mail cn givenName sn brPersonCPF schacDateOfBirth</ReturnAttributes>
    </DataConnector>

    <DataConnector id="dcLDAP3" xsi:type="LDAPDirectory" ldapURL="%{idp.attribute.resolver.LDAP.ldapURL.3}" baseDN="%{idp.attribute.resolver.LDAP.baseDN.3}" principal="%{idp.attribute.resolver.LDAP.bindDN.3}" principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential.3}" useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS.3:true}" noResultIsError="%{idp.attribute.resolver.LDAP.noResultsIsError:false}" multipleResultsIsError="%{idp.attribute.resolver.LDAP.multipleResultsIsError:true}">
        <FilterTemplate>
            <![CDATA[
                %{idp.attribute.resolver.LDAP.searchFilter.3}
            ]]>
        </FilterTemplate>
        <ReturnAttributes>%{idp.authn.LDAP.returnAttributes.3} mail cn givenName sn employeeType employeeNumber</ReturnAttributes>
    </DataConnector>

    <DataConnector id="dcLDAPBrEduPerson1" xsi:type="LDAPDirectory" ldapURL="%{idp.attribute.resolver.LDAP.ldapURL.1}" baseDN="%{idp.attribute.resolver.LDAP.baseDN.1}" principal="%{idp.attribute.resolver.LDAP.bindDN.1}" principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential.1}" useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS.1:true}" noResultIsError="%{idp.attribute.resolver.LDAP.noResultsIsError:false}" multipleResultsIsError="%{idp.attribute.resolver.LDAP.multipleResultsIsError:true}">
        <FilterTemplate>
            <![CDATA[
                %{idp.attribute.resolver.LDAP.searchFilter.1}
            ]]>
        </FilterTemplate>
        <ReturnAttributes>brEduAffiliationType</ReturnAttributes>
    </DataConnector>

    <DataConnector id="dcLDAPBrEduPerson2" xsi:type="LDAPDirectory" ldapURL="%{idp.attribute.resolver.LDAP.ldapURL.2}" baseDN="%{idp.attribute.resolver.LDAP.baseDN.2}" principal="%{idp.attribute.resolver.LDAP.bindDN.2}" principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential.2}" useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS.2:true}" noResultIsError="%{idp.attribute.resolver.LDAP.noResultsIsError:false}" multipleResultsIsError="%{idp.attribute.resolver.LDAP.multipleResultsIsError:true}">
        <FilterTemplate>
            <![CDATA[
                %{idp.attribute.resolver.LDAP.searchFilter.2}
            ]]>
        </FilterTemplate>
        <ReturnAttributes>brEduAffiliationType</ReturnAttributes>
    </DataConnector>

    <DataConnector id="dcLDAPBrEduPerson3" xsi:type="LDAPDirectory" ldapURL="%{idp.attribute.resolver.LDAP.ldapURL.3}" baseDN="%{idp.attribute.resolver.LDAP.baseDN.3}" principal="%{idp.attribute.resolver.LDAP.bindDN.3}" principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential.3}" useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS.3:true}" noResultIsError="%{idp.attribute.resolver.LDAP.noResultsIsError:false}" multipleResultsIsError="%{idp.attribute.resolver.LDAP.multipleResultsIsError:true}">
        <FilterTemplate>
            <![CDATA[
                %{idp.attribute.resolver.LDAP.searchFilter.3}
            ]]>
        </FilterTemplate>
        <ReturnAttributes>brEduAffiliationType</ReturnAttributes>
    </DataConnector>

    <DataConnector id="ComputedIDConnector" xsi:type="ComputedId" generatedAttributeID="ComputedID" salt="%{idp.cafe.computedIDsalt}">
        <InputDataConnector ref="dcLDAP1" attributeNames="%{idp.authn.LDAP.returnAttributes.1}" />
        <InputDataConnector ref="dcLDAP2" attributeNames="%{idp.authn.LDAP.returnAttributes.2}" />
        <InputDataConnector ref="dcLDAP3" attributeNames="%{idp.authn.LDAP.returnAttributes.3}" />
    </DataConnector>

    <DataConnector id="staticAttributes" xsi:type="Static">
        <Attribute id="eduPersonEntitlement">
            <Value>urn:mace:rediris.es:entitlement:wiki:tfemc2</Value>
        </Attribute>
    </DataConnector>

</AttributeResolver>

Este arquivo está disponível para download em: https://svn.cafe.rnp.br/repos/CAFe/idp-files-v421/multiplas_bases_idpv4.1/attribute-resolver-multiplas-bases.xml

Por fim, é necessário fazer um restart no jetty e acompanhar os logs para identificação de eventual erro.

systemctl restart jetty9 && tail -f /opt/shibboleth-idp/logs/idp-process.log

Last updated