Package org.waveprotocol.box.server.robots.dataapi

Source Code of org.waveprotocol.box.server.robots.dataapi.DataApiOAuthServletTest$ServletOutputStreamStub

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.waveprotocol.box.server.robots.dataapi;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.contains;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.google.common.collect.Maps;

import junit.framework.TestCase;

import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthProblemException;
import net.oauth.OAuthServiceProvider;
import net.oauth.OAuthValidator;
import net.oauth.OAuth.Parameter;

import org.waveprotocol.box.server.authentication.SessionManager;
import org.waveprotocol.wave.model.id.TokenGenerator;
import org.waveprotocol.wave.model.wave.ParticipantId;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
* Unit tests for the {@link DataApiOAuthServlet}.
*
* @author ljvderijk@google.com (Lennard de Rijk)
*/
public class DataApiOAuthServletTest extends TestCase {

  private static class ServletOutputStreamStub extends ServletOutputStream {

    private final StringWriter stringWriter;
    private boolean closed;

    public ServletOutputStreamStub() {
      stringWriter = new StringWriter();
    }

    @Override
    public void write(int b) {
      stringWriter.write((char) b);
    }

    @Override
    public String toString() {
      return stringWriter.toString();
    }

    public boolean isClosed() {
      return closed;
    }

    @Override
    public void close() throws IOException {
      super.close();
      stringWriter.close();
      closed = true;
    }

    @Override
    public boolean isReady() {
      return true;
    }

    @Override
    public void setWriteListener(WriteListener wl) {
    }
  }

  private static final String FAKE_TOKEN = "fake_token";
  private static final String REQUEST_TOKEN_PATH = "/request_token";
  private static final String AUTHORIZE_TOKEN_PATH = "/authorize_token";
  private static final String ACCESS_TOKEN_PATH = "/access_token";
  private static final String GET_ALL_TOKENS_PATH = "/get_all_tokens";
  private static final ParticipantId ALEX = ParticipantId.ofUnsafe("alex@example.com");
  private static final String CALLBACK_VALUE = "callback";

  private OAuthValidator validator;
  private DataApiTokenContainer tokenContainer;
  private SessionManager sessionManager;
  private HttpServletRequest req;
  private HttpServletResponse resp;
  private DataApiOAuthServlet servlet;
  private ServletOutputStreamStub outputStream;
  private StringWriter outputWriter;
  private OAuthConsumer consumer;

  @Override
  protected void setUp() throws Exception {
    validator = mock(OAuthValidator.class);
    sessionManager = mock(SessionManager.class);

    TokenGenerator tokenGenerator = mock(TokenGenerator.class);
    when(tokenGenerator.generateToken(anyInt())).thenReturn(FAKE_TOKEN);
    tokenContainer = new DataApiTokenContainer(tokenGenerator);

    req = mock(HttpServletRequest.class);
    when(req.getRequestURL()).thenReturn(new StringBuffer("www.example.com/robot"));
    when(req.getLocale()).thenReturn(Locale.ENGLISH);
    HttpSession sessionMock = mock(HttpSession.class);
    when(req.getSession()).thenReturn(sessionMock);
    when(req.getSession(anyBoolean())).thenReturn(sessionMock);

    resp = mock(HttpServletResponse.class);
    outputStream = new ServletOutputStreamStub();
    when(resp.getOutputStream()).thenReturn(outputStream);
    outputWriter = new StringWriter();
    when(resp.getWriter()).thenReturn(new PrintWriter(outputWriter));

    OAuthServiceProvider serviceProvider = new OAuthServiceProvider("", "", "");
    consumer = new OAuthConsumer("", "consumerkey", "consumersecret", serviceProvider);

    servlet =
        new DataApiOAuthServlet(REQUEST_TOKEN_PATH,
            AUTHORIZE_TOKEN_PATH, ACCESS_TOKEN_PATH, GET_ALL_TOKENS_PATH,
            serviceProvider, validator, tokenContainer, sessionManager, tokenGenerator);
  }

  @Override
  protected void tearDown() throws Exception {
    outputStream.close();
  }

