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
Giorgio PorroGiorgio Porro 

SOAP API Security Header

Hello,

I'm trying to make a call to a WebService that requires the Soap Security Header to be provided in the message. They also require Password Digest.

I am able to POST a message to the service, and getting the response I'm looking for, using a tool such as SOAP UI. In the log I see the Soap Header looks like this

<soapenv:Header><wsse:Security soapenv:mustUnderstand="1" 
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-0A895E4ED2XY1B64BB142239383782811>
    <wsse:Username>irhythmtest</wsse:Username>
    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">kxPMdaV96UNV1OXw0B83IpnwgNc=</wsse:Password>
    <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">LTYzMDgmJTU1MTE5ODgyMjQ2HOZ==</wsse:Nonce>
    <wsu:Created>2015-01-27T09:41:14Z</wsu:Created>
</wsse:UsernameToken></wsse:Security></soapenv:Header>

What I'm trying to do is to create this header in an Apex Class.
I highligheted in BOLD (above) the "variable" fields.

- For Password Digest, I'm generating the string using the process below

            Blob targetBlob = Blob.valueOf('mypass');
            Blob hash = Crypto.generateDigest('SHA1', targetBlob);
            String b64 = EncodingUtil.base64Encode(hash);  

- For Nonce, I'm generating the string using the process below

            Long randomLong = Crypto.getRandomLong();
            String Nounce = EncodingUtil.base64Encode(Blob.valueOf(String.valueOf(randomLong)));

- For Created, I'm generating the string using the process below

            String Create = Datetime.now().formatGmt('yyyy-MM-dd\'T\'hh:mm:ss\'Z\'');

I am not sure what goes in the wsu:Id="UsernameToken part of the header. How are tools such as SOAP UI generating a different and accepted Token in each call?

Any help or ideas on this would be highly appreciated

Thanks!
Giorgio
Best Answer chosen by Giorgio Porro
James LoghryJames Loghry

 

I hope I'm reading this right, but it sounds like you are (or were) having issues calling a service with wsdl2apex / salesforce using credentials in the header?  If you're trying to do this via WSDL2Apex, it doesn't support advanced headers by default.  By advanced headers, I mean the ability to pass in credentials, etc through the header.  It's possible, but with some modification to the WSDL2Apex generated class.  This blog has an example on how they addressed credentials in the headers: http://blog.dacology.com/callouts-from-salesforce-adding-soap-headers-for-wsse-security/

The gist is, you'll need to create a seperate class for the Authentication element.  The class will likely have a username and password attribute.  You then declare this in your service class, and WSDL2Apex picks it up. Below is a psuedo example that worked in my case:
 
public class AuthenticationToken {
        public String Username;
        public String Password;
        private String[] Username_type_info = new String[]{'Username','http://www.w3.org/2001/XMLSchema','string','0','1','false'};
        private String[] Password_type_info = new String[]{'Password','http://www.w3.org/2001/XMLSchema','string','0','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://someurl','true','false'};
        private String[] field_order_type_info = new String[]{'Username','Password'};
}

public class ServiceSoap {
        public String endpoint_x = EndpointSettings.getValue('MyEndpoint');
        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 MyClass.AuthenticationToken AuthenticationToken;
        private String AuthenticationToken_hns = 'AuthenticationToken=http://serviceurl';
        private String[] ns_map_type_info = new String[]{'http://serviceurl', 'Wsdl'};
        //methods go here
    }

Now, getting this to work took some time and patience, but you may find it easier to just manually construct the Http request with the appropriate headers in the long run.

 

All Answers

James LoghryJames Loghry

 

I hope I'm reading this right, but it sounds like you are (or were) having issues calling a service with wsdl2apex / salesforce using credentials in the header?  If you're trying to do this via WSDL2Apex, it doesn't support advanced headers by default.  By advanced headers, I mean the ability to pass in credentials, etc through the header.  It's possible, but with some modification to the WSDL2Apex generated class.  This blog has an example on how they addressed credentials in the headers: http://blog.dacology.com/callouts-from-salesforce-adding-soap-headers-for-wsse-security/

The gist is, you'll need to create a seperate class for the Authentication element.  The class will likely have a username and password attribute.  You then declare this in your service class, and WSDL2Apex picks it up. Below is a psuedo example that worked in my case:
 
public class AuthenticationToken {
        public String Username;
        public String Password;
        private String[] Username_type_info = new String[]{'Username','http://www.w3.org/2001/XMLSchema','string','0','1','false'};
        private String[] Password_type_info = new String[]{'Password','http://www.w3.org/2001/XMLSchema','string','0','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://someurl','true','false'};
        private String[] field_order_type_info = new String[]{'Username','Password'};
}

public class ServiceSoap {
        public String endpoint_x = EndpointSettings.getValue('MyEndpoint');
        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 MyClass.AuthenticationToken AuthenticationToken;
        private String AuthenticationToken_hns = 'AuthenticationToken=http://serviceurl';
        private String[] ns_map_type_info = new String[]{'http://serviceurl', 'Wsdl'};
        //methods go here
    }

Now, getting this to work took some time and patience, but you may find it easier to just manually construct the Http request with the appropriate headers in the long run.

 
This was selected as the best answer
David Hall 29David Hall 29
We are working on this same issue, and we see how to modify the wsdl2apex code in general, but we are not clear how to generate the Type attribute in the Password element, like

<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">blah</wsse:Password>. 

We can generate the <wsse:Password> field and populate it, but we don't see where or how to get the Type="..." attribute added under the Password itself.

How do we get this added to the Password element that gets generated?  And what specific code actually generates the Username and Password elements themselves?

 
Tejas Kapasi 13Tejas Kapasi 13
David, Did you get the answer? I am having the same query to get Type Attribute. 
Christian Monje Marcos 15Christian Monje Marcos 15
Hi Tejas, David, James,

Have you been able to solve this problem? I have a similar problem and I need to get some help.

Thanks!
Navinkumar SethiyaNavinkumar Sethiya

Hi All,

Are you able to find the solution for it? We are also facing the same issue

Loureiro@UPFLoureiro@UPF
Hi!
Any update on this?
Davide GammoneDavide Gammone
Hi, someone have found how to do? thanks