/*******************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2017] 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.login;
import org.cloudfoundry.identity.uaa.TestClassNullifier;
import org.cloudfoundry.identity.uaa.client.ClientMetadata;
import org.cloudfoundry.identity.uaa.client.JdbcClientMetadataProvisioning;
import org.cloudfoundry.identity.uaa.home.BuildInfo;
import org.cloudfoundry.identity.uaa.home.HomeController;
import org.cloudfoundry.identity.uaa.zone.IdentityZone;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneConfiguration;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.cloudfoundry.identity.uaa.zone.Links;
import org.cloudfoundry.identity.uaa.zone.MultitenancyFixture;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = HomeControllerViewTests.ContextConfiguration.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class HomeControllerViewTests extends TestClassNullifier {
private static final String base64EncodedImg = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAXRQTFRFAAAAOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ozk4Ojo6Ojk5NkZMFp/PFqDPNkVKOjo6Ojk5MFhnEq3nEqvjEqzjEbDpMFdlOjo5Ojo6Ojo6Ozg2GZ3TFqXeFKfgF6DVOjo6Ozg2G5jPGZ7ZGKHbGZvROjo6Ojo5M1FfG5vYGp3aM1BdOjo6Ojo6Ojk4KHWeH5PSHpTSKHSbOjk4Ojo6Ojs8IY/QIY/QOjs7Ojo6Ojo6Ozc0JYfJJYjKOzYyOjo5Ozc0KX7AKH/AOzUxOjo5Ojo6Ojo6Ojo6Ojs8LHi6LHi6Ojs7Ojo6Ojo6Ojo6Ojo6Ojo6L3K5L3S7LnW8LnS7Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6NlFvMmWeMmaeNVJwOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojk5Ojk4Ojk4Ojk5Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6FaXeFabfGZ/aGKDaHJnVG5rW////xZzURgAAAHV0Uk5TAAACPaXbAVzltTa4MykoM5HlPY/k5Iw85QnBs2D7+lzAtWD7+lyO6EKem0Ey47Mx2dYvtVZVop5Q2i4qlZAnBiGemh0EDXuddqypcHkShPJwYufmX2rvihSJ+qxlg4JiqP2HPtnW1NjZ2svRVAglGTi91RAXr3/WIQAAAAFiS0dEe0/StfwAAAAJcEhZcwAAAEgAAABIAEbJaz4AAADVSURBVBjTY2BgYGBkYmZhZWVhZmJkAANGNnYODk5ODg52NrAIIyMXBzcPLx8/NwcXIyNYQEBQSFhEVExcQgAiICklLSNbWiYnLy0lCRFQUFRSLq9QUVVUgAgwqqlraFZWaWmrqzFCTNXR1dM3MDQy1tWB2MvIaMJqamZuYWnCCHeIlbWNrZ0VG5QPFLF3cHRydoErcHVz9/D08nb3kYSY6evnHxAYFBwSGhYeAbbWNzIqOiY2Lj4hMckVoiQ5JTUtPSMzKzsH6pfcvPyCwqKc4pJcoAAA2pghnaBVZ0kAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTAtMDhUMTI6NDg6MDkrMDA6MDDsQS6eAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTEwLTA4VDEyOjQ4OjA5KzAwOjAwnRyWIgAAAEZ0RVh0c29mdHdhcmUASW1hZ2VNYWdpY2sgNi43LjgtOSAyMDE0LTA1LTEyIFExNiBodHRwOi8vd3d3LmltYWdlbWFnaWNrLm9yZ9yG7QAAAAAYdEVYdFRodW1iOjpEb2N1bWVudDo6UGFnZXMAMaf/uy8AAAAYdEVYdFRodW1iOjpJbWFnZTo6aGVpZ2h0ADE5Mg8AcoUAAAAXdEVYdFRodW1iOjpJbWFnZTo6V2lkdGgAMTky06whCAAAABl0RVh0VGh1bWI6Ok1pbWV0eXBlAGltYWdlL3BuZz+yVk4AAAAXdEVYdFRodW1iOjpNVGltZQAxNDQ0MzA4NDg5qdC9PQAAAA90RVh0VGh1bWI6OlNpemUAMEJClKI+7AAAAFZ0RVh0VGh1bWI6OlVSSQBmaWxlOi8vL21udGxvZy9mYXZpY29ucy8yMDE1LTEwLTA4LzJiMjljNmYwZWRhZWUzM2ViNmM1Mzg4ODMxMjg3OTg1Lmljby5wbmdoJKG+AAAAAElFTkSuQmCC";
@Autowired
WebApplicationContext webApplicationContext;
@Autowired
MockEnvironment environment;
private MockMvc mockMvc;
private IdentityZoneConfiguration originalConfiguration;
@Before
public void setUp() throws Exception {
SecurityContextHolder.clearContext();
IdentityZoneHolder.clear();
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.build();
originalConfiguration = IdentityZoneHolder.get().getConfig();
IdentityZoneHolder.get().setConfig(new IdentityZoneConfiguration());
}
@After
public void tearDown() {
SecurityContextHolder.clearContext();
IdentityZoneHolder.clear();
IdentityZoneHolder.get().setConfig(originalConfiguration);
}
@Test
public void tilesFromClientMetadataAndTilesConfigShown() throws Exception {
mockMvc.perform(get("/"))
.andExpect(xpath("//*[@id='tile-1'][text()[contains(.,'client-1')]]").exists())
.andExpect(xpath("//*[@class='tile-1']/@href").string("http://app.launch/url"))
.andExpect(xpath("//head/style[2]").string(".tile-1 .tile-icon {background-image: url(\"data:image/png;base64," + base64EncodedImg + "\")}"))
.andExpect(xpath("//*[@id='tile-2'][text()[contains(.,'Client 2 Name')]]").exists())
.andExpect(xpath("//*[@class='tile-2']/@href").string("http://second.url/"))
.andExpect(xpath("//*[@class='tile-3']").doesNotExist());
}
@Test
public void tilesFromClientMetadataAndTilesConfigShown_forOtherZone() throws Exception {
IdentityZone identityZone = MultitenancyFixture.identityZone("test", "test");
IdentityZoneHolder.set(identityZone);
mockMvc.perform(get("/"))
.andExpect(xpath("//*[@id='tile-1'][text()[contains(.,'client-1')]]").exists())
.andExpect(xpath("//*[@class='tile-1']/@href").string("http://app.launch/url"))
.andExpect(xpath("//head/style[1]").string(".tile-1 .tile-icon {background-image: url(\"data:image/png;base64," + base64EncodedImg + "\")}"))
.andExpect(xpath("//*[@id='tile-2'][text()[contains(.,'Client 2 Name')]]").exists())
.andExpect(xpath("//*[@class='tile-2']/@href").string("http://second.url/"))
.andExpect(xpath("//*[@class='tile-3']").doesNotExist());
}
@Test
public void testConfiguredHomePage() throws Exception {
mockMvc.perform(get("/home"))
.andExpect(status().isOk());
String customHomePage = "http://custom.home/page";
IdentityZoneHolder.get().getConfig().getLinks().setHomeRedirect(customHomePage);
mockMvc.perform(get("/home"))
.andExpect(status().is3xxRedirection())
.andExpect(header().string("Location", customHomePage));
IdentityZone zone = MultitenancyFixture.identityZone("zone","zone");
zone.setConfig(new IdentityZoneConfiguration());
IdentityZoneHolder.set(zone);
mockMvc.perform(get("/home"))
.andExpect(status().isOk());
zone.getConfig().getLinks().setHomeRedirect(customHomePage);
mockMvc.perform(get("/home"))
.andExpect(status().is3xxRedirection())
.andExpect(header().string("Location", customHomePage));
}
@Test
public void testConfiguredGlobalHomePage() throws Exception {
HomeController controller = webApplicationContext.getBean(HomeController.class);
//nothing configured
mockMvc.perform(get("/home"))
.andExpect(status().isOk());
String globalHomePage = "http://{zone.subdomain}.custom.home/{zone.id}";
controller.setGlobalLinks(new Links().setHomeRedirect(globalHomePage));
//global home redirect configured
mockMvc.perform(get("/home"))
.andExpect(status().is3xxRedirection())
.andExpect(header().string("Location", "http://.custom.home/uaa"));
//configure home redirect on the default zone
String customHomePage = "http://custom.home/page";
IdentityZoneHolder.get().getConfig().getLinks().setHomeRedirect(customHomePage);
mockMvc.perform(get("/home"))
.andExpect(status().is3xxRedirection())
.andExpect(header().string("Location", customHomePage));
//create a new zone, no config, inherits the global redirect
IdentityZone zone = MultitenancyFixture.identityZone("zoneId","zonesubdomain");
zone.setConfig(new IdentityZoneConfiguration());
IdentityZoneHolder.set(zone);
mockMvc.perform(get("/home"))
.andExpect(status().is3xxRedirection())
.andExpect(header().string("Location", "http://zonesubdomain.custom.home/zoneId"));
//zone configures its own home redirect
zone.getConfig().getLinks().setHomeRedirect(customHomePage);
mockMvc.perform(get("/home"))
.andExpect(status().is3xxRedirection())
.andExpect(header().string("Location", customHomePage));
}
@Configuration
@EnableWebMvc
@Import(ThymeleafConfig.class)
static class ContextConfiguration extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Bean
BuildInfo buildInfo() {
return new BuildInfo();
}
@Bean
JdbcClientMetadataProvisioning clientMetadataProvisioning() throws MalformedURLException {
ClientMetadata clientMetadata1 = new ClientMetadata();
clientMetadata1.setClientId("client-1");
clientMetadata1.setShowOnHomePage(true);
clientMetadata1.setAppLaunchUrl(new URL("http://app.launch/url"));
clientMetadata1.setAppIcon(base64EncodedImg);
ClientMetadata clientMetadata2 = new ClientMetadata();
clientMetadata2.setClientId("client-2");
clientMetadata2.setShowOnHomePage(true);
clientMetadata2.setAppLaunchUrl(new URL("http://second.url/"));
clientMetadata2.setAppIcon("base64-encoded-img");
clientMetadata2.setClientName("Client 2 Name");
ClientMetadata clientMetadataDoesNotExist = new ClientMetadata();
clientMetadataDoesNotExist.setClientId("client-3");
clientMetadataDoesNotExist.setShowOnHomePage(false);
List<ClientMetadata> clientMetadataList = new ArrayList<>();
clientMetadataList.add(clientMetadata1);
clientMetadataList.add(clientMetadata2);
clientMetadataList.add(clientMetadataDoesNotExist);
JdbcClientMetadataProvisioning clientMetadata = mock(JdbcClientMetadataProvisioning.class);
when(clientMetadata.retrieveAll()).thenReturn(clientMetadataList);
return clientMetadata;
}
@Bean
MockEnvironment environment() {
return new MockEnvironment();
}
@Bean
HomeController homeController(MockEnvironment environment) {
HomeController homeController = new HomeController(environment);
homeController.setUaaBaseUrl("http://uaa.example.com");
return homeController;
}
}
}