function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
IvarIvar 

ws-security in WebService

Hi all.

 

I am trying to connect from Apex to an external WebService that requires the use of ws-security. I have discovered that this is not directly supported by Apex, but a suggested solution was to manually edit the WDSL document to include the ws-security header information.

 

I have been trying to do this without much luck, and was wondering if anyone out there had a simple example of what I need to inject into the WSDL, and where?

 

My thanks in advance,

Ivar

forecast_is_cloudyforecast_is_cloudy

I'm assuming that you're trying to insert WS-Security username/password tokens into your Apex callout (as opposed to some other WS-Security profile like SAML etc.). If so, the following write-up by Chuck Mortimore, Security PM at Salesforce.com should be very helpful. It waks thru how you can modify the generated WSDL2Apex class to manually insert WSS username/password SOAP headers into a sample web service request. Note that with this approach, you don't have to modify the WSDL itself - just the generated Apex class.

 

 

1) Generate Code from this WSDL and called the class “echo”

 

 

<?xml version="1.0" encoding="utf-8"?>

<wsdl:definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"

  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"

  xmlns:s="http://www.w3.org/2001/XMLSchema"

  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"

  xmlns:tns="http://doc.sample.com/docSample"

  targetNamespace="http://doc.sample.com/docSample"

  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

  <wsdl:types>

    <s:schema elementFormDefault="qualified" targetNamespace="http://doc.sample.com/docSample">

      <s:element name="EchoString">

        <s:complexType>

          <s:sequence>

            <s:element minOccurs="0" maxOccurs="1" type="s:string" />

          </s:sequence>

        </s:complexType>

      </s:element>

      <s:element name="EchoStringResponse">

        <s:complexType>

          <s:sequence>

            <s:element minOccurs="0" maxOccurs="1" name="EchoStringResult" />

          </s:sequence>

        </s:complexType>

      </s:element>

    </s:schema>

  </wsdl:types>

  <wsdl:message name="EchoStringSoapIn">

    <wsdl:part name="parameters" element="tns:EchoString" />

  </wsdl:message>

 

  <wsdl:message name="EchoStringSoapOut">

    <wsdl:part name="parameters" element="tns:EchoStringResponse" />

  </wsdl:message>

 

  <wsdl:portType name="DocSamplePortType">

    <wsdl:operation name="EchoString">

      <wsdl:input message="tns:EchoStringSoapIn" />

      <wsdl:output message="tns:EchoStringSoapOut" />

    </wsdl:operation>

  </wsdl:portType>

  <wsdl:binding name="DocSampleBinding">

    <wsdl:operation name="EchoString">

      <soap:operation soapAction="urn:dotnet.callouttest.soap.sforce.com/EchoString" style="document" />

      <wsdl:input>

        <soap:body use="literal" />

      </wsdl:input>

      <wsdl:output>

        <soap:body use="literal" />

      </wsdl:output>

    </wsdl:operation>

  </wsdl:binding>

  <wsdl:service name="DocSample">

    <wsdl:port name="DocSamplePort" binding="tns:DocSampleBinding">

      <soap:address location="http://www.qaresponder.info/WebServices/DocSample.asmx" />

    </wsdl:port>

  </wsdl:service>

</wsdl:definitions>

 

2) Modified code to talk to postbin.org...a cool service that echo’s posts, so you can see what is there.   Don’t forget to whitelist postbin in “Remote Sites”

 

Changed:         public String endpoint_x = 'http://www.qaresponder.info/WebServices/DocSample.asmx';

To:                   public String endpoint_x = 'http://www.postbin.org/p97gfq';

 

Resulting in this class:

 

 

public class echo {

    public class EchoStringResponse_element {

        public String EchoStringResult;

        private String[] EchoStringResult_type_info = new String[]{'EchoStringResult','http://www.w3.org/2001/XMLSchema','string','0','1','false'};

        private String[] apex_schema_type_info = new String[]{'http://doc.sample.com/docSample','true','false'};

        private String[] field_order_type_info = new String[]{'EchoStringResult'};

    }

    public class DocSamplePort {

        public String endpoint_x = 'http://www.postbin.org/p97gfq';

        public Map<String,String> inputHttpHeaders_x;

