James Palfrey
James Palfrey

Reputation: 803

OAuth 401 Unauthorised

so learning still but i'm getting an Error 401 unauthorised back from the code below. I know that the OAuth header works as it works in postman so i'm assuming there is a problem with the POST request / Auth header? Any ideas?

//set timestamp
            Long timestamp = System.currentTimeMillis()/1000;
            //set nonce ***** call from main system*************************************************************
            String aString = randomAlphaNumeric(11);
            // other stuff
            RestTemplate restTemplate = new RestTemplate();
            restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
            HttpHeaders headers = new HttpHeaders();
            String url = "aURL";
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
           // String auth = Base64.getEncoder().encodeToString(credentials.getBytes());
            List<NameValuePair> oauthHeaders = new ArrayList<>(9);
            oauthHeaders.add(new BasicNameValuePair("oauth_consumer_key", "aKey"));
            oauthHeaders.add(new BasicNameValuePair("oauth_nonce", aString));
            oauthHeaders.add(new BasicNameValuePair("oauth_timestamp", String.valueOf(timestamp)));
            oauthHeaders.add(new BasicNameValuePair("oauth_signature_method", "HMAC-SHA1"));
            oauthHeaders.add(new BasicNameValuePair("oauth_version", "1.0"));
            //generate signature
            //encode
            String encodedURL = encode(oauthHeaders.toString());
            System.out.println("encoded URL:" +encodedURL);
            //form base string
            String baseString = "POST&"+encode(url).toString()+encodedURL;
            System.out.println("Base String:  "+baseString);
            //form signature
            byte[] byteHMAC = null;
            try {

                Mac mac = Mac.getInstance("HmacSHA1");
                SecretKeySpec spec;
                if (null == secretKey) {
                    String signingKey = encode(secretKey) + '&';
                    spec = new SecretKeySpec(signingKey.getBytes(), "HmacSHA1");
                } else {
                    String signingKey = encode(secretKey) + '&' + encode(secretKey);
                    spec = new SecretKeySpec(signingKey.getBytes(), "HmacSHA1");
                }
                mac.init(spec);
                byteHMAC = mac.doFinal(baseString.getBytes());
            } catch (Exception e) {
                e.printStackTrace();
            }
            String signature = new BASE64Encoder().encode(byteHMAC);
            System.out.println("oauth signature:    "+signature);


            //set signature to params
            oauthHeaders.add(new BasicNameValuePair("oauth_signature", signature));
            String test = "OAuth "+oauthHeaders.toString();
            headers.set("Authorization", test);
            MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
            map.add("Name",name.toString());
            map.add("Region",region.toString());


            HttpEntity<MultiValueMap<String, String>> requestEntity= new HttpEntity<MultiValueMap<String, String>>(headers, map);
            System.out.println(requestEntity);
            ResponseEntity<String> response= restTemplate.exchange(url ,HttpMethod.POST, requestEntity, String.class);
            System.out.println(response.toString());
            HttpStatus status = response.getStatusCode();
            status.toString();
            if(status.equals("200")){
                Notification.show("Employer" + name +" added successfully");
            }
            else{
                Notification.show("Unsuccessful, error: "+status);
            }


        }

removed the URL and consumer key / signature for obvious reasons.

The following System out prints might help as well:

encoded params: %5Boauth_consumer_key%3aKey%2C%20oauth_nonce%3DWZU8H1B5JA6%2C%20oauth_timestamp%3D1511621759%2C%20oauth_signature_method%3DHMAC-SHA1%2C%20oauth_version%3D1.0%5D

Base String: POST&https%3A%2F%2Fapi.test.payrun.io%2FEmployer%5Boauth_consumer_key%3aKey%2C%20oauth_nonce%3DWZU8H1B5JA6%2C%20oauth_timestamp%3D1511621759%2C%20oauth_signature_method%3DHMAC-SHA1%2C%20oauth_version%3D1.0%5D

oauth signature: DlRJGSzgRIItzz+LzMbgnIfbOqU=

Upvotes: 1

Views: 528

Answers (2)

James Palfrey
James Palfrey

Reputation: 803

For anyone who wants to make this work then please see below for a complete OAuth Generator example :):

