WebSessionSecurityContextRepository custom session attribute name
Fixes: gh-4843
This commit is contained in:
parent
b7529be3d0
commit
8d30d6110b
|
@ -16,26 +16,45 @@
|
||||||
package org.springframework.security.web.server.context;
|
package org.springframework.security.web.server.context;
|
||||||
|
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
import reactor.core.publisher.Mono;
|
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
|
* @author Rob Winch
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
public class WebSessionServerSecurityContextRepository
|
public class WebSessionServerSecurityContextRepository
|
||||||
implements ServerSecurityContextRepository {
|
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<Void> save(ServerWebExchange exchange, SecurityContext context) {
|
public Mono<Void> save(ServerWebExchange exchange, SecurityContext context) {
|
||||||
return exchange.getSession()
|
return exchange.getSession()
|
||||||
.doOnNext(session -> {
|
.doOnNext(session -> {
|
||||||
if(context == null) {
|
if(context == null) {
|
||||||
session.getAttributes().remove(SESSION_ATTR);
|
session.getAttributes().remove(this.springSecurityContextAttrName);
|
||||||
} else {
|
} else {
|
||||||
session.getAttributes().put(SESSION_ATTR, context);
|
session.getAttributes().put(this.springSecurityContextAttrName, context);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.flatMap(session -> session.changeSessionId());
|
.flatMap(session -> session.changeSessionId());
|
||||||
|
@ -43,7 +62,7 @@ public class WebSessionServerSecurityContextRepository
|
||||||
|
|
||||||
public Mono<SecurityContext> load(ServerWebExchange exchange) {
|
public Mono<SecurityContext> load(ServerWebExchange exchange) {
|
||||||
return exchange.getSession().flatMap( session -> {
|
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);
|
return context == null ? Mono.empty() : Mono.just(context);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,23 @@ public class WebSessionServerSecurityContextRepositoryTests {
|
||||||
@Test
|
@Test
|
||||||
public void saveAndLoadWhenDefaultsThenFound() {
|
public void saveAndLoadWhenDefaultsThenFound() {
|
||||||
SecurityContext expected = new SecurityContextImpl();
|
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.<SecurityContext>getAttribute(attrName)).isEqualTo(expected);
|
||||||
|
|
||||||
SecurityContext actual = this.repository.load(this.exchange).block();
|
SecurityContext actual = this.repository.load(this.exchange).block();
|
||||||
|
|
||||||
|
@ -49,7 +65,7 @@ public class WebSessionServerSecurityContextRepositoryTests {
|
||||||
@Test
|
@Test
|
||||||
public void saveAndLoadWhenNullThenDeletes() {
|
public void saveAndLoadWhenNullThenDeletes() {
|
||||||
SecurityContext context = new SecurityContextImpl();
|
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();
|
this.repository.save(this.exchange, null).block();
|
||||||
|
|
||||||
SecurityContext actual = this.repository.load(this.exchange).block();
|
SecurityContext actual = this.repository.load(this.exchange).block();
|
||||||
|
|
Loading…
Reference in New Issue