All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.identity.federation.services.FSSOAPService Maven / Gradle / Ivy

There is a newer version: 14.8.4
Show newest version
/**
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
 *
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the License at
 * https://opensso.dev.java.net/public/CDDLv1.0.html or
 * opensso/legal/CDDLv1.0.txt
 * See the License for the specific language governing
 * permission and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at opensso/legal/CDDLv1.0.txt.
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * $Id: FSSOAPService.java,v 1.4 2008/11/10 22:56:58 veiming Exp $
 *
 */

package com.sun.identity.federation.services;

import com.sun.identity.federation.common.FSException;
import com.sun.identity.federation.common.FSUtils;
import com.sun.identity.federation.common.IFSConstants;
import com.sun.identity.federation.common.LogUtil;
import com.sun.identity.liberty.ws.meta.jaxb.ProviderDescriptorType;
import com.sun.identity.shared.xml.XMLUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import javax.xml.soap.Detail;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPMessage;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
    
/**
 * Utils to handle SOAP profiles.
 */
public class FSSOAPService {
    private static FSSOAPService instance = null;
    private static MessageFactory fac = null;
    private static SOAPConnectionFactory scf = null;

    static {
        try {
            fac = MessageFactory.newInstance();
        } catch(Exception ex) {
            FSUtils.debug.error(
                FSUtils.bundle.getString( "missingSOAPMessageFactory"), ex);
        }

        try {
            scf = SOAPConnectionFactory.newInstance();
        } catch(SOAPException e) {
            FSUtils.debug.error("FSSOAPService", e);
        }
    };
    
    /* do nothing constructor */
    private FSSOAPService() {
    }
    
    /*
     * Binds the passed object xml string to SOAP message.
     * The SOAP Message will then be sent across to the remote
     * provider for processing.
     * @param xmlString the request/response xml string to be bound
     * @return SOAPMessage constructed from the xml string
     */
    public SOAPMessage bind(String xmlString) {
        SOAPMessage msg = null;
        MimeHeaders mimeHeaders = new MimeHeaders();
        mimeHeaders.addHeader("Content-Type","text/xml");
        StringBuffer envBegin = new StringBuffer(100);
        envBegin.append("<").append(IFSConstants.SOAP_ENV_PREFIX).
            append(":Envelope").append(IFSConstants.SPACE).append("xmlns:").
            append(IFSConstants.SOAP_ENV_PREFIX).append("=\"").
            append(IFSConstants.SOAP_URI).append("\">").append(IFSConstants.NL).
            append("<").append(IFSConstants.SOAP_ENV_PREFIX).
            append(":Body>").append(IFSConstants.NL);
        
        StringBuffer envEnd = new StringBuffer(100);
        envEnd.append(IFSConstants.START_END_ELEMENT).
            append(IFSConstants.SOAP_ENV_PREFIX).append(":Body>").
            append(IFSConstants.NL).
            append(IFSConstants.START_END_ELEMENT).
            append(IFSConstants.SOAP_ENV_PREFIX).
            append(":Envelope>").append(IFSConstants.NL);
        try {
            StringBuffer sb = new StringBuffer(300);
            sb.append(envBegin).append(xmlString).append(envEnd);
            if (FSUtils.debug.messageEnabled()) {
                FSUtils.debug.message("response created is: "+sb.toString() +
                        "\n--------------------");
            }
            ByteArrayOutputStream bop = new ByteArrayOutputStream();
            bop.write(sb.toString().getBytes(IFSConstants.DEFAULT_ENCODING));
            msg = fac.createMessage(mimeHeaders, new ByteArrayInputStream(
                bop.toByteArray()));
        } catch(Exception e ) {
            FSUtils.debug.error("could not build response:", e);
            return null;
        }
        return msg;
    }
    
