2

I am trying to change the wsdl2apex code for a web service call header that currently looks like this:
<env:Header>
<Security xmlns="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd">
<UsernameToken Id="UsernameToken-4">
<Username>test</Username>
<Password>test</Password>
</UsernameToken>
</Security>
</env:Header>

to look like this:
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-4" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>Test</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Test</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>

One problem is that I can't work out how to change the namespaces for elements (or even if it matters what name they have). A secondary problem is putting the Type attribute onto the Password element.

Can any provide any information that might help?

Thanks

skaffman
  • 398,947
  • 96
  • 818
  • 769
Dean Barnes
  • 2,252
  • 4
  • 29
  • 53

3 Answers3

5

I was having a similar issue. I was able to generate the following SOAP Header which worked for my implementation:

   <env:Header>
      <Security xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
         <UsernameToken>
            <Username>aaaaaa</Username>
            <Password>xxxxxx</Password>
            <Nonce>MzI3MTUzODg0MjQy</Nonce>
            <wsu:Created>2013-04-23T16:09:00.701Z</wsu:Created>
         </UsernameToken>
      </Security>
   </env:Header>

Security Class:

public class OasisOpenOrgWssSecuritySecext 
{

    // UserToken Class
    public class UsernameToken 
    {
        // Constructor for UsernameToken used to pass in username and password parameters
        public UsernameToken(String username, String password)
        {
            this.Username = username;
            this.Password = password;
            this.Nonce = generateNounce();
            this.Created = generateTimestamp();
        }

        public String Username;
        public String Password;
        public String Nonce;
        public String Created;
        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[] Nonce_type_info = new String[]{'Nonce','http://www.w3.org/2001/XMLSchema','string','0','1','false'};
        private String[] Created_type_info = new String[]{'wsu:Created','http://www.w3.org/2001/XMLSchema','string','0','1','false'};        
        private String[] apex_schema_type_info = new String[]{'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd','true','false'};
        private String[] field_order_type_info = new String[]{'Username','Password','Nonce','Created'};

        // Generate Nounce, random number base64 encoded
        public String generateNounce()
        {
            Long randomLong = Crypto.getRandomLong();
            return EncodingUtil.base64Encode(Blob.valueOf(String.valueOf(randomLong)));
        }

        // Generate timestamp in GMT
        public String generateTimestamp()
        {
            return Datetime.now().formatGmt('yyyy-MM-dd\'T\'hh:mm:ss\'Z\'');
        }
    }

    // SecurityHeaderType Class
    public class SecurityHeaderType 
    {       
        // Constructor for SecurityHeaderType used to pass in username and password parameters and instantiate the UsernameToken object     
        public SecurityHeaderType(String username, String password)
        {
            this.UsernameToken = new OasisOpenOrgWssSecuritySecext.UsernameToken(username, password);
        }

        public String wsuNamespace = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd';              
        public OasisOpenOrgWssSecuritySecext.UsernameToken UsernameToken;
        private String[] UsernameToken_type_info = new String[]{'UsernameToken','http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd','UsernameToken','1','1','false'};
        private String[] wsuNamespace_att_info = new String[]{'xmlns:wsu'};               
        private String[] apex_schema_type_info = new String[]{'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd','true','false'};
        private String[] field_order_type_info = new String[]{'UsernameToken'};
    }
}

Add the lines between the comments to your class generated by wsdl2apex:

public class XyzWebService {
    public String endpoint_x = 'https://webservice/'
    // ADDITION TO WSDL
    public OasisOpenOrgWssSecuritySecext.SecurityHeaderType Security = new OasisOpenOrgWssSecuritySecext.SecurityHeaderType( 'aaaaaa', 'xxxxxx');
    private String Security_hns = 'Security=http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';**                            
    // END ADDITION TO WSDL
    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;
user2312740
  • 51
  • 1
  • 2
  • I tried this. I am sure that I am using the correct user name and password. I get the response: A security error was encountered when verifying the message faultcode=ns1:SecurityError. This generic message does not really help me. I tried leaving out Nonce and Created (a tip that I found elsewhere), but that gives the same result. Anyone got some other hints to help me? – Sander de Jong Dec 05 '18 at 08:26
  • Hi. Did you finally get it? – ram lou Sep 21 '21 at 11:39
1

I had a similar problem. I manually created a class to create the basic structure. Fortunately, the service I was consuming either assumed or was able to determine that the type was text without the type parameter being explicitly set, so you may want to try that and see if it works.

For the namespaces I set those up as attributes:

private String[] wsu_att_info = new String[] {'xmlns:wsu'};

This question may also be helpful: What are the parameters for the Salesforce WebServiceCallout.invoke method?

Community
  • 1
  • 1
Jeremy
  • 1,015
  • 4
  • 11
  • 20
  • I don't suppose you found how to add an attribute to an element containing only a string while you were at it did you? – Dean Barnes Feb 18 '11 at 11:47
  • Since I got something working, no, but I did get an answer that I haven't had a chance to test yet: (http://stackoverflow.com/questions/4413631/salesforce-wsdl-import-of-simplecontent-w-extension) – Jeremy Feb 18 '11 at 22:39
  • I've just had a go at implementing that, but I can't seem to work it out. It'd be easier if there was documentation for it somewhere, but I can't find it if it does exist. – Dean Barnes Feb 24 '11 at 14:32
0

Might not be possible for everyone, but we managed to solve the problem by using XSLT to transform the SOAP we had into the SOAP we wanted.

Dean Barnes
  • 2,252
  • 4
  • 29
  • 53
  • I have exactly same need as yours. Can you please provide more details on how were you able to achieve this ? – HSG May 01 '19 at 12:47
  • @HSG this was 8 years and multiple jobs ago, so I'm afraid I cannot much. I assume I used XSLT to map from the format we had to the format we wanted. – Dean Barnes May 01 '19 at 12:50
  • No worries, I think I am almost there. Appreciate the response. – HSG May 01 '19 at 13:39