public class oAuthGenerator {
private String httpMethod;
    private String params;
    private String url;
    //Required for percent encoding
    private static final String ENC = "ASCII";
    //Required for nonce
    private static final String ALPHA_NUMERIC_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
    //As provided by Payrun.io
    private static final String secretKey = "aSecretKey";
    //As provided by Payrun.io
    private static final String consumerKey ="aConsumerKey";
    private List veriList;

    //Constructor for setting signature base string values.
    //@Param url needs to be percent encoded
    //@Param params needs to be percent encoded, this is done @Method generateOAuth()
    public oAuthGenerator(String httpMethod,String url )throws Exception {
        veriList= new ArrayList<String>();
        veriList.add("POST");
        veriList.add("GET");
        veriList.add("PUT");
        veriList.add("DELETE");

        if (veriList.contains(httpMethod)){
        this.httpMethod = httpMethod+"&";}
            this.url = URLEncoder.encode(url,ENC)+"&";
    }

    //A method used to generate the OAuth Authorization header
    //@Method randomAlphaNumeric() calls internal method using instance variable ALPHA_NUMERIC_STRING
    //@Method getSignature() returns String HMACSHA1 > Base64 encoded value of httpMethod,url,params
    public String generateOAuth()throws Exception{
        //Set timestamp as seconds from 01-01-1970
        Timestamp timestamp = new Timestamp(System.currentTimeMillis()/1000);
        Long aTimestamp = timestamp.getTime();
        //Set nonce which is a 10 digit random, non repeating alpha-numeric value
        String aNonce = randomAlphaNumeric(10);
        //Normalize and form param string
        String normalizedParams = "oauth_consumer_key="+consumerKey+"&"+"oauth_nonce="+aNonce+"&"+"oauth_signature_method="+"HMAC-SHA1"+"&"+"oauth_timestamp="+ aTimestamp.toString()+"&"+"oauth_version="+"1.0";
        //Percent encoded params
        params = URLEncoder.encode(normalizedParams,ENC);
        //Set signature variable
        String signature = getSignature();
        //place into required format
        String oAuthResult = "OAuth "+"oauth_version="+"\"1.0\""+","+"oauth_consumer_key="+"\"" + consumerKey + "\""+","+"oauth_signature_method="+"\"HMAC-SHA1\""+","+"oauth_timestamp="+"\""+aTimestamp+"\""+","+"oauth_nonce="+"\""+aNonce+"\""+","+"oauth_signature="+"\""+signature+"\"";
        return oAuthResult;
    }
    // A method designed to return a hashed and base64 encoded value.
    //@Param aString holds HMAC-SHA1 and Base 64 encoded value of variables httpMethod,url,params
    //@Param result holds percent encoded value of aString
    private String getSignature()
            throws Exception {
        //form base string
        StringBuilder base = new StringBuilder();
        base.append(httpMethod);
        base.append(url);
        base.append(params);
        //Set SecretKey of variable secretKey using HMAC-SHA1 algorithm
        SecretKey signingKey = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
        // Get an hmac_sha1 Mac instance and initialize with the signing key
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(signingKey);
        // Compute the hmac on input data bytes, then encode to Base64
        String aString = Base64.getEncoder().encodeToString(mac.doFinal(base.toString().getBytes(ENC))).trim();
        //Percent encoded the Base64 value
        String result = URLEncoder.encode(aString, ENC);
        return new String(result);

    }

    //Required for nonce, returns a random alpha numeric value by using variable ALPHA_NUMERIC_STRING
    private static String randomAlphaNumeric(int count) {
        StringBuilder builder = new StringBuilder();
        while (count-- != 0) {
            int character = (int)(Math.random()*ALPHA_NUMERIC_STRING.length());
            builder.append(ALPHA_NUMERIC_STRING.charAt(character));
        }
        return builder.toString();
    }
}

Upvotes: 0

Takahiko Kawasaki
Takahiko Kawasaki

Reputation: 19001

The value of oauth_signature is wrong. You are using asignature as the value of oauth_signature, but you have to compute the correct value for your request and set it to oauth_signature. If the value of oauth_signature is wrong, the server will reject your request. See "3.4. Signature" in RFC 5849 (The OAuth 1.0 Protocol) for details.

Upvotes: 1

Related Questions