io.syndesis.runtime.credential.CredentialITCase.java Source code

Java tutorial

Introduction

Here is the source code for io.syndesis.runtime.credential.CredentialITCase.java

Source

/**
 * Copyright (C) 2016 Red Hat, Inc.
 *
 * 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 io.syndesis.runtime.credential;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.NewCookie;

import io.syndesis.credential.AcquisitionMethod;
import io.syndesis.credential.AcquisitionResponse;
import io.syndesis.credential.AcquisitionResponse.State;
import io.syndesis.credential.CredentialFlowState;
import io.syndesis.credential.Credentials;
import io.syndesis.credential.OAuth2CredentialFlowState;
import io.syndesis.credential.Type;
import io.syndesis.model.connection.ConfigurationProperty;
import io.syndesis.model.connection.Connection;
import io.syndesis.model.connection.Connector;
import io.syndesis.rest.v1.state.ClientSideState;
import io.syndesis.runtime.BaseITCase;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.springframework.web.util.UriUtils.encode;

public class CredentialITCase extends BaseITCase {

    @Autowired
    ClientSideState clientSideState;

    @Test
    public void callbackErrorsShouldBeHandeled() {
        final String credentialKey = UUID.randomUUID().toString();
        final OAuth2CredentialFlowState flowState = new OAuth2CredentialFlowState.Builder()
                .providerId("test-provider").key(credentialKey).returnUrl(URI.create("/ui#state")).build();

        final HttpHeaders cookies = persistAsCookie(flowState);

        final ResponseEntity<Void> callbackResponse = http(HttpMethod.GET,
                "/api/v1/credentials/callback?denied=something", null, Void.class, null, cookies,
                HttpStatus.TEMPORARY_REDIRECT);

        assertThat(callbackResponse.getStatusCode()).as("Status should be temporarry redirect (307)")
                .isEqualTo(HttpStatus.TEMPORARY_REDIRECT);
        assertThat(callbackResponse.hasBody()).as("Should not contain HTTP body").isFalse();
        assertThat(callbackResponse.getHeaders().getLocation().toString()).matches(
                "http.?://localhost:[0-9]*/api/v1/ui#%7B%22connectorId%22:%22test-provider%22,%22message%22:%22Unable%20to%20update%20the%20state%20of%20authorization%22,%22status%22:%22FAILURE%22%7D");

        final List<String> receivedCookies = callbackResponse.getHeaders().get("Set-Cookie");
        assertThat(receivedCookies).hasSize(1);
        assertThat(receivedCookies.get(0)).isEqualTo("cred-o2-" + credentialKey
                + "=\"\"; path=/; secure; HttpOnly; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:00 GMT");
    }

    @After
    public void cleanupDatabase() {
        dataManager.delete(Connector.class, "test-provider");
        dataManager.delete(Connection.class, "test-connection");
    }

    @Before
    public void prepopulateDatabase() {
        final Connector provider = new Connector.Builder().id("test-provider")
                .putProperty("clientId",
                        new ConfigurationProperty.Builder().addTag(Credentials.CLIENT_ID_TAG).build())
                .putProperty("clientSecret",
                        new ConfigurationProperty.Builder().addTag(Credentials.CLIENT_SECRET_TAG).build())
                .putConfiguredProperty("clientId", "a-client-id")
                .putConfiguredProperty("clientSecret", "a-client-secret").build();
        dataManager.create(provider);

        dataManager.create(new Connection.Builder().id("test-connection").connector(provider).build());
    }

    @Test
    public void shouldApplyOAuthPropertiesToNewlyCreatedConnections() {
        final OAuth2CredentialFlowState flowState = new OAuth2CredentialFlowState.Builder()
                .providerId("test-provider").key("key").accessGrant(new AccessGrant("token")).build();

        final HttpHeaders cookies = persistAsCookie(flowState);

        final Connection newConnection = new Connection.Builder().name("Test connection").build();
        final ResponseEntity<Connection> connectionResponse = http(HttpMethod.POST, "/api/v1/connections",
                newConnection, Connection.class, tokenRule.validToken(), cookies, HttpStatus.OK);

        assertThat(connectionResponse.hasBody()).as("Should contain created connection").isTrue();

        final Connection createdConnection = connectionResponse.getBody();
        assertThat(createdConnection.isDerived()).isTrue();
        assertThat(createdConnection.getConfiguredProperties()).containsOnly(entry("accessToken", "token"),
                entry("clientId", "appId"), entry("clientSecret", "appSecret"));
    }

    @Test
    public void shouldInitiateCredentialFlow() throws UnsupportedEncodingException {
        final ResponseEntity<AcquisitionResponse> acquisitionResponse = post(
                "/api/v1/connectors/test-provider/credentials", Collections.singletonMap("returnUrl", "/ui#state"),
                AcquisitionResponse.class, tokenRule.validToken(), HttpStatus.ACCEPTED);

        assertThat(acquisitionResponse.hasBody()).as("Should present a acquisition response in the HTTP body")
                .isTrue();

        final AcquisitionResponse response = acquisitionResponse.getBody();
        assertThat(response.getType()).isEqualTo(Type.OAUTH2);

        final String redirectUrl = response.getRedirectUrl();
        assertThat(redirectUrl).as("Should redirect to Salesforce and containthe correct callback URL")
                .startsWith("https://test/oauth2/authorize?client_id=testClientId&response_type=code&redirect_uri=")
                .contains(encode("/api/v1/credentials/callback", "ASCII"));

        final MultiValueMap<String, String> params = UriComponentsBuilder.fromHttpUrl(redirectUrl).build()
                .getQueryParams();

        final String state = params.getFirst("state");

        assertThat(state).as("state parameter should be set").isNotEmpty();

        final State responseStateInstruction = response.state();
        assertThat(responseStateInstruction).as("acquisition response should contain the state instruction")
                .isNotNull();
        assertThat(responseStateInstruction.persist()).isEqualByComparingTo(State.Persist.COOKIE);
        assertThat(responseStateInstruction.spec()).isNotEmpty();

        final CredentialFlowState credentialFlowState = clientSideState
                .restoreFrom(Cookie.valueOf(responseStateInstruction.spec()), CredentialFlowState.class);

        final CredentialFlowState expected = new OAuth2CredentialFlowState.Builder().key("test-state")
                .providerId("test-provider").build();

        assertThat(credentialFlowState).as("The flow state should be as expected")
                .isEqualToIgnoringGivenFields(expected, "returnUrl");
        final URI returnUrl = credentialFlowState.getReturnUrl();
        assertThat(returnUrl).isNotNull();
        assertThat(returnUrl.isAbsolute()).isTrue();
        assertThat(returnUrl.getPath()).isEqualTo("/ui");
        assertThat(returnUrl.getFragment()).isEqualTo("state");
    }

    @Test
    public void shouldProvideCredentialsApplicableTo() {
        final ResponseEntity<AcquisitionMethod> acquisitionMethodEntity = get(
                "/api/v1/connectors/test-provider/credentials", AcquisitionMethod.class, tokenRule.validToken(),
                HttpStatus.OK);

        assertThat(acquisitionMethodEntity.hasBody()).as("Should present a acquisition method in the HTTP body")
                .isTrue();

        final AcquisitionMethod acquisitionMethod = acquisitionMethodEntity.getBody();

        final AcquisitionMethod salesforce = new AcquisitionMethod.Builder().type(Type.OAUTH2)
                .label("test-provider").icon("test-provider").label("test-provider").description("test-provider")
                .build();

        assertThat(acquisitionMethod).isEqualTo(salesforce);
    }

    @Test
    public void shouldReceiveCallbacksFromResourceProviders() {
        final OAuth2CredentialFlowState flowState = new OAuth2CredentialFlowState.Builder()
                .providerId("test-provider").key(UUID.randomUUID().toString()).returnUrl(URI.create("/ui#state"))
                .build();

        final HttpHeaders cookies = persistAsCookie(flowState);

        final ResponseEntity<Void> callbackResponse = http(HttpMethod.GET,
                "/api/v1/credentials/callback?state=test-state&code=code", null, Void.class, null, cookies,
                HttpStatus.TEMPORARY_REDIRECT);

        assertThat(callbackResponse.getStatusCode()).as("Status should be temporarry redirect (307)")
                .isEqualTo(HttpStatus.TEMPORARY_REDIRECT);
        assertThat(callbackResponse.hasBody()).as("Should not contain HTTP body").isFalse();
        assertThat(callbackResponse.getHeaders().getLocation().toString()).matches(
                "http.?://localhost:[0-9]*/api/v1/ui#%7B%22connectorId%22:%22test-provider%22,%22message%22:%22Successfully%20authorized%20Syndesis's%20access%22,%22status%22:%22SUCCESS%22%7D");

        final List<String> receivedCookies = callbackResponse.getHeaders().get("Set-Cookie");
        assertThat(receivedCookies).hasSize(1);

        final OAuth2CredentialFlowState endingFlowState = clientSideState
                .restoreFrom(Cookie.valueOf(receivedCookies.get(0)), OAuth2CredentialFlowState.class);

        // AccessGrant does not implement equals/hashCode
        assertThat(endingFlowState).isEqualToIgnoringGivenFields(
                new OAuth2CredentialFlowState.Builder().createFrom(flowState).code("code").build(), "accessGrant");
        assertThat(endingFlowState.getAccessGrant()).isEqualToComparingFieldByField(new AccessGrant("token"));
    }

    private HttpHeaders persistAsCookie(final OAuth2CredentialFlowState flowState) {
        final NewCookie cookie = clientSideState.persist(flowState.persistenceKey(), "/", flowState);

        final HttpHeaders cookies = new HttpHeaders();
        cookies.add(HttpHeaders.COOKIE, cookie.toString());
        return cookies;
    }

}