  public void testDoRequestToken() throws Exception {
    when(req.getPathInfo()).thenReturn(REQUEST_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");

    servlet.doGet(req, resp);

    verify(resp).setStatus(HttpServletResponse.SC_OK);
    verify(validator).validateMessage(any(OAuthMessage.class), any(OAuthAccessor.class));
    assertTrue(outputStream.isClosed());

    // Verify that the output contains a token and token secret.
    String output = outputStream.toString();
    Map<String, String> parameters = toMap(OAuth.decodeForm(output));
    assertTrue("Request token should be present", parameters.containsKey(OAuth.OAUTH_TOKEN));
    assertTrue(
        "Request token secret should be present", parameters.containsKey(OAuth.OAUTH_TOKEN_SECRET));
    OAuthAccessor requestTokenAccessor =
        tokenContainer.getRequestTokenAccessor(parameters.get(OAuth.OAUTH_TOKEN));
    assertNotNull("Container should have stored the token", requestTokenAccessor);
    assertEquals("Correct secret should be returned", requestTokenAccessor.tokenSecret,
        parameters.get(OAuth.OAUTH_TOKEN_SECRET));
  }

  public void testDoRequestTokenUnauthorizedOnOAuthException() throws Exception {
    when(req.getPathInfo()).thenReturn(REQUEST_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");

    doThrow(new OAuthException("")).when(validator).validateMessage(
        any(OAuthMessage.class), any(OAuthAccessor.class));

    servlet.doGet(req, resp);

    verify(resp).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  }

  public void testDoRequestTokenUnauthorizedOnURISyntaxException() throws Exception {
    when(req.getPathInfo()).thenReturn(REQUEST_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");

    doThrow(new URISyntaxException("", "")).when(validator).validateMessage(
        any(OAuthMessage.class), any(OAuthAccessor.class));

    servlet.doGet(req, resp);

    verify(resp).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  }

  public void testDoAuthorizeTokenGet() throws Exception {
    when(req.getPathInfo()).thenReturn(AUTHORIZE_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");
    Map<String, String[]> params = getDoAuthorizeTokenParams();
    when(req.getParameterMap()).thenReturn(params);

    when(sessionManager.getLoggedInUser(any(HttpSession.class))).thenReturn(ALEX);

    servlet.doGet(req, resp);

    verify(resp).getWriter();
    assertFalse("Output must have been written", outputWriter.toString().isEmpty());
    verify(resp).setStatus(HttpServletResponse.SC_OK);
  }

  public void testDoAuthorizeTokenBadRequestOnMissingParameters() throws Exception {
    when(req.getPathInfo()).thenReturn(AUTHORIZE_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");

    // No parameters set.
    servlet.doGet(req, resp);

    verify(resp).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), anyString());
  }

  public void testDoAuthorizeTokenRedirectsForLogin() throws Exception {
    when(req.getPathInfo()).thenReturn(AUTHORIZE_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");
    Map<String, String[]> params = getDoAuthorizeTokenParams();
    when(req.getParameterMap()).thenReturn(params);

    String expectedRedirect = "/auth/login/fake";
    when(sessionManager.getLoginUrl(anyString())).thenReturn(expectedRedirect);

    // No user logged in.
    when(sessionManager.getLoggedInUser(any(HttpSession.class))).thenReturn(null);

    servlet.doGet(req, resp);

    verify(resp).sendRedirect(expectedRedirect);
  }

  public void testDoAuthorizeTokenUnauthorizedOnWrongToken() throws Exception {
    when(req.getPathInfo()).thenReturn(AUTHORIZE_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");
    Map<String, String[]> params = getDoAuthorizeTokenParams();
    params.put(OAuth.OAUTH_TOKEN, new String[] {"wrong_token"});
    when(req.getParameterMap()).thenReturn(params);

    when(sessionManager.getLoggedInUser(any(HttpSession.class))).thenReturn(ALEX);

    servlet.doGet(req, resp);

    verify(resp).sendError(eq(HttpServletResponse.SC_UNAUTHORIZED), anyString());
  }

  public void testDoAuthorizeTokenPost() throws Exception {
    when(req.getPathInfo()).thenReturn(AUTHORIZE_TOKEN_PATH);
    when(req.getMethod()).thenReturn("POST");
    Map<String, String[]> params = getDoAuthorizeTokenParams();
    when(req.getParameterMap()).thenReturn(params);
    String token = servlet.getOrGenerateXsrfToken(ALEX);
    when(req.getParameter("token")).thenReturn(token);
    when(req.getParameter("agree")).thenReturn("yes");

    when(sessionManager.getLoggedInUser(any(HttpSession.class))).thenReturn(ALEX);

    servlet.doPost(req, resp);

    verify(resp).sendRedirect(contains(CALLBACK_VALUE));
    String requestToken = params.get(OAuth.OAUTH_TOKEN)[0];
    assertEquals("Token should be authorized by Alex", ALEX,
        tokenContainer.getRequestTokenAccessor(requestToken).getProperty(
            DataApiTokenContainer.USER_PROPERTY_NAME));
  }

  public void testDoAuthorizeTokenPostUnauthorizedOnFailingXsrf() throws Exception {
    when(req.getPathInfo()).thenReturn(AUTHORIZE_TOKEN_PATH);
    when(req.getMethod()).thenReturn("POST");
    Map<String, String[]> params = getDoAuthorizeTokenParams();
    when(req.getParameterMap()).thenReturn(params);
    when(req.getParameter("token")).thenReturn("wrong_token");

    when(sessionManager.getLoggedInUser(any(HttpSession.class))).thenReturn(ALEX);

    servlet.doPost(req, resp);

    verify(resp).sendError(eq(HttpServletResponse.SC_UNAUTHORIZED), anyString());
  }

  public void testDoAuthorizeTokenPostRejectsToken() throws Exception {
    when(req.getPathInfo()).thenReturn(AUTHORIZE_TOKEN_PATH);
    when(req.getMethod()).thenReturn("POST");
    when(req.getParameter("cancel")).thenReturn("yes");
    Map<String, String[]> params = getDoAuthorizeTokenParams();
    when(req.getParameterMap()).thenReturn(params);
    String token = servlet.getOrGenerateXsrfToken(ALEX);
    when(req.getParameter("token")).thenReturn(token);

    when(sessionManager.getLoggedInUser(any(HttpSession.class))).thenReturn(ALEX);

    servlet.doPost(req, resp);

    verify(resp).setStatus(HttpServletResponse.SC_OK);
    try {
      tokenContainer.getRequestTokenAccessor(params.get(OAuth.OAUTH_TOKEN)[0]);
      fail("This token should not be present anymore");
    } catch (OAuthProblemException e) {
      // expected
    }
  }

  public void testDoAuthorizeTokenPostBadRequestWhenOmittedPostData() throws Exception {
    when(req.getPathInfo()).thenReturn(AUTHORIZE_TOKEN_PATH);
    when(req.getMethod()).thenReturn("POST");

    Map<String, String[]> params = getDoAuthorizeTokenParams();
    when(req.getParameterMap()).thenReturn(params);
    String token = servlet.getOrGenerateXsrfToken(ALEX);
    when(req.getParameter("token")).thenReturn(token);

    when(sessionManager.getLoggedInUser(any(HttpSession.class))).thenReturn(ALEX);

    // We didn't set the cancel nor agree param, i.e. something is wrong with
    // the form being submitted.
    servlet.doPost(req, resp);

    verify(resp).setStatus(HttpServletResponse.SC_BAD_REQUEST);
  }

  public void testDoExchangeToken() throws Exception {
    when(req.getPathInfo()).thenReturn(ACCESS_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");
    Map<String, String[]> params = getDoExchangeTokenParams();
    when(req.getParameterMap()).thenReturn(params);

    servlet.doGet(req, resp);

    verify(validator).validateMessage(any(OAuthMessage.class), any(OAuthAccessor.class));
    verify(resp).setStatus(HttpServletResponse.SC_OK);

    // Verify that the output contains a token and token secret.
    String output = outputStream.toString();
    Map<String, String> parameters = toMap(OAuth.decodeForm(output));
    assertTrue("Access token should be present", parameters.containsKey(OAuth.OAUTH_TOKEN));
    assertTrue(
        "Access token secret should be present", parameters.containsKey(OAuth.OAUTH_TOKEN_SECRET));
    OAuthAccessor accessTokenAccessor =
        tokenContainer.getAccessTokenAccessor(parameters.get(OAuth.OAUTH_TOKEN));
    assertNotNull("Container should have stored the token", accessTokenAccessor);
    assertEquals("Correct secret should be returned", accessTokenAccessor.tokenSecret,
        parameters.get(OAuth.OAUTH_TOKEN_SECRET));
  }

  public void testDoExchangeTokenUnauthorizedOnUnknownToken() throws Exception {
    when(req.getPathInfo()).thenReturn(ACCESS_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");
    Map<String, String[]> params = getDoExchangeTokenParams();
    params.put(OAuth.OAUTH_TOKEN, new String[] {"unknown"});
    when(req.getParameterMap()).thenReturn(params);

    servlet.doGet(req, resp);

    verify(resp).sendError(eq(HttpServletResponse.SC_UNAUTHORIZED), anyString());
  }

  public void testDoExchangeTokenUnauthorizedOnOAuthException() throws Exception {
    when(req.getPathInfo()).thenReturn(ACCESS_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");

    Map<String, String[]> params = getDoExchangeTokenParams();
    when(req.getParameterMap()).thenReturn(params);

    doThrow(new OAuthException("")).when(validator).validateMessage(
        any(OAuthMessage.class), any(OAuthAccessor.class));

    servlet.doGet(req, resp);

    verify(validator).validateMessage(any(OAuthMessage.class), any(OAuthAccessor.class));
    verify(resp).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  }

  public void testDoExchangeTokenUnauthorizedOnURISyntaxException() throws Exception {
    when(req.getPathInfo()).thenReturn(ACCESS_TOKEN_PATH);
    when(req.getMethod()).thenReturn("GET");
    Map<String, String[]> params = getDoExchangeTokenParams();
    when(req.getParameterMap()).thenReturn(params);

    doThrow(new URISyntaxException("", "")).when(validator).validateMessage(
        any(OAuthMessage.class), any(OAuthAccessor.class));

    servlet.doGet(req, resp);

    verify(validator).validateMessage(any(OAuthMessage.class), any(OAuthAccessor.class));
    verify(resp).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  }

  /** Sets the list of parameters needed for testing authorizing a request token */
  private Map<String, String[]> getDoAuthorizeTokenParams() {
    OAuthAccessor requestAccessor = tokenContainer.generateRequestToken(consumer);
    Map<String, String[]> params = Maps.newHashMap();
    params.put(OAuth.OAUTH_TOKEN, new String[] {requestAccessor.requestToken});
    params.put(OAuth.OAUTH_CALLBACK, new String[] {CALLBACK_VALUE});
    return params;
  }

  /** Sets the list of parameters needed to test exchanging a request token */
  private Map<String, String[]> getDoExchangeTokenParams() throws Exception {
    OAuthAccessor requestAccessor = tokenContainer.generateRequestToken(consumer);
    tokenContainer.authorizeRequestToken(requestAccessor.requestToken, ALEX);
    Map<String, String[]> params = Maps.newHashMap();
    params.put(OAuth.OAUTH_TOKEN, new String[] {requestAccessor.requestToken});
    return params;
  }

  /**
   * Converts a list of parameters to a map.
   */
  private static Map<String, String> toMap(List<Parameter> params) {
    Map<String, String> map = Maps.newHashMap();
    for (Parameter parameter : params) {
      map.put(parameter.getKey(), parameter.getValue());
    }
    return map;
  }
}
TOP

Related Classes of org.waveprotocol.box.server.robots.dataapi.DataApiOAuthServletTest$ServletOutputStreamStub

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.