    /*
     * Sends the passed SOAPMessage to the SOAPEndpoint URL
     * that is passed.
     * @param msg the SOAPMessage to be sent
     * @param soapEndPoint the SOAPEndpoint URL of remote provider
     * @return SOAPMessage response message from remote provider
     * @exception IOException, SOAPException if error occurrs
     */
    public SOAPMessage sendMessage(
        SOAPMessage msg,
        String soapEndPoint
    ) throws IOException, SOAPException 
    {
        try {
            FSUtils.debug.message("just started in func sendMessage");
            if (soapEndPoint == null) {
                FSUtils.debug.error("createSOAPReceiverURL Error!");
                String[] data = { soapEndPoint };
                LogUtil.error(
                    Level.INFO,
                    LogUtil.FAILED_SOAP_URL_END_POINT_CREATION,
                    data);
                return null;
            }
            // Send the message to the provider using the connection.
            ByteArrayOutputStream output  = new ByteArrayOutputStream();
            msg.writeTo(output);
            String xmlString = output.toString(IFSConstants.DEFAULT_ENCODING);
            if (FSUtils.debug.messageEnabled()) {
                FSUtils.debug.message("SENDING message: \n " + xmlString +
                    "\nURLEndpoint :" + soapEndPoint + "\nSOAP CALL");
            }
            SOAPConnection con = scf.createConnection();
            SOAPMessage  reply = con.call(msg, soapEndPoint);
            FSUtils.debug.message("SOAP CALL COMPLETED");
            if (reply == null) {
                return null;
            }
            // check the SOAP message for any SOAP related errors
            // before passing control to SAML processor
            output  = new ByteArrayOutputStream();
            reply.writeTo(output);
            xmlString = output.toString(IFSConstants.DEFAULT_ENCODING);
            if (FSUtils.debug.messageEnabled()) {
                FSUtils.debug.message("REPLIED message: \n " + xmlString);
            }
            return reply;
        } catch(Exception e){
            FSUtils.debug.error("In catch of sendMessage" , e);
            return null;
        }
    }
    
    /*
     * Method to send the passed SOAPMessage to the SOAPEndpoint URL
     * that is passed. The SOAP Message will then be sent across to the remote
     * provider in order to perform federation termination.
     * @param msg the FSFederationTerminationNotification 
     *  SOAPMesage to be sent
     * @param soapEndPoint the SOAPEndpoint URL of remote provider
     * @return boolean true if successful else false
     */
    public boolean sendTerminationMessage(
        SOAPMessage msg, String soapEndPoint) 
    {
        try {
            FSUtils.debug.message("started in func sendTerminationMessage");
            if(soapEndPoint == null) {
                FSUtils.debug.error("createSOAPReceiverURL Error!");
                String[] data =
                    { FSUtils.bundle.getString("failCreateURLEndpoint") };
                LogUtil.error(Level.INFO,
                              LogUtil.FAILED_SOAP_URL_END_POINT_CREATION,
                              data);
                return false;
            }
            // Send the message to the provider using the connection.
            ByteArrayOutputStream output  = new ByteArrayOutputStream();
            msg.writeTo(output);
            if (FSUtils.debug.messageEnabled()) {
                String xmlString = output.toString(
                    IFSConstants.DEFAULT_ENCODING);
                FSUtils.debug.message("SENDING message: \n " + xmlString);
                FSUtils.debug.message("URLEndpoint :" + soapEndPoint);
            }
            SOAPConnection con = scf.createConnection();
            SOAPMessage  reply = con.call(msg, soapEndPoint);
            FSUtils.debug.message("SOAP CALL COMPLETED");
            return true;
        } catch(Exception e){
            if(FSUtils.debug.messageEnabled()) {
                FSUtils.debug.message("In catch of sendTerminationMessage", e);
            }
            return false;
        }
    }

