shibbolethidp

Shibboleth 4 IDP: Query two different login sources with the Password flow


I have two login sources (an Active Directory and a local MySQL Database) that each contain different users. I want to configure the Password flow in this way:

How can I achieve that?


Solution

  • This is the solution I found:

    inside the file conf/authn/password-authn-config.xml put the following lines or replace if they already exist:

    <import resource="jaas-authn-config.xml"/>
    
    <!-- Ordered list of CredentialValidators to apply to a request. -->
    <util:list id="shibboleth.authn.Password.Validators">
        <ref bean="shibboleth.JAASValidator"/>
    </util:list>
    

    Comment out any other resources that you don't need, such as ldap-authn-config.xml or krb5-authn-config.xml.

    In my case, I want the login to succeed if either of my login sources return 'okay'. Therefore you need this line:

    <!-- Controls whether all validators in the above bean have to succeed, or just one. -->
    <util:constant id="shibboleth.authn.Password.RequireAll" static-field="java.lang.Boolean.FALSE"/>
    

    If you want all login sources to succeed, just replace 'FALSE' with 'TRUE'.

    Next, put the following inside conf/authn/jaas-authn-config.xml:

    <!-- Specify your JAAS config. -->
    <bean id="JAASConfig" class="org.springframework.core.io.FileSystemResource" c:path="%{idp.home}/conf/authn/jaas.config" />
        
    <util:property-path id="shibboleth.authn.JAAS.JAASConfigURI" path="JAASConfig.URI" />
        
    <!-- Specify the application name(s) in the JAAS config. -->
    <util:list id="shibboleth.authn.JAAS.LoginConfigNames">
        <value>ShibUserPassAuthLDAP</value>
        <value>ShibUserPassAuthJAAS</value>
    </util:list>
    

    Now open conf/authn/jaas.config and write this:

    ShibUserPassAuthJAAS {
        relationalLogin.DBLogin required debug=true
        dbDriver="com.mysql.jdbc.Driver"
        userTable="login"
        userColumn="email"
        passColumn="password"
        dbURL="jdbc:mysql://localhost:3306/login"
        dbUser="your_db_user"
        dbPassword="your_db_password"
        hashAlgorithm="SHA2" // or what u need
        saltColumn="salt" // leave empty if you don't need this
        errorMessage="Invalid password"
        where="status < 9999"; // remove if you don't need this
    };
    
    ShibUserPassAuthLDAP {
        org.ldaptive.jaas.LdapLoginModule required
        ldapUrl="ldap://localhost:10389" // your active directory url
        useStartTLS="true"
        baseDn="OU=example,OU=example,DC=example,DC=org" // change this to whatever you need
        bindDn="CN=shibboleth,OU=example,DC=example,DC=local" // change this to whatever you need
        bindCredential="your_ad_password"
        userFilter="(sAMAccountName={user})"
        credentialConfig="{trustCertificates=file:/opt/shibboleth-idp/credentials/ldap.pem}";
    };
    

    relationalLogin.DBLogin is a java class I use to actually check the credentials. You can download it from here: download the jar

    Just put it in this directory on your idp: {shibboleth_root}/edit-webapp/WEB-INF/lib/

    Now make sure you configured the password flow correctly in conf/authn/general_authn.xml:

    <bean id="authn/Password" parent="shibboleth.AuthenticationFlow"
                  p:passiveAuthenticationSupported="true"
                  p:forcedAuthenticationSupported="true"/>
    

    And to enable the Password flow change this line in idp.properties:

    idp.authn.flows=
    

    to this:

    idp.authn.flows=Password
    

    After you completed these steps, don't forget to restart jetty for the changes to take effect.

    Explanation

    The two entries called ShibUserPassAuthLDAP and ShibUserPassAuthJAAS in jaas-authn-config.xml are where the magic happens: the password flow will try to validate the credentials using those two configurations you provided. It will try the first one and finish authentication if it succeeds, or try the second configuration if the first fails.