zoukankan      html  css  js  c++  java
  • opensaml的SOAP消息发送和接收

    首先是Saml工具类

    SamlUtils
    package xuzs.common;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import javax.xml.namespace.QName;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    
    import org.opensaml.DefaultBootstrap;
    import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
    import org.opensaml.xml.Configuration;
    import org.opensaml.xml.XMLObject;
    import org.opensaml.xml.XMLObjectBuilder;
    import org.opensaml.xml.io.Marshaller;
    import org.opensaml.xml.io.MarshallingException;
    import org.opensaml.xml.io.UnmarshallingException;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    import org.xml.sax.SAXException;
    
    public class SamlUtils {
        
        public static final String ACT_REQ = "samlp:ActivateRequest";
        public static final String ACT_RESP = "samlp:ActivateResponse";
        public static final String LGOUT_REQ = "samlp:LogoutRequest";
        public static final String LGOUT_RESP = "samlp:LogoutResponse";
    
        private static DocumentBuilder builder;
    
        private static SecureRandomIdentifierGenerator generator;
        private String issuerURL;
    
        public String getIssuerURL() {
            return issuerURL;
        }
    
        public void setIssuerURL(String issuerURL) {
            this.issuerURL = issuerURL;
        }
    
        static {
            try {
                // 此处初始化所有builder等操作
                DefaultBootstrap.bootstrap();
                generator = new SecureRandomIdentifierGenerator();
                DocumentBuilderFactory factory = DocumentBuilderFactory
                        .newInstance();
                factory.setNamespaceAware(true);
                builder = factory.newDocumentBuilder();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
        public SamlUtils() {
            this(null);
        }
    
        public SamlUtils(String issuerURL) {
            this.issuerURL = issuerURL;
        }
        
        /**
         * 产生ID
         * @return 唯一ID
         */
        public static String generateId(){
            return generator.generateIdentifier().substring(1);
        }
    
        /**
         * 构造对象
         * @param cls
         * @param qname
         * @return
         */
        @SuppressWarnings("unchecked")
        public static <T> T create(Class<T> cls, QName qname) {
            return (T) ((XMLObjectBuilder<?>) Configuration.getBuilderFactory()
                    .getBuilder(qname)).buildObject(qname);
        }
    
        /**
         */
        public static Document asDOMDocument(XMLObject object){
            Document document = builder.newDocument();
            Marshaller out = Configuration.getMarshallerFactory().getMarshaller(
                    object);
            try {
                out.marshall(object, document);
            } catch (MarshallingException e) {
                e.printStackTrace();
            }
            return document;
        }
    
        public static XMLObject fromElement(Element element){
            XMLObject xmlObject = null;
            try {
                xmlObject = Configuration.getUnmarshallerFactory().getUnmarshaller(element)
                        .unmarshall(element);
            } catch (UnmarshallingException e) {
                e.printStackTrace();
            }
            return xmlObject;
        }
        
        public static Document parse(InputStream is){
            Document doc = null;
            try {
                doc = builder.parse(is);
            } catch (SAXException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return doc;
        }
        
        /**
         * 替换Document中指定的Node的名称
         * @param doc 要替换的Document
         * @param oNodeName 被替换的节点名称
         * @param tNodeName 要替换为的节点名称
         * @return
         */
        public static boolean renameNode(Document doc, String oNodeName,
                String tNodeName) {
            NodeList nodes = doc.getElementsByTagName(oNodeName);
            if (nodes.getLength() > 0) {
                Node node = nodes.item(0);
                doc.renameNode(node, node.getNamespaceURI(), tNodeName);
                return true;
            }
            return false;
        }
    }

    然后是发送的客户端类

    SamlMsgClient
    package xuzs.common;
    
    import org.opensaml.ws.soap.client.BasicSOAPMessageContext;
    import org.opensaml.ws.soap.client.http.HttpClientBuilder;
    import org.opensaml.ws.soap.client.http.HttpSOAPClient;
    import org.opensaml.ws.soap.common.SOAPException;
    import org.opensaml.ws.soap.soap11.Body;
    import org.opensaml.ws.soap.soap11.Envelope;
    import org.opensaml.xml.XMLObject;
    import org.opensaml.xml.parse.BasicParserPool;
    import org.opensaml.xml.security.SecurityException;
    
    public class SamlMsgClient {
    
        /**
         * 对端地址
         */
        private String serverUrl;
    
        protected String getServerUrl() {
            return serverUrl;
        }
    
        protected void setServerUrl(String serverUrl) {
            this.serverUrl = serverUrl;
        }
    
        public SamlMsgClient(String serverUrl) {
            super();
            this.serverUrl = serverUrl;
        }
    
        /**
         * 直接发送samlXml对象,并返回samlXml对象
         * 
         * @param reqXmlObj 需要发送的消息体
         * @return 结果对象
         */
        public XMLObject send(XMLObject reqXmlObj) {
            // 声明返回对象
            XMLObject respXmlObj = null;
            // 构造消息信封
            Envelope envelope = SamlUtils.create(Envelope.class,
                    Envelope.DEFAULT_ELEMENT_NAME);
            Body body = SamlUtils.create(Body.class, Body.DEFAULT_ELEMENT_NAME);
            // 将请求对象放入信封体
            body.getUnknownXMLObjects().add(reqXmlObj);
            envelope.setBody(body);
            // 构造SOAP消息上下文,并将信封放入其中
            BasicSOAPMessageContext soapContext = new BasicSOAPMessageContext();
            soapContext.setOutboundMessage(envelope);
            // 构造消息发送客户端
            HttpClientBuilder clientBuilder = new HttpClientBuilder();
            HttpSOAPClient soapClient = new HttpSOAPClient(
                    clientBuilder.buildClient(), new BasicParserPool());
    
            try {
                // 发送消息体,并返回结果对象
                soapClient.send(serverUrl, soapContext);
                Envelope respEnvelope = (Envelope) soapContext.getInboundMessage();
                if (respEnvelope.getBody().getUnknownXMLObjects().size() > 0) {
                    respXmlObj = respEnvelope.getBody().getUnknownXMLObjects().get(0);
                }
            } catch (SOAPException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            }
            return respXmlObj;
        }
    
        /**
         * 发送samlXml对象,但在发送和接收时做消息名称的修改
         * 
         * @param reqXmlObj 发送消息体,此处可为LogoutRequest
         * @param oReqName 请求消息中被替换的节点名称
         * @param tReqName 请求消息中要替换成的节点名称
         * @param oRespName 响应消息中被替换的节点名称
         * @param tRespName 响应消息中要替换成的节点名称
         * @return 响应消息体,此处可为LogoutResponse
         */
        public XMLObject send(XMLObject reqXmlObj, String oReqName,
                String tReqName, String oRespName, String tRespName) {
            // 声明返回对象
            XMLObject respXmlObj = null;
            // 替换请求对象的消息节点名称
            SamlUtils.renameNode(SamlUtils.asDOMDocument(reqXmlObj), oReqName,
                    tReqName);
            // 发送SOAP消息,并返回结果
            XMLObject tempXmlObj = send(reqXmlObj);
            // 替换响应对象的消息节点名称
            SamlUtils.renameNode(tempXmlObj.getDOM().getOwnerDocument(), oRespName,
                    tRespName);
            // 构造返回对象,此对象为新建对象
            respXmlObj = SamlUtils.fromElement(tempXmlObj.getDOM());
            return respXmlObj;
        }
        
    }

    接收端

    SoapServlet
    package xuzs.servlet;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Date;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.opensaml.saml2.core.LogoutRequest;
    import org.opensaml.saml2.core.LogoutResponse;
    import org.opensaml.ws.soap.soap11.Envelope;
    import org.opensaml.xml.util.XMLHelper;
    import org.w3c.dom.Document;
    
    import xuzs.common.MessageGen;
    import xuzs.common.SamlUtils;
    
    public class SoapServlet extends HttpServlet {
    
        protected static final long serialVersionUID = 1L;
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws IOException, ServletException {
            request.setAttribute("test", new Date());
            this.getServletContext().getRequestDispatcher("/index.jsp")
                    .forward(request, response);
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws IOException, ServletException {
            // 首先从request中取出SOAP消息信封
            Document reqDom = SamlUtils.parse(request.getInputStream());
            // @debug 打印消息体
            System.out.println("Receive Message : \n"
                    + XMLHelper.nodeToString(reqDom.getDocumentElement()));
    
            // 登出消息
            if (reqDom.getElementsByTagName(SamlUtils.LGOUT_REQ).getLength() > 0) {
                Envelope envelope = (Envelope) SamlUtils.fromElement(reqDom
                        .getDocumentElement());
                LogoutRequest logoutRequest = (LogoutRequest) envelope.getBody()
                        .getUnknownXMLObjects().get(0);
                // @debug 打印处理对象
                System.out.println(XMLHelper.nodeToString(SamlUtils
                        .asDOMDocument(logoutRequest).getDocumentElement()));
                LogoutResponse logoutResponse = MessageGen.generateLogoutResponse();
                try {
                    // 信封复用,清除之前的消息体内容
                    envelope.getBody().getUnknownXMLObjects().clear();
                    // 将响应消息体放入信封
                    envelope.getBody().getUnknownXMLObjects().add(logoutResponse);
                    // 设置响应类型为text/xml
                    response.setContentType("text/xml");
                    PrintWriter out = response.getWriter();
                    Document respDom = SamlUtils.asDOMDocument(envelope);
                    System.out.println(XMLHelper.nodeToString(respDom.getDocumentElement()));
                    out.print(XMLHelper.nodeToString(respDom.getDocumentElement()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            // 报活消息
            else if (reqDom.getElementsByTagName(SamlUtils.ACT_REQ).getLength() > 0) {
                SamlUtils.renameNode(reqDom, SamlUtils.ACT_REQ, SamlUtils.LGOUT_REQ);
                Envelope envelope = (Envelope) SamlUtils.fromElement(reqDom
                        .getDocumentElement());
                LogoutRequest logoutRequest = (LogoutRequest) envelope.getBody()
                        .getUnknownXMLObjects().get(0);
                // @debug 打印处理对象
                System.out.println(XMLHelper.nodeToString(SamlUtils
                        .asDOMDocument(logoutRequest).getDocumentElement()));
                LogoutResponse logoutResponse = MessageGen.generateLogoutResponse();
                try {
                    // 信封复用,清除之前的消息体内容
                    envelope.getBody().getUnknownXMLObjects().clear();
                    // 将响应消息体放入信封
                    envelope.getBody().getUnknownXMLObjects().add(logoutResponse);
                    // 设置响应类型为text/xml
                    response.setContentType("text/xml");
                    PrintWriter out = response.getWriter();
                    Document respDom = SamlUtils.asDOMDocument(envelope);
                    SamlUtils.renameNode(respDom, SamlUtils.LGOUT_RESP,
                            SamlUtils.ACT_RESP);
                    System.out.println(XMLHelper.nodeToString(respDom.getDocumentElement()));
                    out.print(XMLHelper.nodeToString(respDom.getDocumentElement()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    测试类

    SendMsgTest
    package xuzs.test;
    
    import org.opensaml.saml2.core.LogoutRequest;
    import org.opensaml.saml2.core.LogoutResponse;
    import org.opensaml.xml.XMLObject;
    import org.opensaml.xml.util.XMLHelper;
    
    import xuzs.common.MessageGen;
    import xuzs.common.SamlMsgClient;
    import xuzs.common.SamlUtils;
    
    public class SendMsgTest {
        
        private static String serverUrl = "http://localhost:8080/opensamlDemo/soapServlet";
        public static void main(String[] args){
            // 发送报活
            sendActivate();
            // 发送登出
            sendLogout();
            // 另一种报活
            sendActivate1();
        }
        
        /**
         * 发送登出消息
         */
        public static void sendLogout(){
            // 构造客户端
            SamlMsgClient client = new SamlMsgClient(serverUrl);
            // 构造登出请求消息对象
            LogoutRequest logoutRequest = MessageGen.generateLogoutRequest();
            // @debug 初始消息体,LogoutReuqest
            System.out.println(XMLHelper.nodeToString(SamlUtils.asDOMDocument(logoutRequest).getDocumentElement()));
            // 干活
            LogoutResponse logoutResponse = (LogoutResponse)client.send(logoutRequest);
            // @debug 响应消息体,LogoutRespons
            System.out.println(XMLHelper.nodeToString(SamlUtils.asDOMDocument(logoutResponse).getDocumentElement()));
        }
        
        /**
         * 发送报活消息1
         */
        public static void sendActivate1(){
            // 构造客户端
            SamlMsgClient client = new SamlMsgClient(serverUrl);
            // 构造登出请求消息对象
            LogoutRequest activateRequest = MessageGen.generateLogoutRequest();
            // @debug 初始消息体,LogoutReuqest
            System.out.println(XMLHelper.nodeToString(SamlUtils.asDOMDocument(activateRequest).getDocumentElement()));
            // 干活
            LogoutResponse logoutResponse = (LogoutResponse)client.send(activateRequest, SamlUtils.LGOUT_REQ, SamlUtils.ACT_REQ, SamlUtils.ACT_RESP, SamlUtils.LGOUT_RESP);
            // @debug 响应消息体,LogoutRespons
            System.out.println(XMLHelper.nodeToString(SamlUtils.asDOMDocument(logoutResponse).getDocumentElement()));
        }
        
        /**
         * 发送报活消息
         */
        public static void sendActivate(){
            // 构造客户端
            SamlMsgClient client = new SamlMsgClient(serverUrl);
            // 构造登出请求消息对象(宿主)
            LogoutRequest activateRequest = MessageGen.generateLogoutRequest();
            // @debug 初始消息体,LogoutReuqest
            System.out.println(XMLHelper.nodeToString(SamlUtils.asDOMDocument(activateRequest).getDocumentElement()));
            // 修改消息体节点
            SamlUtils.renameNode(SamlUtils.asDOMDocument(activateRequest), SamlUtils.LGOUT_REQ,
                    SamlUtils.ACT_REQ);
            // @debug 发送消息体,ActivateReuqest
            System.out.println(XMLHelper.nodeToString(activateRequest.getDOM()));
            // 干活
            XMLObject tempXmlObj = client.send(activateRequest);
            // @debug 响应消息体,ActivateRespons
            System.out.println(XMLHelper.nodeToString(tempXmlObj.getDOM()));
            // 替换响应对象的消息节点名称
            SamlUtils.renameNode(tempXmlObj.getDOM().getOwnerDocument(), SamlUtils.ACT_RESP, SamlUtils.LGOUT_RESP);
            // 返回登出响应消息对象(宿主)
            LogoutResponse activateResponse = (LogoutResponse)SamlUtils.fromElement(tempXmlObj.getDOM());
            // @debug 处理消息体,LogoutRespons
            System.out.println(XMLHelper.nodeToString(activateResponse.getDOM()));
        }
        
    }

    MessageGen过于简单,就不贴了。

  • 相关阅读:
    2014 ACM-ICPC Beijing Invitational Programming Contest
    面试算法爱好者书籍/OJ推荐
    最新版本号MYSQL官网下载地址可是必需要注冊后才干下载
    [ZJOI2019]开关
    2019-9-24-dotnet-remoting-使用事件
    2019-9-24-dotnet-remoting-使用事件
    2019-3-8-为何使用-DirectComposition
    2019-3-8-为何使用-DirectComposition
    2019-8-31-C#-获取-PC-序列号
    2019-8-31-C#-获取-PC-序列号
  • 原文地址:https://www.cnblogs.com/xzs603/p/2891289.html
Copyright © 2011-2022 走看看