    /*
     * Parses the SOAPMessage and return the Element
     * corresponding to the liberty message(request/response).
     * @param message the SOAPMessage to be parsed
     * @return Element corresponding to liberty request/response
     */
    public Element parseSOAPMessage(SOAPMessage message) {
        FSUtils.debug.message("FSSOAPService.parseSOAPMessage: Called");
        ByteArrayOutputStream bop = null;
        String xmlString = null;
        
        // first check if there was any soap error during verifyHost()
        try {
            // check the SOAP message for any SOAP
            // related errros before passing control to SAM processor
            bop = new ByteArrayOutputStream();
            message.writeTo(bop);
            xmlString = bop.toString(IFSConstants.DEFAULT_ENCODING);
            Document doc = XMLUtils.toDOMDocument(xmlString, FSUtils.debug);
            Element root = doc.getDocumentElement();
            String rootName  = root.getLocalName();
            if ((rootName == null) ||(rootName.length() == 0)) {
                FSUtils.debug.error("FSSOAPService.parseSOAPMessage: " +
                    "Local name of the SOAPElement in  the" +
                    " SOAPMessage passed seems to be missing");
                return null;
            }
            if (!(rootName.equals("Envelope")) ||
                (!(root.getNamespaceURI().equals(IFSConstants.SOAP_URI)))) 
            {
                FSUtils.debug.error(
                    "FSSOAPService.parseSOAPMessage: Could not" +
                    "parse SOAPMessage, either root element is not Envelope" +
                    " or invalid name space");
                return null;
            }
            NodeList nlbody = root.getChildNodes();
            int blength = nlbody.getLength();
            if (blength <=0 ) {
                FSUtils.debug.error("FSSOAPService.parseSOAPMessage: Message " +
                    "does not have body");
                return null;
            }
            Node child = null;
            boolean found = false;
            for (int i = 0; i < blength; i++) {
                child =(Node)nlbody.item(i);
                if (child.getNodeType() != Node.ELEMENT_NODE) {
                    continue;
                }
                String childName = child.getLocalName();
                if (childName.equals("Body")) {
                    found = true;
                    break; // found the message body
                }
            }
            if (!found) {
                FSUtils.debug.error("FSSOAPService.parseSOAPMessage: Message " +
                    "does not have body1");
                return null;
            }
            Element body =(Element)child;
            //Is soap-env:Fault
            NodeList nl  = body.getElementsByTagNameNS(
                IFSConstants.SOAP_URI, "Fault");
            int length = nl.getLength();
            
            if (length > 1) {
                return null;
            }
            if (length != 0 ) {
                child =(Node)nl.item(0);
                if (child.getNodeType() != Node.ELEMENT_NODE) {
                        return null;
                }
                if (child.getLocalName().equalsIgnoreCase("Fault")) {
                    if (FSUtils.debug.messageEnabled()) {
                        FSUtils.debug.message("FSSOAPService." +
                            " parseSOAPMessage soap-env:Fault found in the " +
                            "SOAPMessage");
                    }
                    return(Element)child;
                }
            }

            try {
                //Is samlp:Request
                child = getSAMLElement(body, "Request");
                if (child != null) {
                   return (Element) child;
                }
                //Is samlp:Response
                child = getSAMLElement(body, "Response");
                if (child != null) {
                   return (Element) child;
                }
                //Is lib:AuthnResponseEnvelope
                child = getFederationElement(body, "AuthnResponseEnvelope");
                if (child != null) {
                   return (Element) child;
                }
                //Is lib:AuthnRequest
                child = getFederationElement(body, "AuthnRequest");
                if (child != null) {
                   return (Element) child;
                }
                //Is lib:RegisterNameIdentifierRequest
                child = getFederationElement(body,
                    "RegisterNameIdentifierRequest");
                if (child != null) {
                   return (Element) child;
                }
                //Is lib:RegisterNameIdentifierResponse
                child = getFederationElement(body,
                    "RegisterNameIdentifierResponse");
                if (child != null) {
                   return (Element) child;
                }
                //Is lib:FederationTerminationNotification
                child = getFederationElement(body,
                    "FederationTerminationNotification");
                if (child != null) {
                   return (Element) child;
                }
                //Is lib:LogoutRequest
                child = getFederationElement(body, "LogoutRequest");
                if (child != null) {
                   return (Element) child;
                }
                //Is lib:LogoutResponse
                child = getFederationElement(body, "LogoutResponse");
                if (child != null) {
                   return (Element) child;
                }
                //Is lib:NameIdentifierMappingRequest
                child = getFederationElement(body, 
                    "NameIdentifierMappingRequest");
                if (child != null) {
                   return (Element) child;
                }
                //Is lib:NameIdentifierMappingResponse
                child = getFederationElement(body, 
                    "NameIdentifierMappingResponse");
                if (child != null) {
                   return (Element) child;
                }
                FSUtils.debug.error(
                    "FSSOAPService.parseMessage:Invalid message type.");
            } catch (FSException e) {
                if (FSUtils.debug.messageEnabled()) {
                    FSUtils.debug.message("SOAPService.parseSOAPMessage: "
                        + "Couldn't object protocol message element.");
                }
            }
            return null;
        } catch(Exception e){
            FSUtils.debug.error("FSSOAPService.parseSOAPMessage: Exception ",e);
            return null;
        }
    }
    
    private Node getSAMLElement(Element body, String nodeName) 
        throws FSException
    {
        NodeList nl = body.getElementsByTagNameNS(
             IFSConstants.PROTOCOL_NAMESPACE_URI, nodeName);
        int length = nl.getLength();
        if (length > 1) {
            throw new FSException((String) null);
        }
        if (length != 0 ) {
            return (Node)nl.item(0);
        }
        return null;
    }

