org.cloudfoundry.identity.uaa.integration.feature.InvitationsIT.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.identity.uaa.integration.feature.InvitationsIT.java

Source

/*******************************************************************************
 *     Cloud Foundry
 *     Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved.
 *
 *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
 *     You may not use this product except in compliance with the License.
 *
 *     This product includes a number of subcomponents with
 *     separate copyright notices and license terms. Your use of these
 *     subcomponents is subject to the terms and conditions of the
 *     subcomponent's license, as noted in the LICENSE file.
 *******************************************************************************/
package org.cloudfoundry.identity.uaa.integration.feature;

import com.dumbster.smtp.SimpleSmtpServer;
import org.cloudfoundry.identity.uaa.ServerRunning;
import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils;
import org.cloudfoundry.identity.uaa.integration.util.ScreenshotOnFail;
import org.cloudfoundry.identity.uaa.invitations.InvitationsRequest;
import org.cloudfoundry.identity.uaa.invitations.InvitationsResponse;
import org.cloudfoundry.identity.uaa.scim.ScimUser;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.client.test.TestAccounts;
import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.client.RestTemplate;

import java.net.URL;
import java.security.SecureRandom;
import java.sql.Timestamp;
import java.util.concurrent.TimeUnit;

import static org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils.getZoneAdminToken;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.MediaType.APPLICATION_JSON;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DefaultIntegrationTestConfig.class)
public class InvitationsIT {

    @Autowired
    TestAccounts testAccounts;

    @Autowired
    @Rule
    public IntegrationTestRule integrationTestRule;

    @Rule
    public ScreenshotOnFail screenShootRule = new ScreenshotOnFail();

    @Autowired
    WebDriver webDriver;

    @Autowired
    SimpleSmtpServer simpleSmtpServer;

    @Autowired
    TestClient testClient;

    @Value("${integration.test.uaa_url}")
    String uaaUrl;

    @Value("${integration.test.base_url}")
    String baseUrl;

    @Value("${integration.test.app_url}")
    String appUrl;

    ServerRunning serverRunning = ServerRunning.isRunning();

    private String scimToken;
    private String loginToken;

    @Before
    public void setup() throws Exception {
        scimToken = testClient.getOAuthAccessToken("admin", "adminsecret", "client_credentials",
                "scim.read,scim.write,clients.admin");
        loginToken = testClient.getOAuthAccessToken("login", "loginsecret", "client_credentials", "oauth.login");
        screenShootRule.setWebDriver(webDriver);
    }

    @Before
    @After
    public void logout_and_clear_cookies() {
        try {
            webDriver.get(baseUrl + "/logout.do");
        } catch (org.openqa.selenium.TimeoutException x) {
            //try again - this should not be happening - 20 second timeouts
            webDriver.get(baseUrl + "/logout.do");
        }
        webDriver.get(appUrl + "/j_spring_security_logout");
        webDriver.get("http://simplesamlphp.cfapps.io/module.php/core/authenticate.php?as=example-userpass&logout");
        webDriver.manage().deleteAllCookies();
    }

    @Test
    public void testInviteUserWithClientRedirect() throws Exception {
        String userEmail = "user-" + new RandomValueStringGenerator().generate() + "@example.com";
        //user doesn't exist
        performInviteUser(userEmail, false);
        //user exist
        performInviteUser(userEmail, true);
    }

