Need to implement an IDP that supports authentication/authorization using another IDP

569 views Asked by At

We have a requirement to implement an IDP that supports authentication/authorization using another external IDP in addition to the standard the username/password form authentication. Does picketlink support this scenario out of the box?.

Here are the required components:

  1. Multiple SPs that depend on our IDP (Lets call it IDP-Internal) for authentication.
  2. IDP-Internal should support username/password form authentication using LdapLoginModule and a DatabaseLogingModule for different user groups. It should also support authentication using another IDP (Lets call it IDP-External)
  3. IDP-External is from an external provider with some SAML extensions.

We have currently implemented the SP and IDP-Internal using picketlink (following picketlink samples). However, the IDP-Internal to IDP-External integration is currently implemented using some hacky borrowed code that handcrafts/parses SAML request/response (no picketlink here). I have managed to integrated this hacky code into IDP-Internal by extending picketlink's IDPWebBrowserSSOValve. This custom valve parses the incoming SAMLResponse from IDP-External and does the local container authentication using a SAML2LoginModule similar to how it is done on the SP side.

Here is the custom valve:

public class IDPInternalAuthentiationValve extends IDPWebBrowserSSOValve {
    @Override
    public void invoke(Request request, Response response) throws IOException, ServletException {
        String samlResponseXML = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY);
        if (isNotNull(samlResponseXML)) {
            // This is a SAML Response from IDP-External
            // Parse SAML and get subjectName and roles
            // Lookup subject in an internal database and get local roles
            ServiceProviderSAMLContext.push(subjectName, combinedRoles);
            // Authenticate locally using SAML2LoginModule
            Principal principal = container.getRealm().authenticate(subjectName, ServiceProviderSAMLContext.EMPTY_PASSWORD);
            ServiceProviderSAMLContext.clear();

            Session session = request.getSessionInternal(false);
            // Save the authenticated Principal in our session
            session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);

            String samlRequestFromSession = (String)session.getNote(GeneralConstants.SAML_REQUEST_KEY);
            // This is the request from SP
            if (isNotNull(samlRequestFromSession)) {
                // Send a response back to SP using the principal created above
                processSAMLRequestMessage(request, response);
            }
        } else {
            // Username/password form authentication flow
            super.invoke(request, response);
        }
    }
}

This solutions, although works, feels a bit hacky. Is there a better way of doing this using just picketlink?

0

There are 0 answers