    private Node getFederationElement(Element body, String nodeName) 
        throws FSException
    {
        NodeList nl = body.getElementsByTagNameNS(
             IFSConstants.LIB_NAMESPACE_URI, nodeName);
        int length = nl.getLength();
        if (length == 0) {
             nl = body.getElementsByTagNameNS(
                 IFSConstants.FF_12_XML_NS, nodeName);
             length = nl.getLength();
        }
        if (length > 1) {
            throw new FSException((String) null);
        }
        if (length != 0 ) {
            return (Node)nl.item(0);
        }
        return null;
    }

    /*
     * Sends a synchronous SOAPMessage to remote provider.
     * @param response the http response object
     * @param msg the SOAPMessage to be sent
     * @param partnerDecriptor the remote provider meta descriptor
     * @param needAuthn determines forced authn
     * @return SOAPMessage corresponding to liberty 
     *  request/response message
     * @exception IOException, SOAPException if error occurrs
     */
    public SOAPMessage doSyncCall(
        HttpServletResponse response,
        SOAPMessage msg,
        ProviderDescriptorType partnerDecriptor,
        boolean needAuthn
    ) throws IOException, SOAPException 
    {
        FSUtils.debug.message("FSSOAPService.doSyncCall: Called");

        String soapURL = createSOAPReceiverUrl(
            response, partnerDecriptor, false);
        if (soapURL == null) {
            FSUtils.debug.error("FSSOAPService.doSyncCall: " +
                "createSOAPReceiverURL Error!");
            String[] data = 
                { FSUtils.bundle.getString("failCreateURLEndpoint") };
            LogUtil.error(Level.INFO,
                        LogUtil.FAILED_SOAP_URL_END_POINT_CREATION,
                        data);
            return null;
        }
        // Send the message to the provider using the connection.
        ByteArrayOutputStream output  = new ByteArrayOutputStream();
        msg.writeTo(output);
        String xmlString = output.toString(IFSConstants.DEFAULT_ENCODING);
        if (FSUtils.debug.messageEnabled()) {
            FSUtils.debug.message(
                "FSSOAPService.doSyncCall: SENDING message\n" + xmlString);
        }
        SOAPConnection con = scf.createConnection();
        SOAPMessage  reply = con.call(msg, soapURL);
        if (reply == null) {
            response.sendError(response.SC_INTERNAL_SERVER_ERROR,
                FSUtils.bundle.getString("noReplyfromSOAPReceiver"));
            return null;
        }
        
        // check the SOAP message for any SOAP related errors
        // before passing control to SAML processor
        output  = new ByteArrayOutputStream();
        reply.writeTo(output);
        xmlString = output.toString(IFSConstants.DEFAULT_ENCODING);
        if (FSUtils.debug.messageEnabled()) {
            FSUtils.debug.message(
                "FSSOAPService.doSyncCall: REPLIED message:\n" + xmlString);
        }
        return reply;
    }
    
