Use SecurityContextHolderStrategy for Taglibs

Issue gh-11060
This commit is contained in:
Josh Cummings
2022-06-21 16:32:01 -06:00
parent 5de975f4a2
commit 237a31c69b
6 changed files with 134 additions and 11 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,11 +32,15 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -74,6 +78,9 @@ public class AbstractAuthorizeTagTests {
@Test
public void privilegeEvaluatorFromRequest() throws IOException {
WebApplicationContext wac = mock(WebApplicationContext.class);
this.servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
given(wac.getBeanNamesForType(SecurityContextHolderStrategy.class)).willReturn(new String[0]);
String uri = "/something";
WebInvocationPrivilegeEvaluator expected = mock(WebInvocationPrivilegeEvaluator.class);
this.tag.setUrl(uri);
@@ -82,6 +89,24 @@ public class AbstractAuthorizeTagTests {
verify(expected).isAllowed(eq(""), eq(uri), eq("GET"), any());
}
@Test
public void privilegeEvaluatorFromRequestUsesSecurityContextHolderStrategy() throws IOException {
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
given(strategy.getContext()).willReturn(new SecurityContextImpl(
new TestingAuthenticationToken("user", "password", AuthorityUtils.NO_AUTHORITIES)));
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBean(SecurityContextHolderStrategy.class, () -> strategy);
wac.refresh();
this.servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
String uri = "/something";
WebInvocationPrivilegeEvaluator expected = mock(WebInvocationPrivilegeEvaluator.class);
this.tag.setUrl(uri);
this.request.setAttribute(WebAttributes.WEB_INVOCATION_PRIVILEGE_EVALUATOR_ATTRIBUTE, expected);
this.tag.authorizeUsingUrlCheck();
verify(expected).isAllowed(eq(""), eq(uri), eq("GET"), any());
verify(strategy).getContext();
}
@Test
public void privilegeEvaluatorFromChildContext() throws IOException {
String uri = "/something";
@@ -90,6 +115,7 @@ public class AbstractAuthorizeTagTests {
WebApplicationContext wac = mock(WebApplicationContext.class);
given(wac.getBeansOfType(WebInvocationPrivilegeEvaluator.class))
.willReturn(Collections.singletonMap("wipe", expected));
given(wac.getBeanNamesForType(SecurityContextHolderStrategy.class)).willReturn(new String[0]);
this.servletContext.setAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher", wac);
this.tag.authorizeUsingUrlCheck();
verify(expected).isAllowed(eq(""), eq(uri), eq("GET"), any());
@@ -104,6 +130,7 @@ public class AbstractAuthorizeTagTests {
WebApplicationContext wac = mock(WebApplicationContext.class);
given(wac.getBeansOfType(SecurityExpressionHandler.class))
.willReturn(Collections.<String, SecurityExpressionHandler>singletonMap("wipe", expected));
given(wac.getBeanNamesForType(SecurityContextHolderStrategy.class)).willReturn(new String[0]);
this.servletContext.setAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher", wac);
assertThat(this.tag.authorize()).isTrue();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,10 @@ import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@@ -68,6 +71,7 @@ public class AccessControlListTagTests {
Map beanMap = new HashMap();
beanMap.put("pe", this.pe);
given(ctx.getBeansOfType(PermissionEvaluator.class)).willReturn(beanMap);
given(ctx.getBeanNamesForType(SecurityContextHolderStrategy.class)).willReturn(new String[0]);
MockServletContext servletCtx = new MockServletContext();
servletCtx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
this.pageContext = new MockPageContext(servletCtx, new MockHttpServletRequest(), new MockHttpServletResponse());
@@ -92,6 +96,30 @@ public class AccessControlListTagTests {
assertThat((Boolean) this.pageContext.getAttribute("allowed")).isTrue();
}
@Test
public void securityContextHolderStrategyIsUsedIfConfigured() throws Exception {
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
given(strategy.getContext()).willReturn(new SecurityContextImpl(this.bob));
GenericWebApplicationContext context = new GenericWebApplicationContext();
context.registerBean(SecurityContextHolderStrategy.class, () -> strategy);
context.registerBean(PermissionEvaluator.class, () -> this.pe);
context.refresh();
MockServletContext servletCtx = new MockServletContext();
servletCtx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
this.pageContext = new MockPageContext(servletCtx, new MockHttpServletRequest(), new MockHttpServletResponse());
this.tag.setPageContext(this.pageContext);
Object domainObject = new Object();
given(this.pe.hasPermission(this.bob, domainObject, "READ")).willReturn(true);
this.tag.setDomainObject(domainObject);
this.tag.setHasPermission("READ");
this.tag.setVar("allowed");
assertThat(this.tag.getDomainObject()).isSameAs(domainObject);
assertThat(this.tag.getHasPermission()).isEqualTo("READ");
assertThat(this.tag.doStartTag()).isEqualTo(Tag.EVAL_BODY_INCLUDE);
assertThat((Boolean) this.pageContext.getAttribute("allowed")).isTrue();
verify(strategy).getContext();
}
@Test
public void childContext() throws Exception {
ServletContext servletContext = this.pageContext.getServletContext();

View File

@@ -22,14 +22,23 @@ import javax.servlet.jsp.tagext.Tag;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockPageContext;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests {@link AuthenticationTag}.
@@ -131,6 +140,24 @@ public class AuthenticationTagTests {
assertThat(this.authenticationTag.getLastMessage()).isEqualTo("<>& ");
}
@Test
public void setSecurityContextHolderStrategyThenUses() throws Exception {
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
given(strategy.getContext()).willReturn(new SecurityContextImpl(
new TestingAuthenticationToken("rodAsString", "koala", AuthorityUtils.NO_AUTHORITIES)));
MockServletContext servletContext = new MockServletContext();
GenericWebApplicationContext applicationContext = new GenericWebApplicationContext();
applicationContext.registerBean(SecurityContextHolderStrategy.class, () -> strategy);
applicationContext.refresh();
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, applicationContext);
this.authenticationTag.setPageContext(new MockPageContext(servletContext));
this.authenticationTag.setProperty("principal");
assertThat(this.authenticationTag.doStartTag()).isEqualTo(Tag.SKIP_BODY);
assertThat(this.authenticationTag.doEndTag()).isEqualTo(Tag.EVAL_PAGE);
assertThat(this.authenticationTag.getLastMessage()).isEqualTo("rodAsString");
verify(strategy).getContext();
}
private class MyAuthenticationTag extends AuthenticationTag {
String lastMessage = null;