如何使用Java生成SAML安全SOAP请求并使用SAAJ调用外部Web服务

时间:2014-10-19 15:47:34

标签: java soap saml ws-security saaj

我有一个使用WS-Security和 SAML 实现的外部SOAP Web服务... Web服务的SOAP请求如下: -

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://services.test.getDesignation.com/schema/MainData/V1">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
         <saml1:Assertion AssertionID="_1EB4A2A52467EB9373141364603919871" IssueInstant="2014-10-18T15:27:19.198Z" Issuer="self" MajorVersion="1" MinorVersion="1" xsi:type="saml1:AssertionType" xmlns:saml1="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <saml1:Conditions NotBefore="2014-10-18T15:27:19.198Z" NotOnOrAfter="2014-10-18T15:32:19.198Z"/>
            <saml1:AuthenticationStatement AuthenticationInstant="2014-10-18T15:27:19.198Z" AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" xsi:type="saml1:AuthenticationStatementType">
               <saml1:Subject>
                  <saml1:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">getDesignationservice</saml1:NameIdentifier>
                  <saml1:SubjectConfirmation>
                     <saml1:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</saml1:ConfirmationMethod>
                  </saml1:SubjectConfirmation>
               </saml1:Subject>
            </saml1:AuthenticationStatement>
         </saml1:Assertion>
         <wsse:UsernameToken wsu:Id="UsernameToken-1EB4A2A52467EB9373141364603919870">
            <wsse:Username>username</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
            <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">FCyqP2DThmR6ygNWnzNrKQ==</wsse:Nonce>
            <wsu:Created>2014-10-18T15:27:19.198Z</wsu:Created>
         </wsse:UsernameToken>
         <wsu:Timestamp wsu:Id="TS-1EB4A2A52467EB9373141364603919869">
            <wsu:Created>2014-10-18T15:27:19.197Z</wsu:Created>
            <wsu:Expires>2014-10-18T15:28:19.197Z</wsu:Expires>
         </wsu:Timestamp>
      </wsse:Security>
   </soapenv:Header>
   <soapenv:Body>
      <v1:getDesignationRequest>
         <v1:DesignationCode>bd</v1:DesignationCode>
      </v1:getDesignationRequest>
   </soapenv:Body>
</soapenv:Envelope>

现在,我要做的是使用SAAJ在Java代码中调用外部服务..

到目前为止,我尝试了以下方法: -

import java.io.ByteArrayOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Random;
import java.util.TimeZone;

import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
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.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.apache.xerces.impl.dv.util.Base64;
import org.w3c.dom.Node;


public class SOAPSecurity3 {

    private static String calculatePasswordDigest(String nonce, String created, String password) {
        String encoded = null;
        try {
            String pass = hexEncode(nonce) + created + password;
            MessageDigest md = MessageDigest.getInstance( "SHA1" );
            md.update( pass.getBytes() );
            byte[] encodedPassword = md.digest();
            encoded = Base64.encode(encodedPassword);
        } catch (NoSuchAlgorithmException ex) {
           /* Logger.getLogger(HeaderHandler.class.getName()).log(Level.SEVERE, null, ex);*/
        }

        return encoded;
    }

    private static String hexEncode(String in) {
        StringBuilder sb = new StringBuilder("");
        for (int i = 0; i < (in.length() - 2) + 1; i = i + 2) {
            int c = Integer.parseInt(in.substring(i, i + 2), 16);
            char chr = (char) c;
            sb.append(chr);
        }
        return sb.toString();
    }

    private static SOAPMessage createSoapRequest(String value) throws Exception{

        //This is used to get time in SOAP request in yyyy-MM-dd'T'HH:mm:ss.SSS'Z' format
      SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:dd.SSS'Z'");
      formatter.setTimeZone(TimeZone.getTimeZone("GMT"));

        //This is for UsernameToken element
        Random generator = new Random();
        String nonceString = String.valueOf(generator.nextInt(999999999)); // This generate random nonce
        Date timestamp = new java.util.Date();
        String pass = "password";
        String user = "username";
        //This is for UsernameToken element ends


        //This is for TimeStamp element value
        java.util.Date create = new java.util.Date();
        java.util.Date expires = new java.util.Date(create.getTime() + (5l * 60l * 1000l));
        //This is for TimeStamp value ends

         MessageFactory messageFactory = MessageFactory.newInstance();
         SOAPMessage soapMessage = messageFactory.createMessage();
         SOAPPart soapPart = soapMessage.getSOAPPart();
        //SOAP Envelope
         SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
         soapEnvelope.addNamespaceDeclaration("v1", "http://services.test.getDesignation.com/schema/MainData/V1");

    //SOAP Header            
         SOAPHeader header = soapMessage.getSOAPHeader(); 
         if (header == null) {
             header = soapEnvelope.addHeader();
         }

         SOAPElement security =header.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd").addAttribute(new QName("xmlns:wsu"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");


                SOAPElement usernameToken = security.addChildElement("UsernameToken", "wsse").addAttribute(QName.valueOf("wsu:Id"),"UsernameToken-89293AC6E584F11ADF141358720544137");

                // add the username to usernameToken
                SOAPElement userNameSOAPElement = usernameToken.addChildElement("Username","wsse");
                userNameSOAPElement.addTextNode("username");

                // add the password to usernameToken
                SOAPElement passwordSOAPElement = usernameToken.addChildElement("Password","wsse").addAttribute(new QName("Type"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
                passwordSOAPElement.addTextNode("password");


                //Adding random Nonce
                SOAPElement nonce =usernameToken.addChildElement("Nonce", "wsse").addAttribute(new QName("EncodingType"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
                nonce.addTextNode(Base64.encode(hexEncode(nonceString).getBytes()));

                //Adding created element of UsernameToken
                SOAPElement created = usernameToken.addChildElement("Created", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
                created.addTextNode(formatter.format(timestamp)); //formatter formats the date to String

                //Adding Timestamp
                SOAPElement timestampElem = security.addChildElement("Timestamp", "wsu").addAttribute(QName.valueOf("wsu:Id"),"TS-1EB4A2A52467EB9373141362942343119");
                SOAPElement elem = timestampElem.addChildElement("Created", "wsu");
                elem.addTextNode(formatter.format(create)); //formatter formats the date to String
                timestampElem.addChildElement(elem);
                elem = timestampElem.addChildElement("Expires", "wsu");
                elem.addTextNode(formatter.format(expires)); //formatter formats the date to String
                timestampElem.addChildElement(elem);


         //////SOAP Body
         SOAPBody soapBody = soapEnvelope.getBody();
         SOAPElement soapElement = soapBody.addChildElement("getDesignationRequest", "v1");
         SOAPElement element1 = soapElement.addChildElement("DesignationCode", "v1");
         element1.addTextNode(value);
         soapMessage.saveChanges();
         System.out.println("----------SOAP Request------------");
         soapMessage.writeTo(System.out);
         return soapMessage;
     }
     private static void createSoapResponse(SOAPMessage soapResponse) throws Exception  {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        Source sourceContent = soapResponse.getSOAPPart().getContent();
        System.out.println("\n----------SOAP Response-----------");
        /////////////////////////////////////////////////////
        StreamResult result = new StreamResult(System.out);
        transformer.transform(sourceContent, result);
        System.out.println();
     }
     public static void main(String args[]) throws Exception{

            SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
            SOAPConnection soapConnection = soapConnectionFactory.createConnection();
            String url = "http://localhost:8090/designation";
            SOAPMessage soapRequest = createSoapRequest("SSE");


            SOAPMessage soapResponse = soapConnection.call(soapRequest, url);
            createSoapResponse(soapResponse);

            String Code =soapResponse.getSOAPBody().getElementsByTagName("Code").item(0).getFirstChild().getNodeValue();

          if(Code.equals("Success"))
          {
            String Result=soapResponse.getSOAPBody().getElementsByTagName("DesignationCodeResult").item(0).getFirstChild().getNodeValue();
            System.out.println(Result ); 
          }
          else 
          {
              System.out.println("SOAP Fault");
          }



            soapConnection.close();
        }
     }

哪个能够产生以下请求并调用外部服务: -

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://services.test.getDesignation.com/schema/MainData/V1">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-89293AC6E584F11ADF141358720544137">
<wsse:Username>username</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">FyRZEA==</wsse:Nonce>
<wsu:Created>2014-10-19T15:38:19.744Z</wsu:Created>
</wsse:UsernameToken>
<wsu:Timestamp wsu:Id="TS-1EB4A2A52467EB9373141362942343119">
<wsu:Created>2014-10-19T15:38:19.744Z</wsu:Created>
<wsu:Expires>2014-10-19T15:43:19.744Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<v1:getDesignationRequest>
<v1:DesignationCode>SSE</v1:DesignationCode>
</v1:getDesignationRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

但是我无法生成此java代码中所需的 SAML 标记来生成所需的实际SOAP请求(在问题的顶部提到)..请帮助..怎么能我使用此Java代码生成**SAML**安全外部服务所需的请求...

由于

3 个答案:

答案 0 :(得分:0)

我建议您查看OpenSAML library。它非常受欢迎,受到良好支持,文档齐全 - 您可以在互联网上找到plenty of examples

答案 1 :(得分:0)

您可以使用Axis 2客户端并添加Rampart以添加SAML支持..您可以这样做吗?

答案 2 :(得分:0)

正如Avi建议我最终使用Axis 2客户端并添加Rampart以添加SAML支持并且它对我有效。
对于参考我在这里做的是链接: - https://thilinamb.wordpress.com/2009/10/20/saml-2-0-token-profile-support-in-rampart-1-5/
https://axis.apache.org/axis2/java/rampart/setting-up-sts.html