    /*
     * Method to construct the URLEndpoint depending on whether basic
     * authentication of one provider to another is to be done. Otherwise the
     * SOAPEndpoint of the remote provider is returned
     * @param response the response object
     * @param partnerDecriptor the remote provider descriptor
     * @param needAuthn determines forced authn
     * @return Element corresponding to liberty request/response
     */
    public String createSOAPReceiverUrl(
        HttpServletResponse response,
        ProviderDescriptorType partnerDecriptor,
        boolean needAuthn
    ) throws IOException 
    {
        // TODO: need to handle needAuthn correctly
        // TODO: need to retrieve auth type, user name and password from meta
        //basic authentication
        String username = null;
        String password = null;
        String to = partnerDecriptor.getSoapEndpoint();
        String authtype = null;
        String soapURL  = null;
        if (needAuthn) {
            int idnx = -1;
            if ((idnx = to.indexOf("//")) == -1) {
                FSUtils.debug.error("FSSOAPService.createSOAPReceiverUrl: " +
                    "createSOAPReceiverUrl: SOAP-Receiver-URL illegal format.");
                response.sendError(response.SC_INTERNAL_SERVER_ERROR,
                    FSUtils.bundle.getString("illegalFormatSOAPUrl"));
                return null;
            }
            String protocol = to.substring(0, idnx-1);
            if (authtype.equalsIgnoreCase(IFSConstants.BASICAUTH) ||
                authtype.equalsIgnoreCase(IFSConstants.NOAUTH)) 
            {
                if (!protocol.equals(IFSConstants.HTTP)) {
                    String[] data = { protocol , authtype }; 
                    LogUtil.error(
                        Level.INFO,
                        LogUtil.MISMATCH_AUTH_TYPE_AND_PROTOCOL,
                        data);
                    response.sendError(response.SC_INTERNAL_SERVER_ERROR,
                        FSUtils.bundle.getString(
                            "mismatchAuthTypeandProtocol"));
                    return null;
                }
            } else if(authtype.equalsIgnoreCase(IFSConstants.SSLWITHBASICAUTH)||
                authtype.equalsIgnoreCase(IFSConstants.SSL)) 
            {
                if (!protocol.equals(IFSConstants.HTTPS)) {
                    String[] data = { protocol, authtype };
                    LogUtil.error(Level.INFO,
                        LogUtil.MISMATCH_AUTH_TYPE_AND_PROTOCOL,
                        data);
                    response.sendError(response.SC_INTERNAL_SERVER_ERROR,
                        FSUtils.bundle.getString(
                            "mismatchAuthTypeandProtocol"));
                    return null;
                }
            } else {
                String[] data = { authtype };
                LogUtil.error(Level.INFO,LogUtil.WRONG_AUTH_TYPE,data);
                response.sendError(response.SC_INTERNAL_SERVER_ERROR,
                    FSUtils.bundle.getString("wrongAuthType"));
                return null;
            }
            
            if (authtype.equalsIgnoreCase(IFSConstants.BASICAUTH) ||
                authtype.equalsIgnoreCase(IFSConstants.SSLWITHBASICAUTH)) 
            {
                Map userMap = null; //partnerDecriptor.getAuthType();
                username =(String) userMap.get(IFSConstants.USER);
                password =(String) userMap.get(IFSConstants.PASSWORD);
                if (username == null || password == null) {
                    FSUtils.debug.error(
                        "FSSOAPService.createSOAPReceiverUrl: " +
                        "PartnerSite required basic authentication. But " +
                        "the user name used for authentication is null.");
                    response.sendError(response.SC_INTERNAL_SERVER_ERROR,
                        FSUtils.bundle.getString("wrongConfigBasicAuth"));
                    return null;
                }
                StringBuffer toSOAP = new StringBuffer(100);
                toSOAP.append(to.substring(0, idnx+2)).append(username).
                    append(":").append(password).append("@").
                    append(to.substring(idnx+2));
                soapURL  = toSOAP.toString();
            }
            return null;
        } else {
            soapURL = to;
        }
        if (FSUtils.debug.messageEnabled()) {
            FSUtils.debug.message(
                "FSSOAPService.createSOAPReceiverUrl: Sending message to URL: "
                + soapURL);
        }
        String[] data = { soapURL };
        LogUtil.access(Level.FINER,"SOAP_RECEIVER_URL", data);
        return soapURL;
    }
    
    /**
     * Forms a SOAP Fault and puts it in the SOAP Message's Body.
     *
     * @param faultcode fault code to be set in SOAPMEssage
     * @param faultString fault string
     * @param detail the details of the fault condition
     * @return SOAPMessage containing the SOAP fault
     */
    public SOAPMessage formSOAPError(
        String faultcode,
        String faultString,
        String detail
    ) {
        SOAPMessage msg = null ;
        SOAPEnvelope envelope = null;
        SOAPFault sf = null;
        SOAPBody body = null;
        SOAPElement se = null;
        try {
            msg = fac.createMessage();
            envelope = msg.getSOAPPart().getEnvelope();
            body = envelope.getBody();
            sf = body.addFault();
            Name qname = envelope.createName(
                faultcode, null, IFSConstants.SOAP_URI);
            sf.setFaultCode(qname);
            sf.setFaultString(FSUtils.bundle.getString(faultString));
            if ((detail != null) && !(detail.length() == 0)) {
                Detail det = sf.addDetail();
                se =(SOAPElement)det.addDetailEntry(envelope.createName(
                    "Problem"));
                se.addAttribute(envelope.createName("details"), 
                    FSUtils.bundle.getString(detail));
            }
        } catch( SOAPException e ) {
            FSUtils.debug.error(
                "FSSOAPService.formSOAPError:", e);
            return null;
        }
        return msg;
    }
    
    /**
     * Returns an instance of FSSOAPService instance.
     *
     * @return an instance of FSSOAPService instance.
     */
    public static FSSOAPService getInstance() {
        FSUtils.debug.message("FSSOAPService.getInstance: Called");
        synchronized(FSServiceManager.class) {
            if (instance == null){
                FSUtils.debug.message(
                    "Constructing a new instance of FSSOAPService");
                instance = new FSSOAPService();
            }
            return instance;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy