The Shibboleth V2 IdP and SP software have reached End of Life and are no longer supported. This documentation is available for historical purposes only. See the IDP v4 and SP v3 wiki spaces for current documentation on the supported versions.

IdPDevExtLoginHandler

Login Handler Extensions

This information is meant to be used in conjunction with the Creating Custom IdP Extensions - General Overview guide.

Overview of Authentication Process

This diagram describes the relationship of various components during the authentication process. It is intended to give LoginHandler developers an idea of the flow of control within the IdP, and thus see where their code fits in.

A common technique used is to have the LoginHandler redirect the user to a servlet or JSP page that either handles the authentication directly (e.g. X.509 client certificate) or prompts the user to provide credentials.

In the latter case, a servlet is used to handle the credential input (e.g. form POST). Once authentication is complete, the servlet should return control to the AuthenticationEngine after setting the various properties such as principal name or authentication method (using httpRequest.setAttribute(LoginHandler.*_KEY, value)).

Classes, Schema Types, and Schema Files

  • Interface to implement:
    edu.internet2.middleware.shibboleth.idp.authn.LoginHandler
  • Bean Definition Parser to extend:
    edu.internet2.middleware.shibboleth.idp.config.profile.authn.AbstractLoginHandlerBeanDefinitionParser
  • Bean Factory to extend:
    edu.internet2.middleware.shibboleth.idp.config.profile.authn.AbstractLoginHandlerFactoryBean
  • Location of schema file to import:
    /schema/shibboleth-2.0-idp-profile-handler.xsd
  • Namespace containing schema type to extend:
    urn:mace:shibboleth:2.0:idp:profile-handler
  • Complex type to extend:
    LoginHandlerType

Example Extension

Extension Class File

package foo.shibboleth.idp.authn.provider;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.opensaml.util.URLBuilder;

import edu.internet2.middleware.shibboleth.idp.authn.provider.AbstractLoginHandler;

public class MyloginHandler extends AbstractLoginHandler {

     /** Class logger. */
    private final Logger log = LoggerFactory.getLogger(MyloginHandler.class);

    /** The URL of the servlet used to perform authentication. */
    private String authenticationServletURL;

    /**
     * Constructor.
     *
     * @param servletURL URL to the authentication servlet
     */
    public MyloginHandler(String servletURL) {
        super();
        setSupportsPassive(false);
        setSupportsForceAuthentication(true);
        authenticationServletURL = servletURL;
    }

    public void login(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse) {

        // forward control to the servlet
        try {
            StringBuilder pathBuilder = new StringBuilder();
            pathBuilder.append(httpRequest.getContextPath());
            if(!authenticationServletURL.startsWith("/")){
                pathBuilder.append("/");
            }

            pathBuilder.append(authenticationServletURL);

            URLBuilder urlBuilder = new URLBuilder();
            urlBuilder.setScheme(httpRequest.getScheme());
            urlBuilder.setHost(httpRequest.getServerName());
            urlBuilder.setPort(httpRequest.getServerPort());
            urlBuilder.setPath(pathBuilder.toString());

            log.debug("Redirecting to {}", urlBuilder.buildURL());
            httpResponse.sendRedirect(urlBuilder.buildURL());
            return;

        } catch (IOException ex) {
            log.error("Unable to redirect to authentication servlet.", ex);
        }
    }
}

Extension Schema

<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://example.org/shibboleth/authn"
            xmlns="http://www.w3.org/2001/XMLSchema"
            xmlns:ph="urn:mace:shibboleth:2.0:idp:profile-handler"
            elementFormDefault="qualified">

    <import namespace="urn:mace:shibboleth:2.0:idp:profile-handler"
            schemaLocation="classpath:/schema/shibboleth-2.0-idp-profile-handler.xsd" />

    <complexType name="Mylogin">
        <complexContent>
            <extension base="ph:LoginHandlerType">
                <attribute name="authenticationServletURL" type="string" default="/Authn/UserPassword"/>
            </extension>
        </complexContent>
    </complexType>
</schema>

Bean Definition Parser

