Package com.google.appengine.tck.oauth

Source Code of com.google.appengine.tck.oauth.ClientSideWebAppFlowTest

/*
* Copyright 2013 Google Inc. All Rights Reserved.
* 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.google.appengine.tck.oauth;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.google.appengine.api.oauth.InvalidOAuthParametersException;
import com.google.appengine.api.oauth.InvalidOAuthTokenException;
import com.google.appengine.api.oauth.OAuthService;
import com.google.appengine.api.oauth.OAuthServiceFactory;
import com.google.appengine.tck.env.Environment;
import com.google.appengine.tck.event.Property;
import com.google.appengine.tck.oauth.support.OAuthServletAnswer;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.Graphene;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

/**
* This uses the Client-Side Web Applications Flow.
*
* Set up:
*
* Create a client Id, and redirect URL for type Web Application. As of today you need to use the
* soon to be retired Cloud Console as creating the client Id is not supported in the new one yet.
*   https://code.google.com/apis/console/b/0/?noredirect
*
* Create a non-admin account that will be used to get the authentication token.
*   -Dappengine.nonAdminTestingAccount.email=
*   -Dappengine.nonAdminTestingAccount.pw=
*
* @author <a href="mailto:terryok@google.com">Terry Okamoto</a>
* @author <a href="mailto:mluksa@redhat.com">Marko Luksa</a>
*/

@SuppressWarnings("UnusedDeclaration")
@RunWith(Arquillian.class)
public class ClientSideWebAppFlowTest extends OAuthTestBase {

    private OAuthService oAuthService;
    private CloseableHttpClient client;
    @Drone
    private WebDriver driver;

    private static final String GOOGLE_OAUTH2_REQUEST_TOKEN_URL = "https://accounts.google.com/o/oauth2/auth";
    private static final String SCOPE_USER = "https://www.googleapis.com/auth/userinfo.email";
    private static final String SCOPE_PROFILE = "https://www.googleapis.com/auth/userinfo.profile";

    private static Map<String, String> tokenCache;

    @Deployment
    public static WebArchive getDeployment() {
        return getBaseDeployment();
    }

    @BeforeClass
    public static void initTokenTable() {
        tokenCache = new HashMap<>();
    }

    @Before
    public void setUp() {
        initProperties();

        if (isInContainer()) {
            oAuthService = OAuthServiceFactory.getOAuthService();
        }

        client = HttpClients.createDefault();
    }

    @After
    public void tearDown() {
        if (client != null) {
            try {
                client.close();
            } catch (IOException ignored) {
            }
        }
    }

    @Test
    @RunAsClient
    public void testUnauthenticatedRequest(@ArquillianResource URL url) throws Exception {
        String response = invokeMethodOnServerUnauthenticated(url, "getEmail");
        OAuthServletAnswer answer = new OAuthServletAnswer(response);

        assertEquals("Should NOT be authenticated: " + answer.getReturnVal(), "user is null", answer.getReturnVal());
    }

    @Test
    @RunAsClient
    public void testGetEmailValidScope(@ArquillianResource URL url) throws Exception {
        String accessToken = getGoogleAccessToken(nonAdminTestingAccountEmail, nonAdminTestingAccountPw,
            oauthClientId, oauthRedirectUri, SCOPE_USER);

        String response = invokeMethodOnServer(url, "getEmail", accessToken, SCOPE_USER);
        OAuthServletAnswer answer = new OAuthServletAnswer(response);

        assertEquals("Should have been authenticated.", nonAdminTestingAccountEmail, answer.getReturnVal());
    }

    @Test
    @RunAsClient
    public void testNoScopeThrowsInvalidOAuthTokenException(@ArquillianResource URL url) throws Exception {
        assumeEnvironment(Environment.APPSPOT);

        String accessToken = getGoogleAccessToken(nonAdminTestingAccountEmail, nonAdminTestingAccountPw,
            oauthClientId, oauthRedirectUri, SCOPE_USER);

        String emptyScope = "";
        String response = invokeMethodOnServer(url, "getEmail", accessToken, emptyScope);
        OAuthServletAnswer answer = new OAuthServletAnswer(response);

        String expectedException = InvalidOAuthTokenException.class.getName();
        assertTrue("Expected: " + expectedException, answer.getReturnVal().startsWith(expectedException));
    }

    @Test
    @RunAsClient
    public void testInvalidScopeThrowsInvalidOAuthTokenException(@ArquillianResource URL url) throws Exception {
        assumeEnvironment(Environment.APPSPOT);

        String accessToken = getGoogleAccessToken(nonAdminTestingAccountEmail, nonAdminTestingAccountPw,
            oauthClientId, oauthRedirectUri, SCOPE_USER);

        String invalidScope = SCOPE_PROFILE;
        String response = invokeMethodOnServer(url, "getEmail", accessToken, invalidScope);
        OAuthServletAnswer answer = new OAuthServletAnswer(response);

        String expectedException = InvalidOAuthParametersException.class.getName();
        assertTrue("Expected: " + expectedException + ", but was " + answer.getReturnVal(),
            answer.getReturnVal().startsWith(expectedException));
    }

    @Test
    @RunAsClient
    public void testUnauthorizedMultipleScopeDoesNotAuthenticate(@ArquillianResource URL url) throws Exception {
        assumeEnvironment(Environment.APPSPOT);

        String accessToken = getGoogleAccessToken(nonAdminTestingAccountEmail, nonAdminTestingAccountPw,
            oauthClientId, oauthRedirectUri, SCOPE_USER);

        String multiScope = SCOPE_USER + " " + SCOPE_PROFILE;
        String response = invokeMethodOnServer(url, "getEmail", accessToken, multiScope);
        OAuthServletAnswer answer = new OAuthServletAnswer(response);


        String expectedException = InvalidOAuthParametersException.class.getName();
        assertTrue("Multiple scopes should not match, expected " + expectedException + ", but was " + answer.getReturnVal(),
            answer.getReturnVal().contains(expectedException));
    }

