com.zimbra.examples.extns.samlprovider.SamlRequestHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.zimbra.examples.extns.samlprovider.SamlRequestHandler.java

Source

/*
 * ***** BEGIN LICENSE BLOCK *****
 * Zimbra Collaboration Suite Server
 * Copyright (C) 2010, 2013, 2014 Zimbra, Inc.
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software Foundation,
 * version 2 of the License.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 * ***** END LICENSE BLOCK *****
 */
package com.zimbra.examples.extns.samlprovider;

import com.zimbra.common.soap.Element;
import com.zimbra.common.soap.SoapProtocol;
import com.zimbra.common.util.SystemUtil;
import com.zimbra.common.util.ZimbraLog;
import com.zimbra.cs.extension.ExtensionHttpHandler;
import org.dom4j.Namespace;
import org.dom4j.QName;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * This HTTP handler handles requests at /service/extension/samlAuthority and acts as a dummy
 * SAML Authority. It responds to &lt;samlp:AssertionIDRequest&gt; requests. See
 * <a href="http://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf">
 * SAML 2.0 Core Spec</a>.
 *
 * <p>
 * It reads /opt/zimbra/conf/issued-saml-assertions.xml file which stores the set of assertions
 * already issued by this SAML Authority.
 *
 * @author vmahajan
 */
public class SamlRequestHandler extends ExtensionHttpHandler {

    private static final Namespace SAML_PROTOCOL_NS = new Namespace("samlp",
            "urn:oasis:names:tc:SAML:2.0:protocol");

    private static Map<String, Element> samlAssertionsMap = new HashMap<String, Element>();

    static {
        try {
            Element issuedAssertionsElt = Element
                    .parseXML(new FileInputStream("/opt/zimbra/conf/issued-saml-assertions.xml"));
            List<Element> assertionsList = issuedAssertionsElt.getPathElementList(new String[] { "Assertion" });
            for (Element assertionElt : assertionsList) {
                samlAssertionsMap.put(assertionElt.getAttribute("ID"), assertionElt);
            }
        } catch (Exception e) {
            ZimbraLog.extensions.error(SystemUtil.getStackTrace(e));
            ZimbraLog.extensions.error("Exception in loading issued assertions");
        }
    }

    /**
     * The path under which the handler is registered for an extension.
     *
     * @return path
     */
    @Override
    public String getPath() {
        return "/samlAuthority";
    }

    /**
     * Processes HTTP POST requests.
     *
     * @param req request message
     * @param resp response message
     * @throws java.io.IOException
     * @throws javax.servlet.ServletException
     */
    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        Element respEnv;
        try {
            Element reqEnv = Element.parseXML(req.getInputStream());
            Element reqBody = reqEnv.getElement("Body");
            Element requestElt = reqBody.getElement("AssertionIDRequest");
            Element idRefElt = requestElt.getElement("AssertionIDRef");

            respEnv = new Element.XMLElement(new QName("Envelope", SoapProtocol.Soap11.getNamespace()));
            Element respBody = respEnv.addElement(new QName("Body", SoapProtocol.Soap11.getNamespace()));
            Element respElt = respBody.addElement(new QName("Response", SAML_PROTOCOL_NS));
            Date now = new Date();
            respElt.addAttribute("ID", "id-" + now.getTime());
            respElt.addAttribute("Version", "2.0");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
            dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
            respElt.addAttribute("IssueInstant", dateFormat.format(now));
            respElt.addAttribute("InResponseTo", requestElt.getAttribute("ID"));
            Element statusElt = respElt.addElement(new QName("Status", SAML_PROTOCOL_NS));
            Element statusCodeElt = statusElt.addElement(new QName("StatusCode", SAML_PROTOCOL_NS));

            if (requestElt != null) {
                String assertionId = idRefElt.getTextTrim();
                Element assertion = samlAssertionsMap.get(assertionId);
                if (assertion == null) {
                    statusCodeElt.addAttribute("Value", "urn:oasis:names:tc:SAML:2.0:status:Requester");
                    Element statusMsgElt = statusElt.addElement(new QName("StatusMessage", SAML_PROTOCOL_NS));
                    statusMsgElt.addText("No assertion found corresponding to the id: " + assertionId);
                } else {
                    statusCodeElt.addAttribute("Value", "urn:oasis:names:tc:SAML:2.0:status:Success");
                    respElt.addElement(assertion.clone());
                }
            }
        } catch (Exception e) {
            ZimbraLog.extensions.error(SystemUtil.getStackTrace(e));
            throw new IOException(e);
        }

        String respEnvStr = respEnv.toString();
        if (ZimbraLog.extensions.isDebugEnabled())
            ZimbraLog.extensions.debug("SAML response: " + respEnvStr);
        resp.getOutputStream().print(respEnvStr);
    }
}