package foo.shibboleth.udo.config.profile.authn
import javax.xml.namespace.QName;
import org.opensaml.xml.util.DatatypeHelper;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.w3c.dom.Element;

import foo.shibboleth.idp.config.profile.ProfileHandlerMyNamespaceHandler;import edu.internet2.middleware.shibboleth.idp.config.profile.authn.AbstractLoginHandlerBeanDefinitionParser;

public class MyHandlerBeanDefinitionParser extends AbstractLoginHandlerBeanDefinitionParser {

    /** Schema type. */
    public static final QName SCHEMA_TYPE = new QName(ProfileHandlerMyNamespaceHandler.NAMESPACE, "Mylogin");

    /** Class logger. */
    private final Logger log = LoggerFactory.getLogger(MyHandlerBeanDefinitionParser.class);

    /** {@inheritDoc} */
    protected Class getBeanClass(Element element) {
        return MyHandlerFactoryBean.class;
    }

    /** {@inheritDoc} */
    protected void doParse(Element config, BeanDefinitionBuilder builder) {
        super.doParse(config, builder);

        builder.addPropertyValue("authenticationServletURL", DatatypeHelper.safeTrim(config.getAttributeNS(null,"authenticationServletURL")));
    }
}

Bean Factory

package foo.shibboleth.idp.config.profile.authn;

import foo.shibboleth.idp.authn.provider.MyloginHandler;
import edu.internet2.middleware.shibboleth.idp.config.profile.authn.AbstractLoginHandlerFactoryBean;
/**
 * Factory bean for {@link MyloginHandler}s.
 */

public class MyHandlerFactoryBean extends AbstractLoginHandlerFactoryBean{

    // URL to authenticatio servlet
    private String authenticationServletURL;

    /**
     * Gets the URL to authentication servlet.
     * @return URL to authentication servlet
     */
    public String getAuthenticationServletURL(){
        return authenticationServletURL;
    }

    /**
     * Set URL to authentication servlet
     * @param url URL to authentication servlet
     */
    public void setAuthenticationServletURL(String url){
        authenticationServletURL = url;
    }

    @Override
    protected Object createInstance() throws Exception {
        MyloginHandler handler = new MyloginHandler(authenticationServletURL);

        populateHandler(handler);

        return handler;

    }

    @Override
    public Class getObjectType() {
        return MyloginHandler.class;
    }
}

Namespace Handler

package foo.shibboleth.idp.config.profile;

import edu.internet2.middleware.shibboleth.common.config.BaseSpringNamespaceHandler;

import foo.shibboleth.idp.config.profile.authn.MyHandlerBeanDefinitionParser;

public class ProfileHandlerMyNamespaceHandler extends BaseSpringNamespaceHandler {

     /** Namespace URI. */
    public static final String NAMESPACE = "http://example.org/shibboleth/authn";

    public void init(){
        super.init();
        registerBeanDefinitionParser(MyHandlerBeanDefinitionParser.SCHEMA_TYPE,
                new MyHandlerBeanDefinitionParser());
    }
}

spring.schemas File

http\://example.org/shibboleth/authn = schema/mylogin-profile-handler.xsd

spring.handlers File

http\://example.org/shibboleth/authn = foo.shibboleth.idp.config.profile.ProfileHandlerMyNamespaceHandler

handler.xml File

Now you can make use of your LoginHandler via handler.xml.

Declare your name space, add your XML schema file to the documents schemaLocation and add your LoginHandler:

<ProfileHandlerGroup xmlns="urn:mace:shibboleth:2.0:idp:profile-handler"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xmlns:example="http://example.org/shibboleth/authn"
                     xsi:schemaLocation="urn:mace:shibboleth:2.0:idp:profile-handler classpath:/schema/shibboleth-2.0-idp-profile-handler.xsd
                     http://example.org/shibboleth/authn classpath:/schema/mylogin-profile-handler.xsd">
[..]
	<LoginHandler xsi:type="example:Mylogin">
		<AuthenticationMethod>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</AuthenticationMethod>
	</LoginHandler>