    @RunAsClient
    public void testIsUserAdminFalse(@ArquillianResource URL url) throws Exception {
        String accessToken = getGoogleAccessToken(nonAdminTestingAccountEmail, nonAdminTestingAccountPw,
            oauthClientId, oauthRedirectUri, SCOPE_USER);

        String response = invokeMethodOnServer(url, "isUserAdmin", accessToken, SCOPE_USER);
        OAuthServletAnswer answer = new OAuthServletAnswer(response);

        assertTrue(nonAdminTestingAccountEmail + " should NOT be a valid admin.",
            answer.getReturnVal().equals("false"));
    }

    @Test
    @RunAsClient
    public void testGetClientId(@ArquillianResource URL url) {
        assumeEnvironment(Environment.APPSPOT);

        String accessToken = getGoogleAccessToken(nonAdminTestingAccountEmail, nonAdminTestingAccountPw,
            oauthClientId, oauthRedirectUri, SCOPE_USER);

        String response = invokeMethodOnServer(url, "getClientId", accessToken, SCOPE_USER);
        OAuthServletAnswer answer = new OAuthServletAnswer(response);

        assertEquals(oauthClientId, answer.getReturnVal());
    }

    /**
     * This can get a single scope only.  Unable to automate requesting token for multiple scopes.
     */
    private String getGoogleAccessToken(String email, String pw, String client_id, String redirect_uri, String scope) {
        Property staticToken = property("authToken");
        if (staticToken.exists()) {
            return staticToken.getPropertyValue();
        }

        // https://accounts.google.com/o/oauth2/auth?response_type=token&client_id=37298738223-o26xasxd7a217srs4t7ue1fudmt1ao1ge5.apps.googleusercontent.com&redirect_uri=https://[YOUR_TEST_APP].appspot.com/your_redirect_path&scope=https://www.googleapis.com/auth/userinfo.email

        String requestTokenUrl = String.format("%s?response_type=token&client_id=%s&redirect_uri=%s&scope=%s",
            GOOGLE_OAUTH2_REQUEST_TOKEN_URL, client_id, redirect_uri, scope);

        String cacheKey = email + ":" + requestTokenUrl;
        if (tokenCache.containsKey(cacheKey)) {
            return tokenCache.get(cacheKey);
        }
        driver.manage().deleteAllCookies();
        driver.get(requestTokenUrl);

        try {
            driver.findElement(By.id("Email")).sendKeys(email);
            driver.findElement(By.id("Passwd")).sendKeys(pw);
            driver.findElement(By.id("signIn")).submit();
        } catch (NoSuchElementException nsee) {
            String errMsg = driver.getCurrentUrl() + " ----- " + driver.getPageSource();
            throw new NoSuchElementException(nsee.toString() + " ----- " + errMsg);
        }

        try {
            WebElement button = driver.findElement(By.id("submit_approve_access"));
            Graphene.waitModel(driver).withTimeout(5, TimeUnit.SECONDS).until().element(button).is().enabled();
            button.click();
        } catch (NoSuchElementException e) {
            // Apparently access has already been approved and the user is not being asked to approve access.
            // The approval page will only be displayed again after access is revoked through Google Accounts.
        }

        // The redirect looks like:
        // https://[YOUR_TEST_APP.appspot.com/your_redirect_path#access_token=ee29.AHES6ZQPPOue4vgQhacbi__AN8Y0wLLt60sEchFaw&token_type=Bearer&expires_in=3600

        // URLEncodedUtils unable to parse parameters after #
        String redirectUrlWithToken = driver.getCurrentUrl().replace("#access_token=", "?access_token=");

        List<NameValuePair> params;
        try {
            params = URLEncodedUtils.parse(new URI(redirectUrlWithToken), "UTF-8");
        } catch (URISyntaxException urise) {
            throw new IllegalStateException(urise);
        }

        String accessToken = null;
        for (NameValuePair param : params) {
            if (param.getName().equals("access_token")) {
                accessToken = param.getValue();
            }
        }
        assertNotNull("Token is null:" + driver.getCurrentUrl() + " ----- " + driver.getPageSource(), accessToken);

        tokenCache.put(cacheKey, accessToken);
        return accessToken;
    }

    private String invokeMethodOnServer(URL baseUrl, String methodName, String accessToken, String scope) {

        HttpGet g = new HttpGet(String.format("%s/oauth-service-helper?method=%s", baseUrl, methodName));
        g.addHeader("Authorization", "Bearer " + accessToken);
        g.addHeader("oauth-test-scope", scope);
        HttpResponse response;
        String responseContent;
        try {
            responseContent = EntityUtils.toString(client.execute(g).getEntity());
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
        return responseContent;
    }

    private String invokeMethodOnServerUnauthenticated(URL baseUrl, String methodName) {

        HttpGet g = new HttpGet(String.format("%s/oauth-service-helper?method=%s", baseUrl, methodName));
        HttpResponse response;
        String responseContent;
        try {
            responseContent = EntityUtils.toString(client.execute(g).getEntity());
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
        return responseContent;
    }
}
TOP

Related Classes of com.google.appengine.tck.oauth.ClientSideWebAppFlowTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.