org.wso2.carbon.security.jaas.handler.SAMLCallbackHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.security.jaas.handler.SAMLCallbackHandler.java

Source

/*
 * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * 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 org.wso2.carbon.security.jaas.handler;

import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.opensaml.Configuration;
import org.opensaml.DefaultBootstrap;
import org.opensaml.saml2.core.Assertion;
import org.opensaml.saml2.core.Response;
import org.opensaml.xml.ConfigurationException;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.xml.io.UnmarshallingException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.wso2.carbon.security.jaas.CarbonCallback;
import org.wso2.carbon.security.jaas.HTTPCallbackHandler;
import org.wso2.carbon.security.jaas.util.CarbonSecurityConstants;
import org.xml.sax.SAXException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * This class builds SAML Assertion from the Authorization header
 * </p>
 */
public class SAMLCallbackHandler implements HTTPCallbackHandler {

    private static boolean openSAMLBootstrapped = false;

    private HttpRequest httpRequest;

    private Assertion samlAssertion;

    @Override
    public void setHTTPRequest(HttpRequest httpRequest) {
        this.httpRequest = httpRequest;
    }

    @Override
    public boolean canHandle() {

        if (httpRequest != null) {

            QueryStringDecoder queryStringDecoder = new QueryStringDecoder(httpRequest.getUri());
            Map<String, List<String>> requestParameters = queryStringDecoder.parameters();
            String b64SAMLResponse = requestParameters.get("SAMLResponse").get(0);

            ByteArrayInputStream SAMLResponseInputStream = null;

            try {
                String responseXml;
                responseXml = new String(org.opensaml.xml.util.Base64.decode(b64SAMLResponse), "UTF-8");
                if (!openSAMLBootstrapped) {
                    DefaultBootstrap.bootstrap();
                    openSAMLBootstrapped = true;
                }

                DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
                documentBuilderFactory.setNamespaceAware(true);
                DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
                docBuilder.setEntityResolver((publicId, systemId) -> {
                    throw new SAXException("AuthnRequest contains invalid elements. Possibly "
                            + "an XML External Entity (XXE) attack.");
                });
                SAMLResponseInputStream = new ByteArrayInputStream(responseXml.getBytes("UTF8"));
                Document document = docBuilder.parse(SAMLResponseInputStream);

                Element element = document.getDocumentElement();

                UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
                Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(element);

                XMLObject xmlObject = unmarshaller.unmarshall(element);
                if (xmlObject instanceof Response) {
                    samlAssertion = ((Response) xmlObject).getAssertions().get(0);
                } else if (xmlObject instanceof Assertion) {
                    samlAssertion = (Assertion) xmlObject;
                } else {
                    return false;
                }

                return true;

            } catch (UnsupportedEncodingException e) {
                //throw new CarbonSecurityException("Error decoding SAML Response", e);
            } catch (ConfigurationException e) {
                //throw new CarbonSecurityException("Failed to bootstrap OpenSAML 2 Library", e);
            } catch (ParserConfigurationException | SAXException | IOException | UnmarshallingException e) {
                //throw new CarbonSecurityException("Failed to parse SAML XML Response", e);
            } finally {
                if (SAMLResponseInputStream != null) {
                    try {
                        SAMLResponseInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
        return false;
    }

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

        if (callbacks != null && callbacks.length > 0) {
            if (callbacks[0] instanceof CarbonCallback) {
                ((CarbonCallback) callbacks[0]).setContent(samlAssertion);
            }
        }
    }

}