        public Map<String,String> outputHttpHeaders_x;

        public String clientCertName_x;

        public String clientCert_x;

        public String clientCertPasswd_x;

        public Integer timeout_x;

        private String[] ns_map_type_info = new String[]{'http://doc.sample.com/docSample', 'echo'};

        public String EchoString(String input) {

            echo.EchoString_element request_x = new echo.EchoString_element();

            echo.EchoStringResponse_element response_x;

            request_x.input = input;

            Map<String, echo.EchoStringResponse_element> response_map_x = new Map<String, echo.EchoStringResponse_element>();

            response_map_x.put('response_x', response_x);

            WebServiceCallout.invoke(

              this,

              request_x,

              response_map_x,

              new String[]{endpoint_x,

              'urn:dotnet.callouttest.soap.sforce.com/EchoString',

              'http://doc.sample.com/docSample',

              'EchoString',

              'http://doc.sample.com/docSample',

              'EchoStringResponse',

              'echo.EchoStringResponse_element'}

            );

            response_x = response_map_x.get('response_x');

            return response_x.EchoStringResult;

        }

    }

    public class EchoString_element {

        public String input;

        private String[] input_type_info = new String[]{'input','http://www.w3.org/2001/XMLSchema','string','0','1','false'};

        private String[] apex_schema_type_info = new String[]{'http://doc.sample.com/docSample','true','false'};

        private String[] field_order_type_info = new String[]{'input'};

    }

 

}

 

 

3) Tested my service to make sure it works by calling it from Anonymous Apex:

 

echo.DocSamplePort e = new echo.DocSamplePort();

e.EchoString('helloworld');

 

 

And I got this:

 

<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><env:Header /><env:Body><EchoString xmlns="http://doc.sample.com/docSample"><input>helloworld</input></EchoString></env:Body></env:Envelope>

 

4) Modified my class to this ( bold shows the changes )

 

public class echo {

    public class EchoStringResponse_element {

        public String EchoStringResult;

        private String[] EchoStringResult_type_info = new String[]{'EchoStringResult','http://www.w3.org/2001/XMLSchema','string','0','1','false'};

        private String[] apex_schema_type_info = new String[]{'http://doc.sample.com/docSample','true','false'};

        private String[] field_order_type_info = new String[]{'EchoStringResult'};

    }

    public class DocSamplePort {

        public String endpoint_x = 'http://www.postbin.org/p97gfq';

        public Map<String,String> inputHttpHeaders_x;

        public Map<String,String> outputHttpHeaders_x;

        public String clientCertName_x;

        public String clientCert_x;

        public String clientCertPasswd_x;

        public Integer timeout_x;

              public echo.Security_element Security;

        private String Security_hns = 'Security=http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd';

        private String[] ns_map_type_info = new String[]{'http://doc.sample.com/docSample', 'echo'};

        public String EchoString(String input, String userid, String password) {

                     Security = new echo.Security_element(userid,password);

            echo.EchoString_element request_x = new echo.EchoString_element();

            echo.EchoStringResponse_element response_x;

            request_x.input = input;

            Map<String, echo.EchoStringResponse_element> response_map_x = new Map<String, echo.EchoStringResponse_element>();

            response_map_x.put('response_x', response_x);

            WebServiceCallout.invoke(

              this,

              request_x,

              response_map_x,

              new String[]{endpoint_x,

              'urn:dotnet.callouttest.soap.sforce.com/EchoString',

              'http://doc.sample.com/docSample',

              'EchoString',

              'http://doc.sample.com/docSample',

              'EchoStringResponse',

              'echo.EchoStringResponse_element'}

            );

            response_x = response_map_x.get('response_x');

            return response_x.EchoStringResult;

        }

    }

    public class EchoString_element {

        public String input;

        private String[] input_type_info = new String[]{'input','http://www.w3.org/2001/XMLSchema','string','0','1','false'};

        private String[] apex_schema_type_info = new String[]{'http://doc.sample.com/docSample','true','false'};

        private String[] field_order_type_info = new String[]{'input'};

    }

 

       public class Security_element{

             

              public Security_element(String username, String password) {

             

                     usernameToken = new UsernameToken_element(username,password);

                    

              }

