From 8d30d6110bdadd6bf2d4dfe5277e613391b5a662 Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Thu, 16 Nov 2017 13:20:21 -0600 Subject: [PATCH] WebSessionSecurityContextRepository custom session attribute name Fixes: gh-4843 --- ...essionServerSecurityContextRepository.java | 29 +++++++++++++++---- ...nServerSecurityContextRepositoryTests.java | 20 +++++++++++-- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/server/context/WebSessionServerSecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/server/context/WebSessionServerSecurityContextRepository.java index fa94c076b9..551be8c2a0 100644 --- a/web/src/main/java/org/springframework/security/web/server/context/WebSessionServerSecurityContextRepository.java +++ b/web/src/main/java/org/springframework/security/web/server/context/WebSessionServerSecurityContextRepository.java @@ -16,26 +16,45 @@ package org.springframework.security.web.server.context; import org.springframework.security.core.context.SecurityContext; +import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; /** - * + * Stores the {@link SecurityContext} in the + * {@link org.springframework.web.server.WebSession}. When a {@link SecurityContext} is + * saved, the session id is changed to prevent session fixation attacks. * @author Rob Winch * @since 5.0 */ public class WebSessionServerSecurityContextRepository implements ServerSecurityContextRepository { - final String SESSION_ATTR = "USER"; + + /** + * The default session attribute name to save and load the {@link SecurityContext} + */ + public static final String DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME = "SPRING_SECURITY_CONTEXT"; + + private String springSecurityContextAttrName = DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME; + + /** + * Sets the session attribute name used to save and load the {@link SecurityContext} + * @param springSecurityContextAttrName the session attribute name to use to save and + * load the {@link SecurityContext} + */ + public void setSpringSecurityContextAttrName(String springSecurityContextAttrName) { + Assert.hasText(springSecurityContextAttrName, "springSecurityContextAttrName cannot be null or empty"); + this.springSecurityContextAttrName = springSecurityContextAttrName; + } public Mono save(ServerWebExchange exchange, SecurityContext context) { return exchange.getSession() .doOnNext(session -> { if(context == null) { - session.getAttributes().remove(SESSION_ATTR); + session.getAttributes().remove(this.springSecurityContextAttrName); } else { - session.getAttributes().put(SESSION_ATTR, context); + session.getAttributes().put(this.springSecurityContextAttrName, context); } }) .flatMap(session -> session.changeSessionId()); @@ -43,7 +62,7 @@ public class WebSessionServerSecurityContextRepository public Mono load(ServerWebExchange exchange) { return exchange.getSession().flatMap( session -> { - SecurityContext context = (SecurityContext) session.getAttributes().get(SESSION_ATTR); + SecurityContext context = (SecurityContext) session.getAttributes().get(this.springSecurityContextAttrName); return context == null ? Mono.empty() : Mono.just(context); }); } diff --git a/web/src/test/java/org/springframework/security/web/server/context/WebSessionServerSecurityContextRepositoryTests.java b/web/src/test/java/org/springframework/security/web/server/context/WebSessionServerSecurityContextRepositoryTests.java index ac8f45b116..9101ab9995 100644 --- a/web/src/test/java/org/springframework/security/web/server/context/WebSessionServerSecurityContextRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/server/context/WebSessionServerSecurityContextRepositoryTests.java @@ -39,7 +39,23 @@ public class WebSessionServerSecurityContextRepositoryTests { @Test public void saveAndLoadWhenDefaultsThenFound() { SecurityContext expected = new SecurityContextImpl(); - this.repository.save(this.exchange, new SecurityContextImpl()).block(); + this.repository.save(this.exchange, expected).block(); + + SecurityContext actual = this.repository.load(this.exchange).block(); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void saveAndLoadWhenCustomAttributeThenFound() { + String attrName = "attr"; + this.repository.setSpringSecurityContextAttrName(attrName); + SecurityContext expected = new SecurityContextImpl(); + + this.repository.save(this.exchange, expected).block(); + + WebSession session = this.exchange.getSession().block(); + assertThat(session.getAttribute(attrName)).isEqualTo(expected); SecurityContext actual = this.repository.load(this.exchange).block(); @@ -49,7 +65,7 @@ public class WebSessionServerSecurityContextRepositoryTests { @Test public void saveAndLoadWhenNullThenDeletes() { SecurityContext context = new SecurityContextImpl(); - this.repository.save(this.exchange, new SecurityContextImpl()).block(); + this.repository.save(this.exchange, context).block(); this.repository.save(this.exchange, null).block(); SecurityContext actual = this.repository.load(this.exchange).block();