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
Marie-Charlotte DMarie-Charlotte D 

Apex callout and wsse authentication

Hello,

I need to connect to an external site to send objects. I use the code below but I still get an error ("wsse authentication" required) . 
Does somebody see the error?

Thank you for your help!
 
        String jsonLeads = JSON.serialize(leadToSend);        
        String headerReq = createHeader();
        
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setHeader('Authorization',headerReq);
        system.debug('header '+request.getHeader('Authorization'));
        request.setEndpoint('http://xxxx');
        request.setMethod('POST');
        request.setBody(jsonLeads);
        system.debug('request '+request);
        
        try{
            HttpResponse response = http.send(request);
            if (response.getStatusCode() != 201) {
                System.debug('The status code returned was not expected: ' +
                             response.getStatusCode() + ' ' + response.getStatus()+response.getBody());
            } else {
                System.debug(response.getBody());
            }
        }catch(System.CalloutException e) {
            system.debug(e);
        }       
    }
    
    public static String createHeader(){
        String token = 'xxxxxx';
        String chars = '0123456789abcdef';
        String nonce = '';
        String dt = system.now()+'Z';
        
        while (nonce.length() < 32) {
            Integer idx = Math.mod(Math.abs(Crypto.getRandomInteger()), chars.length());
            nonce += chars.substring(idx, idx+1);
        }
        system.debug('nonce: '+nonce);
        String nonce64 = EncodingUtil.base64Encode(Blob.valueOf(nonce));
        
        Blob target = Blob.valueOf(nonce+dt+token); 
        Blob digestSha1 = Crypto.generateDigest('SHA1',target);
        String digest = EncodingUtil.base64Encode(digestSha1);
        
        String header = 'X-WSSE:UsernameToken Token="'+token+'",PasswordDigest="'+digest+'",Nonce="'+nonce64+'",Created="'+dt+'"';       
        return header;
    }

 
Ann Kristin OlsenAnn Kristin Olsen
I had the same error. 
change this line
request.setHeader('Authorization',headerReq); to request.setHeader('X-WSSE',headerReq);
Then my code was able to authenticate
Pasquale IodicePasquale Iodice
Hi Ann,
I'm trying to call an external service using Http request following the above code with your suggestion but i'm having authorization error 401. I think my header is wrong. Can you past your sample working code please.

Best regards
 
Ann Kristin OlsenAnn Kristin Olsen
Hi Pasquale - for my integration to Emarsys. I accedentially removed the Z in datetime setting and then the authentification worked.
This a class that I made of copy and paste from forum - and is working fine towards an Emarsys integration.


public class WSSecurityUtil {
  
    public class UsernameToken{
        public String Username;
        public String Password;
            public String Nonce;
        public String dt;
        public String Digest;
        public String Header;
        
        public UsernameToken(String username,String password){
            System.debug('WSSecurityUtil -Logger in med '+username+' - '+password);
            this.Username = username;
            this.Password = password;
            this.Nonce = generateNounce();
            this.dt = generateTimestamp();
            this.Digest = generateDigest(Nonce,dt,Password);
            this.Header = generateHeader(username,Digest,Nonce,dt);
        }
        
        /* Generate Nounce, random number base64 encoded */
        public String generateNounce()
        {    
            String nonce='';
            String possible = '0123456789abcdef';
            while (nonce.length() < 16) {
            Integer i = Math.mod(Math.abs(Crypto.getRandomInteger()), possible.length());
            nonce += possible.substring(i, i+1);
            }
            String nonce64 = EncodingUtil.convertToHex(Blob.valueOf(nonce));
            return nonce64;

        }

        /* Generate timestamp in GMT. In Emarsys example with Z, work only without Z */
        public String generateTimestamp()
        {
            Datetime dt = Datetime.now();
            return dt.format('yyyy-MM-dd\'T\'HH:mm:ss');
            //return Datetime.now().formatGmt('yyyy-MM-dd\'T\'HH:mm:ss\'Z\'');
            //return dt.format('yyyy-MM-dd\'T\'HH:mm:ss\'Z\'');
        }
    
        /* Generate Digest */
        public String generateDigest(String nonce,String dt, String key)
        {
            Blob shaOne = crypto.generateDigest('SHA1', blob.valueOf(nonce+dt+key));
            String hexConv= encodingUtil.convertToHex(shaOne);
            return EncodingUtil.base64Encode(blob.valueOf(hexConv));
        }
    
        /* Generate Header */
        public String generateHeader(String Username,String Digest,String Nonce,String dt){
            return 'X-WSSE: UsernameToken Username="'+Username+'",PasswordDigest="'+Digest+'",Nonce="'+Nonce+'",Created="'+dt+'"';  
        }    
    }
}
Ann Kristin OlsenAnn Kristin Olsen
Then I call the class to create header

WSSecurityUtil.UsernameToken security = new WSSecurityUtil.UsernameToken( userName, key);
                Header = security.header;
Ann Kristin OlsenAnn Kristin Olsen
Then I use the header in request

 String headerReq = header;
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setMethod(POST);
        request.setHeader('X-WSSE',headerReq);

        request.setHeader('Accept','text/html');
        request.setHeader('Content-Type', 'application/json');
        request.setEndpoint(endpoint);
        request.setBody(jSON);
        HttpResponse response = http.send(request);
Ann Kristin OlsenAnn Kristin Olsen
Hi yes I have the X-WSSE in my generated return and in the request.setHeader. My understanding is that 'X-WSSE is kind of a authorization type, but the word X-WSSE need also be in generateHeader return. I also had a problem with this lines of code - I do not remember if it got to long or.... while (nonce.length() < 32) { Integer idx = Math.mod(Math.abs(Crypto.getRandomInteger()), chars.length()); nonce += chars.substring(idx, idx+1); } I use this /* Generate Nounce, random number base64 encoded */ public String generateNounce() { String nonce=''; String possible = '0123456789abcdef'; while (nonce.length() < 16) { Integer i = Math.mod(Math.abs(Crypto.getRandomInteger()), possible.length()); nonce += possible.substring(i, i+1); } String nonce64 = EncodingUtil.convertToHex(Blob.valueOf(nonce)); return nonce64; }
Pasquale IodicePasquale Iodice
Ciao Ann,

thank you very much for your immediate support. Even in my case it was a problem related to date formatting. I finally solved using, for my time zone (italy), this date format: datetime.now().format('yyyy-MM-dd\'T\'HH:mm:ss\'+01:00\'');
Thank u