              public UsernameToken_element usernameToken;

              private String[] usernameToken_type_info = new String[]{'UsernameToken','http://www.w3.org/2001/XMLSchema','element','1','1','false'};

        private String[] apex_schema_type_info = new String[]{'http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd','true','false'};

        private String[] field_order_type_info = new String[]{'usernameToken'};

       

       }

 

    public class UsernameToken_element {

             

              public UsernameToken_element(String username, String password) {

             

                     this.username = username;

                     this.password = password;

             

              }

             

        public String username;

              public String password;

        private String[] username_type_info = new String[]{'Username','http://www.w3.org/2001/XMLSchema','string','1','1','false'};

        private String[] password_type_info = new String[]{'Password','http://www.w3.org/2001/XMLSchema','string','1','1','false'};

        private String[] apex_schema_type_info = new String[]{'http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd','true','false'};

        private String[] field_order_type_info = new String[]{'username','password'};

    }

}

 

5) Tested it like this:

 

echo.DocSamplePort e = new echo.DocSamplePort();

e.EchoString('helloworld', 'username', 'password');

 

 

And got this:

 

 

<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><env:Header><Security xmlns="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"><UsernameToken><Username>username</Username><Password>password</Password></UsernameToken></Security></env:Header><env:Body><EchoString xmlns="http://doc.sample.com/docSample"><input>helloworld</input></EchoString></env:Body></env:Envelope>


 

Done!

Prajapati.LakhanPrajapati.Lakhan

Hi,

 

I tried to add WS-Security info in proxy classes but "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" is not supported in my case so i have used "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" provided by API doc.  When I tried to call the webservice I am getting error "Type must be provided for the password" -  in my case server is expecting soap header as follows -

  <UsernameToken>

                <Username>username</Username>
                 <Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#PasswordText">password</Password>
</UsernameToken>

 

instead of -

<UsernameToken>

              <Username>username</Username>

              <Password>password</Password>

</UsernameToken>

 

Please let me know if any body has implmented this, how can I modify proxy class to include attribute info for the child node.

There is an approach I found @StackOverflow to add attribute in parent node using following code-

<foo a="b"><bar>baz</bar></foo>

Apex classes would be generated-

public class MyService {
   public class bar {
      public String bar;
      private String[] bar_type_info = new String[] {'bar','http://www.w3.org/2001/XMLSchema','string','0','1','true'};
      private String[] apex_schema_type_info = new String[] {'http://schema.myservice.com', 'false', 'false'};
      private String[] field_order_type_info = new String[] {'bar'};
   }

   public class foo {
      public MyService.bar bar;
      public String a;
      private String[] bar_type_info = new String[] {'bar','http://schema.myservice.com','bar','0','1','true'};
      private String[] a_att_info = new String[] {'a'};
      private String apex_schema_type_info = new String[] {'http://schema.myservice.com','false','false'};
      private String[] field_order_type_info = new String[] {'bar'};
   }
}

 

 I tried some combinations for the following xml

 

 

 <UsernameToken>

                <Username>username</Username>
                 <Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#PasswordText">password</Password>
</UsernameToken>


 

I tried many combinations but nothing worked for me, please if somebody have implemented it successfully, let me know what i missed.

 

Thanks,

Lakhan

Sean ScottSean Scott

has anyone figured out what the proxy class looks like in order to generate the attribute on the password tag?

 

<Password Type="XXX">value</Password>

jojoforcejojoforce

have you been able to figure out how to pass the Type attribute into the password? Thanks

NowshadNowshad

