/* * Copyright 2016, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.google.auth.oauth2; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import com.google.common.collect.ImmutableMap; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class AppEngineCredentialsTest extends BaseSerializationTest { private static final String EXPECTED_ACCESS_TOKEN = "ExpectedAccessToken"; private static final Date EXPECTED_EXPIRATION_DATE = new Date(System.currentTimeMillis() + 60L * 60L * 100L); private static final byte[] EXPECTED_SIGNATURE = {0xD, 0xE, 0xA, 0xD}; private static final String EXPECTED_ACCOUNT = "serviceAccount"; private static final Collection SCOPES = Collections.unmodifiableCollection(Arrays.asList("scope1", "scope2")); private static final Collection DEFAULT_SCOPES = Collections.unmodifiableCollection(Arrays.asList("scope3")); @Test public void constructor_usesAppIdentityService() throws IOException { Collection scopes = Collections.singleton("SomeScope"); TestAppEngineCredentials credentials = new TestAppEngineCredentials(scopes); List forNameArgs = credentials.getForNameArgs(); assertEquals(4, forNameArgs.size()); assertEquals(AppEngineCredentials.APP_IDENTITY_SERVICE_FACTORY_CLASS, forNameArgs.get(0)); assertEquals(AppEngineCredentials.APP_IDENTITY_SERVICE_CLASS, forNameArgs.get(1)); assertEquals(AppEngineCredentials.GET_ACCESS_TOKEN_RESULT_CLASS, forNameArgs.get(2)); assertEquals(AppEngineCredentials.SIGNING_RESULT_CLASS, forNameArgs.get(3)); } @Test public void constructor_noAppEngineRuntime_throwsHelpfulLoadError() throws IOException { try { new TestAppEngineCredentialsNoSdk(); fail("Credential expected to fail to load if credential class not present."); } catch (IOException e) { String message = e.getMessage(); assertTrue(message.contains("Check that the App Engine SDK is deployed.")); assertTrue(e.getCause() instanceof ClassNotFoundException); assertTrue( e.getCause() .getMessage() .contains(AppEngineCredentials.APP_IDENTITY_SERVICE_FACTORY_CLASS)); } } @Test public void refreshAccessToken_sameAs() throws IOException { TestAppEngineCredentials credentials = new TestAppEngineCredentials(SCOPES); AccessToken accessToken = credentials.refreshAccessToken(); assertEquals(EXPECTED_ACCESS_TOKEN, accessToken.getTokenValue()); assertEquals(EXPECTED_EXPIRATION_DATE, accessToken.getExpirationTime()); } @Test public void getAccount_sameAs() throws IOException { TestAppEngineCredentials credentials = new TestAppEngineCredentials(SCOPES); assertEquals(EXPECTED_ACCOUNT, credentials.getAccount()); } @Test public void sign_sameAs() throws IOException { TestAppEngineCredentials credentials = new TestAppEngineCredentials(SCOPES); assertArrayEquals(EXPECTED_SIGNATURE, credentials.sign("Bytes to sign".getBytes())); } @Test public void createScoped_clonesWithScopes() throws IOException { TestAppEngineCredentials credentials = new TestAppEngineCredentials(null); assertTrue(credentials.createScopedRequired()); try { credentials.refreshAccessToken(); fail("Should not be able to use credential without scopes."); } catch (Exception expected) { // Expected } GoogleCredentials scopedCredentials = credentials.createScoped(SCOPES); assertNotSame(credentials, scopedCredentials); AccessToken accessToken = scopedCredentials.refreshAccessToken(); assertEquals(EXPECTED_ACCESS_TOKEN, accessToken.getTokenValue()); assertEquals(EXPECTED_EXPIRATION_DATE, accessToken.getExpirationTime()); } @Test public void createScoped_defaultScopes() throws IOException { TestAppEngineCredentials credentials = new TestAppEngineCredentials(null); assertTrue(credentials.createScopedRequired()); GoogleCredentials newCredentials = credentials.createScoped(null, DEFAULT_SCOPES); assertFalse(newCredentials.createScopedRequired()); newCredentials = credentials.createScoped(SCOPES, null); assertFalse(newCredentials.createScopedRequired()); newCredentials = credentials.createScoped(SCOPES, DEFAULT_SCOPES); assertFalse(newCredentials.createScopedRequired()); AccessToken accessToken = newCredentials.refreshAccessToken(); assertEquals(EXPECTED_ACCESS_TOKEN, accessToken.getTokenValue()); assertEquals(EXPECTED_EXPIRATION_DATE, accessToken.getExpirationTime()); } @Test public void equals_true() throws IOException { GoogleCredentials credentials = new TestAppEngineCredentials(SCOPES); GoogleCredentials otherCredentials = new TestAppEngineCredentials(SCOPES); assertTrue(credentials.equals(credentials)); assertTrue(credentials.equals(otherCredentials)); assertTrue(otherCredentials.equals(credentials)); } @Test public void equals_false_scopes() throws IOException { final Collection emptyScopes = Collections.emptyList(); Collection scopes = Collections.singleton("SomeScope"); AppEngineCredentials credentials = new TestAppEngineCredentials(emptyScopes); AppEngineCredentials otherCredentials = new TestAppEngineCredentials(scopes); assertFalse(credentials.equals(otherCredentials)); assertFalse(otherCredentials.equals(credentials)); } @Test public void toString_containsFields() throws IOException { String expectedToString = String.format( "TestAppEngineCredentials{scopes=[%s], scopesRequired=%b}", "SomeScope", false); Collection scopes = Collections.singleton("SomeScope"); AppEngineCredentials credentials = new TestAppEngineCredentials(scopes); assertEquals(expectedToString, credentials.toString()); } @Test public void hashCode_equals() throws IOException { AppEngineCredentials credentials = new TestAppEngineCredentials(SCOPES); assertEquals(credentials.hashCode(), credentials.hashCode()); } @Test public void serialize() throws IOException, ClassNotFoundException { Collection scopes = Collections.singleton("SomeScope"); AppEngineCredentials credentials = new TestAppEngineCredentials(scopes); GoogleCredentials deserializedCredentials = serializeAndDeserialize(credentials); assertEquals(credentials, deserializedCredentials); assertEquals(credentials.hashCode(), deserializedCredentials.hashCode()); assertEquals(credentials.toString(), deserializedCredentials.toString()); } private static class TestSigningResult { private final byte[] signature; TestSigningResult(byte[] signature) { this.signature = signature; } public byte[] getSignature() { return this.signature; } } private static class TestAppIdentityServiceFactory { public static TestAppIdentityService getAppIdentityService() { return new TestAppIdentityService(); } } private static class TestAppIdentityService { public TestGetAccessTokenResult getAccessToken(Iterable scopes) { return new TestGetAccessTokenResult(EXPECTED_ACCESS_TOKEN, EXPECTED_EXPIRATION_DATE); } public String getServiceAccountName() { return EXPECTED_ACCOUNT; } public TestSigningResult signForApp(byte[] toSign) { return new TestSigningResult(EXPECTED_SIGNATURE); } } private static class TestGetAccessTokenResult { private final String accessToken; private final Date expirationTime; TestGetAccessTokenResult(String accessToken, Date expirationTime) { this.accessToken = accessToken; this.expirationTime = expirationTime; } public String getAccessToken() { return this.accessToken; } public Date getExpirationTime() { return this.expirationTime; } } private static class TestAppEngineCredentials extends AppEngineCredentials { private static final long serialVersionUID = -5191475572296306231L; private static final Map> TYPES = ImmutableMap.of( AppEngineCredentials.APP_IDENTITY_SERVICE_FACTORY_CLASS, TestAppIdentityServiceFactory.class, AppEngineCredentials.APP_IDENTITY_SERVICE_CLASS, TestAppIdentityService.class, AppEngineCredentials.GET_ACCESS_TOKEN_RESULT_CLASS, TestGetAccessTokenResult.class, AppEngineCredentials.SIGNING_RESULT_CLASS, TestSigningResult.class); private List forNameArgs; TestAppEngineCredentials(Collection scopes) throws IOException { super(scopes, null); } TestAppEngineCredentials(Collection scopes, Collection defaultScopes) throws IOException { super(scopes, defaultScopes); } @Override Class forName(String className) throws ClassNotFoundException { if (forNameArgs == null) { forNameArgs = new ArrayList<>(); } forNameArgs.add(className); Class lookup = TYPES.get(className); if (lookup != null) { return lookup; } throw new ClassNotFoundException(className); } List getForNameArgs() { return forNameArgs; } } private static class TestAppEngineCredentialsNoSdk extends AppEngineCredentials { private static final long serialVersionUID = -8987103249265111274L; TestAppEngineCredentialsNoSdk() throws IOException { super(null, null); } @Override Class forName(String className) throws ClassNotFoundException { throw new ClassNotFoundException(className); } } }