nl.surfnet.spring.security.opensaml.controller.AuthnRequestController.java Source code

Java tutorial

Introduction

Here is the source code for nl.surfnet.spring.security.opensaml.controller.AuthnRequestController.java

Source

/*
 * Copyright 2012 SURFnet bv, The Netherlands
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package nl.surfnet.spring.security.opensaml.controller;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Properties;

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

import nl.surfnet.spring.security.opensaml.AuthnRequestGenerator;
import nl.surfnet.spring.security.opensaml.SAMLMessageHandler;
import nl.surfnet.spring.security.opensaml.util.IDService;
import nl.surfnet.spring.security.opensaml.util.TimeService;
import nl.surfnet.spring.security.opensaml.xml.EndpointGenerator;

import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.opensaml.saml2.core.AuthnRequest;
import org.opensaml.saml2.metadata.Endpoint;
import org.opensaml.saml2.metadata.SingleSignOnService;
import org.opensaml.ws.message.encoder.MessageEncodingException;
import org.opensaml.xml.security.CriteriaSet;
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.security.credential.CredentialResolver;
import org.opensaml.xml.security.credential.UsageType;
import org.opensaml.xml.security.criteria.EntityIDCriteria;
import org.opensaml.xml.security.criteria.UsageCriteria;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class AuthnRequestController {
    private final static Logger LOG = LoggerFactory.getLogger(AuthnRequestController.class);

    private final TimeService timeService;
    private final IDService idService;

    private SAMLMessageHandler samlMessageHandler;

    private String assertionConsumerServiceURL;

    private String entityID;

    private CredentialResolver credentialResolver;

    private String metaDataProperties;

    public AuthnRequestController() {
        this.timeService = new TimeService();
        this.idService = new IDService();
    }

    @Required
    public void setCredentialResolver(CredentialResolver cr) {
        this.credentialResolver = cr;
    }

    @Required
    public void setSAMLMessageHandler(SAMLMessageHandler samlMessageHandler) {
        this.samlMessageHandler = samlMessageHandler;
    }

    @Required
    public void setAssertionConsumerServiceURL(String assertionConsumerServiceURL) {
        this.assertionConsumerServiceURL = assertionConsumerServiceURL;
    }

    @Required
    public void setEntityID(final String entityID) {
        this.entityID = entityID;
    }

    @RequestMapping(value = { "/OpenSAML.sso/Login" }, method = RequestMethod.GET)
    public void commence(@RequestParam(value = "target") String target, HttpServletRequest request,
            HttpServletResponse response) throws IOException {

        AuthnRequestGenerator authnRequestGenerator = new AuthnRequestGenerator(entityID, timeService, idService);
        EndpointGenerator endpointGenerator = new EndpointGenerator();

        Endpoint endpoint = endpointGenerator.generateEndpoint(SingleSignOnService.DEFAULT_ELEMENT_NAME, target,
                assertionConsumerServiceURL);

        AuthnRequest authnReqeust = authnRequestGenerator.generateAuthnRequest(target, assertionConsumerServiceURL);

        LOG.debug("Sending authnRequest to {}", target);

        Credential signingCredential;
        try {
            CriteriaSet criteriaSet = new CriteriaSet();
            criteriaSet.add(new EntityIDCriteria(entityID));
            criteriaSet.add(new UsageCriteria(UsageType.SIGNING));
            signingCredential = credentialResolver.resolveSingle(criteriaSet);

            // Could be injected from somewhere. Not yet needed currently.
            String relayState = null;

            samlMessageHandler.sendSAMLMessage(authnReqeust, endpoint, response, relayState, signingCredential);
        } catch (MessageEncodingException mee) {
            LOG.error("Could not send authnRequest to Identity Provider.", mee);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } catch (org.opensaml.xml.security.SecurityException e) {
            LOG.error("Could not send authnRequest to Identity Provider.", e);
        }
    }

    @RequestMapping(value = { "/OpenSAML.sso/Metadata" }, method = RequestMethod.GET)
    public void metaData(HttpServletResponse response) throws IOException {
        /*
         * see https://rnd.feide.no/2010/01/05/
         * metadata_aggregation_requirements_specification/#section_5_5_3
         */
        response.setHeader("Content-Type", "application/xml");
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

        String result = IOUtils.toString(new ClassPathResource("metadata-template-sp.xml").getInputStream());

        result = result.replace("%VALID_UNTIL%",
                df.format(new DateTime().toDateMidnight().toDateTime().plusDays(1).toDate()));
        result = result.replace("%ENTITY_ID%", entityID);
        result = result.replace("%ASSERTION_CONSUMER_SERVICE_URL%", assertionConsumerServiceURL);

        Properties props = new Properties();
        props.load(new ClassPathResource("metadata.defaults.properties").getInputStream());

        if (StringUtils.hasText(metaDataProperties)) {
            ClassPathResource classPathResource = new ClassPathResource(metaDataProperties);
            if (classPathResource.exists()) {
                props.load(classPathResource.getInputStream());
            }
        }

        result = result.replace("%NAMEID_FORMAT%", props.getProperty("nameid-format"));

        result = result.replace("%SERVICE_NAME_EN%", props.getProperty("service-name-en"));
        result = result.replace("%SERVICE_NAME_NL%", props.getProperty("service-name-nl"));
        result = result.replace("%SERVICE_DESCRIPTION_EN%", props.getProperty("service-description-en"));
        result = result.replace("%SERVICE_DESCRIPTION_NL%", props.getProperty("service-description-nl"));

        result = result.replace("%CONTACT_PERSON_ADMINISTRATIVE_GIVEN_NAME%",
                props.getProperty("contact-person-administrative-given-name"));
        result = result.replace("%CONTACT_PERSON_ADMINISTRATIVE_SUR_NAME%",
                props.getProperty("contact-person-administrative-sur-name"));
        result = result.replace("%CONTACT_PERSON_ADMINISTRATIVE_EMAIL%",
                props.getProperty("contact-person-administrative-email"));

        result = result.replace("%CONTACT_PERSON_TECHNICAL_GIVEN_NAME%",
                props.getProperty("contact-person-technical-given-name"));
        result = result.replace("%CONTACT_PERSON_TECHNICAL_SUR_NAME%",
                props.getProperty("contact-person-technical-sur-name"));
        result = result.replace("%CONTACT_PERSON_TECHNICAL_EMAIL%",
                props.getProperty("contact-person-technical-email"));

        result = result.replace("%CONTACT_PERSON_SUPPORT_GIVEN_NAME%",
                props.getProperty("contact-person-support-given-name"));
        result = result.replace("%CONTACT_PERSON_SUPPORT_SUR_NAME%",
                props.getProperty("contact-person-support-sur-name"));
        result = result.replace("%CONTACT_PERSON_SUPPORT_EMAIL%",
                props.getProperty("contact-person-support-email"));

        response.getOutputStream().write(result.getBytes());
        response.flushBuffer();

    }

    public void setMetaDataProperties(String metaDataProperties) {
        this.metaDataProperties = metaDataProperties;
    }
}