com.here.account.auth.OAuth1SignerTest.java Source code

Java tutorial

Introduction

Here is the source code for com.here.account.auth.OAuth1SignerTest.java

Source

/*
 * Copyright (c) 2016 HERE Europe B.V.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.here.account.auth;

import static org.junit.Assert.assertTrue;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.junit.Before;
import org.junit.Test;

import com.here.account.http.HttpProvider.HttpRequest;
import com.here.account.util.Clock;
import com.here.account.util.OAuthConstants;

public class OAuth1SignerTest {

    private String clientId = "clientId";
    private String clientSecret = "clientSecret";

    private OAuth1Signer oauth1Signer;

    MyHttpRequest httpRequest;

    private static class MyHttpRequest implements HttpRequest {

        private String authorizationHeader;

        public MyHttpRequest() {
            super();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void addAuthorizationHeader(String value) {
            this.authorizationHeader = value;
        }

        public String getAuthorizationHeader() {
            return this.authorizationHeader;
        }

    }

    private String method;
    private String url;
    private Clock clock;

    private long clockCurrentTimeMillis = 0;

    @Before
    public void setUp() {
        this.clock = new Clock() {

            @Override
            public long currentTimeMillis() {
                // TODO Auto-generated method stub
                return clockCurrentTimeMillis;
            }

            @Override
            public void schedule(ScheduledExecutorService scheduledExecutorService, Runnable runnable,
                    long millisecondsInTheFutureToSchedule) {
                // TODO Auto-generated method stub

            }

        };
        this.oauth1Signer = new MyOAuth1Signer(clock, clientId, clientSecret);
        this.httpRequest = new MyHttpRequest();
        this.method = "GET";
        this.url = "http://localhost:8080/whatever";
    }

    protected static class MyOAuth1Signer extends OAuth1Signer {
        public MyOAuth1Signer(Clock clock, String clientId, String clientSecret) {
            super(clock, clientId, clientSecret);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void nextBytes(byte[] bytes) {
            byte a = 0x00;
            for (int i = 0; i < bytes.length; i++) {
                bytes[i] = a;
                a += 0x01;
            }
        }
    }

    @Test
    public void test_sign_formParams_impactsSignature() {
        Map<String, List<String>> formParams = null;

        oauth1Signer.authorize(httpRequest, method, url, formParams);
        String signatureNull = httpRequest.getAuthorizationHeader();

        formParams = new HashMap<String, List<String>>();
        oauth1Signer.authorize(httpRequest, method, url, formParams);
        String signatureEmpty = httpRequest.getAuthorizationHeader();

        formParams.put("foo", Collections.singletonList("bar"));
        oauth1Signer.authorize(httpRequest, method, url, formParams);
        String signatureFooBar = httpRequest.getAuthorizationHeader();

        formParams.put("foo", Collections.singletonList("none"));
        oauth1Signer.authorize(httpRequest, method, url, formParams);
        String signatureFooNone = httpRequest.getAuthorizationHeader();

        assertTrue("signatureNull was null, but shouldn't be", null != signatureNull);
        assertTrue("signatureEmpty was null, but shouldn't be", null != signatureEmpty);
        assertTrue("signatureFooBar was null, but shouldn't be", null != signatureFooBar);
        assertTrue("signatureFooNone was null, but shouldn't be", null != signatureFooNone);

        assertTrue("signatureNull " + signatureNull + " doesn't match signatureEmpty " + signatureEmpty,
                signatureNull.equals(signatureEmpty));
        assertTrue("signatureNull " + signatureNull + " matches signatureFooBar " + signatureFooBar
                + ", but shouldn't", !signatureNull.equals(signatureFooBar));
        assertTrue("signatureFooBar " + signatureFooBar + " matches signatureFooNone " + signatureFooNone
                + ", but shouldn't", !signatureFooBar.equals(signatureFooNone));
    }

    /**
     * Demonstrate the tradeoffs between HmacSHA1 and HmacSHA256 signature methods.
     * OAuth1 signature spec calls out the former by name, 
     * but is extensible to the latter as well.
     * 
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws UnsupportedEncodingException 
     */
    @Test
    public void test_HmacSHA1_HmacSHA256()
            throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
        String key = UUID.randomUUID().toString();

        String input = "my dog has fleas";

        String sig1 = HmacSHAN(key, "HmacSHA1", input);
        assertTrue("sig1 was null for HmacSHA1", null != sig1);

        String sig256 = HmacSHAN(key, "HmacSHA256", input);
        assertTrue("sig256 was null for HmacSHA256", null != sig256);

        assertTrue("sig1 " + sig1 + " wasn't smaller than sig256 " + sig256, sig1.length() < sig256.length());

    }

    @Test
    public void test_OAuth1Signer_uses_HMAC_SHA256()
            throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException {
        this.clockCurrentTimeMillis = System.currentTimeMillis();

        byte[] nonceBytes = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
        String nonce = Base64.encodeBase64URLSafeString(nonceBytes).substring(0, nonceBytes.length);

        long oauth_timestamp = clockCurrentTimeMillis / 1000L; // oauth1 uses seconds

        String shaVariant = "SHA256";//"SHA1";

        String requestParameters = "oauth_consumer_key=" + clientId + "&oauth_nonce=" + nonce
                + "&oauth_signature_method=HMAC-" + shaVariant + "&oauth_timestamp=" + oauth_timestamp
                + "&oauth_version=1.0";
        String signatureBaseString = "GET&" + urlEncode(url) + "&" + urlEncode(requestParameters); // no request parameters in this test case

        System.out.println("test       signatureBaseString " + signatureBaseString);

        String key = urlEncode(clientSecret) + "&"; // no token shared-secret

        String expectedSignature = HmacSHAN(key, "Hmac" + shaVariant, signatureBaseString);

        String expectedSignatureInAuthorizationHeader = urlEncode(expectedSignature);

        oauth1Signer.authorize(httpRequest, method, url, null);
        String actualHeader = httpRequest.getAuthorizationHeader();

        Pattern pattern = Pattern.compile("\\A.*oauth_signature=\\\"([^\\\"]+).*\\z");
        Matcher matcher = pattern.matcher(actualHeader);
        assertTrue("pattern wasn't matched: " + actualHeader, matcher.matches());
        String actualSignature = matcher.group(1);

        assertTrue("expected signature " + expectedSignatureInAuthorizationHeader + ", actual signature "
                + actualSignature, expectedSignatureInAuthorizationHeader.equals(actualSignature));
    }

    private String urlEncode(String s) throws UnsupportedEncodingException {
        return URLEncoder.encode(s, OAuthConstants.UTF_8_STRING).replaceAll("\\+", "%20");
    }

    protected String HmacSHAN(String keyString, String algorithm, String baseString)
            throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
        /*
                 byte[] keyBytes = (urlEncode(consumerSecret) + "&").getBytes(OAuthConstants.UTF_8_CHARSET);
        SecretKeySpec signingKey = new SecretKeySpec(keyBytes, signatureMethod);
            
        //generate signature based on the requested signature method
        Mac mac = Mac.getInstance(signatureMethod);
        mac.init(signingKey);
        byte[] signedBytes = mac.doFinal(bytesToSign);
        return Base64.encodeBase64String(signedBytes);
            
         */
        byte[] keyBytes = keyString.getBytes("UTF-8");
        Key signingKey = new SecretKeySpec(keyBytes, algorithm);
        Mac mac = Mac.getInstance(algorithm);
        mac.init(signingKey);

        //generate signature bytes
        byte[] signatureBytes = mac.doFinal(baseString.getBytes("UTF-8"));

        // base64-encode the hmac
        //return new Base64().encodeAsString(signatureBytes);
        return Base64.encodeBase64String(signatureBytes);
    }

}