Controler:- I fixed as below

  // Below created date and nonce string we need to send along with the Tibco user name and password details to the stub
         DateTime d = System.now();
         String createdStr = d.formatGmt('yyyy-MM-dd HH:mm:ss.SSSSSS');
         String nonceStr = String.valueOf(Crypto.getRandomInteger());                           
         Blob nonceBlob = Blob.valueOf(nonceStr);
         nonceStr=EncodingUtil.base64Encode(nonceBlob);        
       // Calling the webserivce callout.. 
         SearchMDCPLookUpStub3.MDCPLookUpSearch stub = new SearchMDCPLookUpStub3.MDCPLookUpSearch();  
         stub.endpoint_x='https://g5t1173g.atlanta.hp.com/hpit/sfdc/dev/mdcp/lookupsearch';
         stub.timeout_x=60000;
         stub.clientCertName_x='SFDC_Certificate';
         stub.inputHttpHeaders_x = new Map<String, String>();
         stub.inputHttpHeaders_x.put('Content-Type', 'application/soap+xml');
         stub.inputHttpHeaders_x.put('SOAPAction','/SFDCServices/MDCPLookUpSearch.serviceagent/MDCPLookUp/MDCPLookUpSearch');

 SearchMDCPLookUpService3.organizationAccountSearchResponse_element accountSearchOutputElementList = stub.MDCPLookUpSearch(mdcpQuery,0,1000,'tibadmin','tibadmin',nonceStr,createdStr);        

NowshadNowshad

 

Controler:-See //SNA

 

 public class SearchMDCPLookUpStub2 {    public class MDCPLookUpSearch {        public SearchMDCPLookUpStub.Security_element Security;        private String Security_hns = 'Security=http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';                  Security = new SearchMDCPLookUpStub.Security_element(userid,password,nonce,dateVal);              }      public class Security_element{                           public Security_element(String username, String password,String nonce,String dateVal ) {                                  usernameToken = new UsernameToken_element(username,password,nonce,dateVal);                                  }        public UsernameToken_element usernameToken;        private String[] usernameToken_type_info = new String[]{'n1:UsernameToken','http://www.w3.org/2001/XMLSchema','element','1','1','false'};        private String[] apex_schema_type_info = new String[]{'http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd','true','false'};        private String[] field_order_type_info = new String[]{'usernameToken'};       }       public class UsernameToken_element {                           public UsernameToken_element(String username, String password,string nonce,string dateVal) {                     this.username = username;                     this.password = password;                     this.nonce= nonce;                     this.created= dateVal;                                  }                     public String username;        public String password;        public String nonce;        public String created;        private String[] username_type_info = new String[]{'n1:Username','http://www.w3.org/2001/XMLSchema','string','1','1','false'};        private String[] nonce_type_info = new String[]{'n1:Nonce','http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary','string','1','1','false'};        private String[] created_type_info = new String[]{'n1:Created','http://www.w3.org/2001/XMLSchema','string','1','1','false'};        private String[] password_type_info = new String[]{'n1:Password','http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText','string','1','1','false'};        private String[] apex_schema_type_info = new String[]{'http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd','true','false'};        private String[] field_order_type_info = new String[]{'username','password','nonce','created'};    }

 

Surender MSurender M
I have successfully executed external Webservice which has authetication when accessing it.
The code is below and see if it helps for anybody.

        String username= 'UrUsername';
        String password= 'UrPassword';
        Blob headerValue = Blob.valueOf(username + ':' + password);
        String authorizationHeader = 'Basic '+ EncodingUtil.base64Encode(headerValue);
        
        sapComDocumentSapRfcFunctions wsdlClass = new sapComDocumentSapRfcFunctions();
        sapComDocumentSapRfcFunctions.ZWS_SFDC_MATERIAL_NBP zws = new          sapComDocumentSapRfcFunctions.ZWS_SFDC_MATERIAL_NBP();
        zws.inputHttpHeaders_x = new Map<String,String>();
        zws.inputHttpHeaders_x.put('Authorization',authorizationHeader);
        zws.inputHttpHeaders_x.put('Content-Type', 'text/xml;charset=UTF-8;');
        zws.timeout_x = 60000;  


Regards,
Surender Madipeddi
Ken Koellner 1Ken Koellner 1
Has anyone solved the issue of passing the Type attribute for the password element in the SOAP Header (not HTTP header).  To get our callout to work, we somehow have to inject the Type element shown below bold below.  We haven't figured a way to do that.  There are some posts above complaining of the same issue with no answer.  I don't believe the post above about HTTP headers are germane to this issue.  The simpler solutions that send the SOAP header with the security info without the Type attribute on password do not help.
 
<env:Header>
                <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                                <UsernameToken>
                                                <Username>myUserName</Username>
                                                <Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">myPassword</Password>
                                </UsernameToken>
                </Security>
</env:Header>