    public void performInviteUser(String email, boolean isVerified) throws Exception {
        webDriver.get(baseUrl + "/logout.do");
        String code = createInvitation(email, email, "http://localhost:8080/app/", OriginKeys.UAA);
        String invitedUserId = IntegrationTestUtils.getUserIdByField(scimToken, baseUrl, OriginKeys.UAA, "email",
                email);
        if (isVerified) {
            ScimUser user = IntegrationTestUtils.getUser(scimToken, baseUrl, invitedUserId);
            user.setVerified(true);
            IntegrationTestUtils.updateUser(scimToken, baseUrl, user);
        }
        String currentUserId = null;
        try {
            currentUserId = IntegrationTestUtils.getUserId(scimToken, baseUrl, OriginKeys.UAA, email);
        } catch (RuntimeException x) {
        }
        assertEquals(invitedUserId, currentUserId);

        webDriver.get(baseUrl + "/invitations/accept?code=" + code);
        if (!isVerified) {
            assertEquals("Create your account", webDriver.findElement(By.tagName("h1")).getText());
            webDriver.findElement(By.name("password")).sendKeys("secr3T");
            webDriver.findElement(By.name("password_confirmation")).sendKeys("secr3T");
            webDriver.findElement(By.xpath("//input[@value='Create account']")).click();
            Assert.assertThat(webDriver.findElement(By.cssSelector("h1")).getText(),
                    containsString("Application Authorization"));
        } else {
            //redirect to the home page to login
            Assert.assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), containsString("Welcome!"));
        }
        String acceptedUserId = IntegrationTestUtils.getUserId(scimToken, baseUrl, OriginKeys.UAA, email);
        if (currentUserId == null) {
            assertEquals(invitedUserId, acceptedUserId);
        } else {
            assertEquals(currentUserId, acceptedUserId);
        }
    }

    @Test
    public void acceptInvitation_for_samlUser() throws Exception {
        webDriver.get(baseUrl + "/logout.do");
        String email = "testinvite@test.org";
        String code = createInvitation(email, email, "http://localhost:8080/app/", "simplesamlphp");

        String invitedUserId = IntegrationTestUtils.getUserIdByField(scimToken, baseUrl, "simplesamlphp", "email",
                email);
        IntegrationTestUtils.createIdentityProvider("simplesamlphp", true, baseUrl, serverRunning);

        webDriver.get(baseUrl + "/invitations/accept?code=" + code);
        webDriver.findElement(By.xpath("//h2[contains(text(), 'Enter your username and password')]"));
        webDriver.findElement(By.name("username")).clear();
        webDriver.findElement(By.name("username")).sendKeys("user_only_for_invitations_test");
        webDriver.findElement(By.name("password")).sendKeys("saml");
        WebElement loginButton = webDriver.findElement(By.xpath("//input[@value='Login']"));
        loginButton.click();
        //wait until UAA page has loaded
        new WebDriverWait(webDriver, 45)
                .until(ExpectedConditions.presenceOfElementLocated(By.id("application_authorization")));
        String acceptedUsername = IntegrationTestUtils.getUsernameById(scimToken, baseUrl, invitedUserId);
        //webdriver follows redirects so we should be on the UAA authorization page
        assertEquals("user_only_for_invitations_test", acceptedUsername);
    }

    @Test
    public void testInsecurePasswordDisplaysErrorMessage() throws Exception {
        String code = createInvitation();
        webDriver.get(baseUrl + "/invitations/accept?code=" + code);
        assertEquals("Create your account", webDriver.findElement(By.tagName("h1")).getText());

        String newPassword = new RandomValueStringGenerator(260).generate();
        webDriver.findElement(By.name("password")).sendKeys(newPassword);
        webDriver.findElement(By.name("password_confirmation")).sendKeys(newPassword);

        webDriver.findElement(By.xpath("//input[@value='Create account']")).click();
        assertThat(webDriver.findElement(By.cssSelector(".alert-error")).getText(),
                containsString("Password must be no more than 255 characters in length."));
    }

    @Test
    public void invitedOIDCUserVerified() throws Exception {
        BaseClientDetails clientDetails = new BaseClientDetails("invite-client", null, null, "client_credentials",
                "scim.invite");
        clientDetails.setClientSecret("invite-client-secret");
        testClient.createClient(scimToken, clientDetails);
        String inviteToken = testClient.getOAuthAccessToken("invite-client", "invite-client-secret",
                "client_credentials", "scim.invite");
        IntegrationTestUtils.createOidcIdentityProvider("oidc-invite-provider", "puppy-invite", baseUrl);

        RestTemplate uaaTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Bearer " + inviteToken);
        headers.setContentType(APPLICATION_JSON);
        InvitationsRequest body = new InvitationsRequest();
        String[] emailList = new String[] { "marissa@test.org" };
        body.setEmails(emailList);
        HttpEntity<InvitationsRequest> request = new HttpEntity<>(body, headers);
        ResponseEntity<InvitationsResponse> response = uaaTemplate.exchange(
                uaaUrl + "/invite_users?client_id=app&redirect_uri=" + appUrl, POST, request,
                InvitationsResponse.class);
        assertThat(response.getStatusCode(), is(HttpStatus.OK));

        String userId = response.getBody().getNewInvites().get(0).getUserId();
        URL inviteLink = response.getBody().getNewInvites().get(0).getInviteLink();

        webDriver.get(inviteLink.toString());
        webDriver.findElement(By.xpath("//h1[contains(text(), 'Welcome')]"));
        webDriver.findElement(By.name("username")).clear();
        webDriver.findElement(By.name("username")).sendKeys("marissa");
        webDriver.findElement(By.name("password")).sendKeys("koala");
        webDriver.findElement(By.xpath("//input[@value='Sign in']")).click();

        ScimUser user = IntegrationTestUtils.getUser(scimToken, baseUrl, userId);
        assertTrue(user.isVerified());

        webDriver.get("https://oidc10.identity.cf-app.com/logout.do");
        IntegrationTestUtils.deleteProvider(getZoneAdminToken(baseUrl, serverRunning), baseUrl, "uaa",
                "puppy-invite");
    }

    private String createInvitation() {
        String userEmail = "user" + new SecureRandom().nextInt() + "@example.com";
        return createInvitation(userEmail, userEmail, "http://localhost:8080/app/", OriginKeys.UAA);
    }

    private String createInvitation(String username, String userEmail, String redirectUri, String origin) {
        return createInvitation(baseUrl, uaaUrl, username, userEmail, origin, redirectUri, loginToken, scimToken);
    }

    public static String createInvitation(String baseUrl, String uaaUrl, String username, String userEmail,
            String origin, String redirectUri, String loginToken, String scimToken) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Bearer " + scimToken);
        RestTemplate uaaTemplate = new RestTemplate();
        ScimUser scimUser = new ScimUser();
        scimUser.setUserName(username);
        scimUser.setPrimaryEmail(userEmail);
        scimUser.setOrigin(origin);
        scimUser.setVerified(false);

        String userId = null;
        try {
            userId = IntegrationTestUtils.getUserIdByField(scimToken, baseUrl, origin, "email", userEmail);
            scimUser = IntegrationTestUtils.getUser(scimToken, baseUrl, userId);
        } catch (RuntimeException x) {
        }
        if (userId == null) {
            HttpEntity<ScimUser> request = new HttpEntity<>(scimUser, headers);
            ResponseEntity<ScimUser> response = uaaTemplate.exchange(uaaUrl + "/Users", POST, request,
                    ScimUser.class);
            if (response.getStatusCode().value() != HttpStatus.CREATED.value()) {
                throw new IllegalStateException("Unable to create test user:" + scimUser);
            }
            userId = response.getBody().getId();
        } else {
            scimUser.setVerified(false);
            IntegrationTestUtils.updateUser(scimToken, uaaUrl, scimUser);
        }

        HttpHeaders invitationHeaders = new HttpHeaders();
        invitationHeaders.add("Authorization", "Bearer " + loginToken);

        Timestamp expiry = new Timestamp(System.currentTimeMillis()
                + TimeUnit.MILLISECONDS.convert(System.currentTimeMillis() + 24 * 3600, TimeUnit.MILLISECONDS));
        ExpiringCode expiringCode = new ExpiringCode(
                null, expiry, "{\"origin\":\"" + origin + "\", \"client_id\":\"app\", \"redirect_uri\":\""
                        + redirectUri + "\", \"user_id\":\"" + userId + "\", \"email\":\"" + userEmail + "\"}",
                null);
        HttpEntity<ExpiringCode> expiringCodeRequest = new HttpEntity<>(expiringCode, invitationHeaders);
        ResponseEntity<ExpiringCode> expiringCodeResponse = uaaTemplate.exchange(uaaUrl + "/Codes", POST,
                expiringCodeRequest, ExpiringCode.class);
        expiringCode = expiringCodeResponse.getBody();
        return expiringCode.getCode();
    }
}