Skip to content

Commit

Permalink
Add support to configure the session cookie programmatically
Browse files Browse the repository at this point in the history
  • Loading branch information
fhanik committed Feb 12, 2016
1 parent f6b7a35 commit cc67be2
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 1 deletion.
@@ -0,0 +1,127 @@
/*
* *****************************************************************************
* 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.web;

import org.springframework.web.context.ServletContextAware;

import javax.servlet.ServletContext;
import javax.servlet.SessionCookieConfig;

import static org.springframework.util.StringUtils.hasText;

public class UaaSessionCookieConfig implements SessionCookieConfig, ServletContextAware {

private String comment;
private String domain;
private int maxAge;
private String path;
private boolean httpOnly;
private String name;
private boolean secure;



@Override
public void setServletContext(ServletContext servletContext) {
SessionCookieConfig config = servletContext.getSessionCookieConfig();
if (hasText(getComment())) {
config.setComment(getComment());
}
if (hasText(getDomain())) {
config.setDomain(getDomain());
}
if (getMaxAge()>Integer.MIN_VALUE) {
config.setMaxAge(getMaxAge());
}
if (getPath()!=null) {
config.setPath(getPath());
}
config.setHttpOnly(isHttpOnly());
config.setSecure(isSecure());
if (hasText(getName())) {
config.setName(getName());
}
}

@Override
public String getName() {
return name;
}

@Override
public void setName(String name) {
this.name = name;
}

@Override
public boolean isSecure() {
return secure;
}

@Override
public void setSecure(boolean secure) {
this.secure = secure;
}

@Override
public String getComment() {
return comment;
}

@Override
public void setComment(String comment) {
this.comment = comment;
}

@Override
public String getDomain() {
return domain;
}

@Override
public void setDomain(String domain) {
this.domain = domain;
}

@Override
public boolean isHttpOnly() {
return httpOnly;
}

@Override
public void setHttpOnly(boolean httpOnly) {
this.httpOnly = httpOnly;
}

@Override
public int getMaxAge() {
return maxAge;
}

@Override
public void setMaxAge(int maxAge) {
this.maxAge = maxAge;
}

@Override
public String getPath() {
return path;
}

@Override
public void setPath(String path) {
this.path = path;
}
}
10 changes: 10 additions & 0 deletions uaa/src/main/webapp/WEB-INF/spring-servlet.xml
Expand Up @@ -31,6 +31,16 @@
<property name="yaml" value="${environmentYamlKey}" />
</bean>

<bean id="sessionCookieConfig" class="org.cloudfoundry.identity.uaa.web.UaaSessionCookieConfig">
<property name="comment" value="${servlet.session-cookie.comment:#{null}}"/>
<property name="domain" value="${servlet.session-cookie.domain:#{null}}"/>
<property name="httpOnly" value="${servlet.session-cookie.http-only:true}"/>
<property name="maxAge" value="${servlet.session-cookie.max-age:#{T(java.lang.Integer).MIN_VALUE}}"/>
<property name="name" value="${servlet.session-cookie.name:#{null}}"/>
<property name="path" value="${servlet.session-cookie.path:#{null}}"/>
<property name="secure" value="${servlet.session-cookie.secure:${require_https:false}}"/>
</bean>

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useSuffixPatternMatch" value="false"/>
Expand Down
Expand Up @@ -43,7 +43,9 @@

import java.io.IOException;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
Expand Down Expand Up @@ -84,6 +86,49 @@ public void logout_and_clear_cookies() {
webDriver.manage().deleteAllCookies();
}

@Test
public void check_JSESSIONID_defaults() throws Exception {
RestTemplate template = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
List<String> cookies = Collections.EMPTY_LIST;
LinkedMultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
requestBody.add("username", testAccounts.getUserName());
requestBody.add("password", testAccounts.getPassword());

headers.set(headers.ACCEPT, MediaType.TEXT_HTML_VALUE);
ResponseEntity<String> loginResponse = template.exchange(baseUrl + "/login",
HttpMethod.GET,
new HttpEntity<>(null, headers),
String.class);

if (loginResponse.getHeaders().containsKey("Set-Cookie")) {
for (String cookie : loginResponse.getHeaders().get("Set-Cookie")) {
headers.add("Cookie", cookie);
}
}
String csrf = IntegrationTestUtils.extractCookieCsrf(loginResponse.getBody());
requestBody.add(CookieBasedCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME, csrf);

headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
loginResponse = template.exchange(baseUrl + "/login.do",
HttpMethod.POST,
new HttpEntity<>(requestBody, headers),
String.class);
cookies = loginResponse.getHeaders().get("Set-Cookie");
assertEquals(2, cookies.size());
headers.clear();
boolean jsessionIdValidated = false;
for (String cookie : loginResponse.getHeaders().get("Set-Cookie")) {
if (cookie.contains("JSESSIONID")) {
jsessionIdValidated = true;
assertTrue(cookie.contains("HttpOnly"));
assertFalse(cookie.contains("Secure"));

}
}
assertTrue("Did not find JSESSIONID", jsessionIdValidated);
}

@Test
public void testSuccessfulLogin() throws Exception {
webDriver.get(baseUrl + "/login");
Expand Down
Expand Up @@ -39,6 +39,7 @@
import org.cloudfoundry.identity.uaa.scim.ScimGroupProvisioning;
import org.cloudfoundry.identity.uaa.security.web.CorsFilter;
import org.cloudfoundry.identity.uaa.util.PredicateMatcher;
import org.cloudfoundry.identity.uaa.web.UaaSessionCookieConfig;
import org.cloudfoundry.identity.uaa.zone.IdentityZone;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneConfiguration;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
Expand Down Expand Up @@ -133,6 +134,7 @@ public void cleanup() throws Exception {
System.clearProperty("spring.profiles.active");
System.clearProperty("uaa.url");
System.clearProperty("login.url");
System.clearProperty("require_https");
if (context != null) {
context.close();
}
Expand All @@ -151,6 +153,17 @@ public void cleanup() throws Exception {
@Test
public void testRootContextDefaults() throws Exception {
context = getServletContext(null, "login.yml","uaa.yml", "file:./src/main/webapp/WEB-INF/spring-servlet.xml");

UaaSessionCookieConfig sessionCookieConfig = context.getBean(UaaSessionCookieConfig.class);
assertNotNull(sessionCookieConfig);
assertNull(sessionCookieConfig.getComment());
assertNull(sessionCookieConfig.getDomain());
assertNull(sessionCookieConfig.getPath());
assertNull(sessionCookieConfig.getName());
assertEquals(Integer.MIN_VALUE, sessionCookieConfig.getMaxAge());
assertTrue(sessionCookieConfig.isHttpOnly());
assertFalse(sessionCookieConfig.isSecure());

assertNotNull(context.getBean("viewResolver", ViewResolver.class));
assertNotNull(context.getBean("resetPasswordController", ResetPasswordController.class));
assertEquals(864000, context.getBean("webSSOprofileConsumer", WebSSOProfileConsumerImpl.class).getMaxAuthenticationAge());
Expand Down Expand Up @@ -266,6 +279,7 @@ public void testRootContextDefaults() throws Exception {

assertTrue(corFilter.getXhrConfiguration().isAllowedCredentials());
assertFalse(corFilter.getDefaultConfiguration().isAllowedCredentials());

}

@Test
Expand All @@ -275,6 +289,16 @@ public void testPropertyValuesWhenSetInYaml() throws Exception {

context = getServletContext(null, "login.yml", "test/bootstrap/bootstrap-test.yml", "file:./src/main/webapp/WEB-INF/spring-servlet.xml");

UaaSessionCookieConfig sessionCookieConfig = context.getBean(UaaSessionCookieConfig.class);
assertNotNull(sessionCookieConfig);
assertEquals("C is for Cookie", sessionCookieConfig.getComment());
assertEquals("sesame.com", sessionCookieConfig.getDomain());
assertEquals("/the/path/to/the/jar", sessionCookieConfig.getPath());
assertEquals("cookiemonster", sessionCookieConfig.getName());
assertEquals(30, sessionCookieConfig.getMaxAge());
assertFalse(sessionCookieConfig.isHttpOnly());
assertTrue(sessionCookieConfig.isSecure());

IdentityZoneProvisioning zoneProvisioning = context.getBean(IdentityZoneProvisioning.class);
IdentityZoneConfiguration zoneConfiguration = zoneProvisioning.retrieve(IdentityZone.getUaa().getId()).getConfig();
assertFalse(zoneConfiguration.getLinks().getSelfService().isSelfServiceLinksEnabled());
Expand Down Expand Up @@ -367,8 +391,12 @@ public void testPropertyValuesWhenSetInYaml() throws Exception {
}

@Test
public void testDefaultInternalHostnamesAndNoDBSettings() throws Exception {
public void testDefaultInternalHostnamesAndNoDBSettings_and_Cookie_isSecure() throws Exception {
try {
//testing to see if session cookie config confirms to this
System.setProperty("require_https","true");


System.setProperty("smtp.host","localhost");
//travis profile script overrides these properties
System.setProperty("database.maxactive", "100");
Expand All @@ -378,6 +406,12 @@ public void testDefaultInternalHostnamesAndNoDBSettings() throws Exception {
System.setProperty("uaa.url", "https://" + uaa + ":555/uaa");
System.setProperty("login.url", "https://" + login + ":555/uaa");
context = getServletContext(null, "login.yml", "uaa.yml", "file:./src/main/webapp/WEB-INF/spring-servlet.xml");

UaaSessionCookieConfig sessionCookieConfig = context.getBean(UaaSessionCookieConfig.class);
assertNotNull(sessionCookieConfig);
assertTrue(sessionCookieConfig.isSecure());


IdentityZoneResolvingFilter filter = context.getBean(IdentityZoneResolvingFilter.class);
Set<String> defaultHostnames = new HashSet<>(Arrays.asList(uaa, login, "localhost"));
assertEquals(filter.getDefaultZoneHostnames(), defaultHostnames);
Expand Down
10 changes: 10 additions & 0 deletions uaa/src/test/resources/test/bootstrap/bootstrap-test.yml
Expand Up @@ -84,3 +84,13 @@ jwt:
refreshTokenValiditySeconds: 7200
accessTokenValiditySeconds: 4800
refreshTokenValiditySeconds: 9600

servlet:
session-cookie:
secure: true
http-only: false
max-age: 30
name: cookiemonster
comment: C is for Cookie
path: /the/path/to/the/jar
domain: sesame.com

0 comments on commit cc67be2

Please sign in to comment.