Getting Started _ Spring Security Architecture
Getting Started _ Spring Security Architecture
Get the
Spring Security Architecture Code
This guide is a primer for Spring Security, offering insight into the design Go To
and basic building blocks of the framework. We cover only the very Repo
basics of application security. However, in doing so, we can clear up
some of the confusion experienced by developers who use Spring
Security. To do this, we take a look at the way security is applied in web
Projects
applications by using filters and, more generally, by using method
annotations. Use this guide when you need a high-level understanding Spring
This guide is not intended as a manual or recipe for solving more than
the most basic problems (there are other sources for those), but it could
be useful for beginners and experts alike. Spring Boot is also often
referenced, because it provides some default behavior for a secure
application, and it can be useful to understand how that fits in with the
overall architecture.
Authentication
COPY
public interface AuthenticationManager {
COPY
public interface AuthenticationProvider {
COPY
@Configuration
public class ApplicationSecurity extends
WebSecurityConfigurerAdapter {
@Autowired
public void initialize(AuthenticationManagerBuilder builder,
DataSource dataSource) {
builder.jdbcAuthentication().dataSource(dataSource).withUser("
dave")
.password("secret").roles("USER");
}
COPY
@Configuration
public class ApplicationSecurity extends
WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
@Override
public void configure(AuthenticationManagerBuilder builder)
{
builder.jdbcAuthentication().dataSource(dataSource).withUser("
dave")
.password("secret").roles("USER");
}
COPY
boolean supports(ConfigAttribute attribute);
Web Security
Spring Security in the web tier (for UIs and HTTP back ends) is based on
Servlet Filters , so it is helpful to first look at the role of Filters
generally. The following picture shows the typical layering of the
handlers for a single HTTP request.
The client sends a request to the application, and the container decides
which filters and which servlet apply to it based on the path of the
request URI. At most, one servlet can handle a single request, but filters
form a chain, so they are ordered. In fact, a filter can veto the rest of the
chain if it wants to handle the request itself. A filter can also modify the
request or the response used in the downstream filters and servlet. The
order of the filter chain is very important, and Spring Boot manages it
through two mechanisms: @Beans of type Filter can have an
@Order or implement Ordered , and they can be part of a
FilterRegistrationBean that itself has an order as part of its API.
Some off-the-shelf filters define their own constants to help signal what
order they like to be in relative to each other (for example, the
SessionRepositoryFilter from Spring Session has a DEFAULT_ORDER
of Integer.MIN_VALUE + 50 , which tells us it likes to be early in the
chain, but it does not rule out other filters coming before it).
There can be multiple filter chains all managed by Spring Security in the
same top level FilterChainProxy and all are unknown to the
container. The Spring Security filter contains a list of filter chains and
dispatches a request to the first chain that matches it. The following
picture shows the dispatch happening based on matching the request
path ( /foo/** matches before /** ). This is very common but not the
only way to match a request. The most important feature of this
dispatch process is that only one chain ever handles a request.
Figure 3. The Spring Security
FilterChainProxy dispatches requests to
Note The fact that all filters internal to Spring Security are
unknown to the container is important, especially in a
Spring Boot application, where, by default, all @Beans
of type Filter are registered automatically with the
container. So if you want to add a custom filter to the
security chain, you need to either not make it be a
@Bean or wrap it in a FilterRegistrationBean that
explicitly disables the container registration.
Creating and Customizing Filter Chains
The default fallback filter chain in a Spring Boot application (the one with
the /** request matcher) has a predefined order of
SecurityProperties.BASIC_AUTH_ORDER . You can switch it off
completely by setting security.basic.enabled=false , or you can use it
as a fallback and define other rules with a lower order. To do the latter,
add a @Bean of type WebSecurityConfigurerAdapter (or
WebSecurityConfigurer ) and decorate the class with @Order , as
follows:
COPY
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends
WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.antMatcher("/match1/**")
...;
}
}
This bean causes Spring Security to add a new filter chain and order it
before the fallback.
Many applications have completely different access rules for one set of
resources compared to another. For example, an application that hosts
a UI and a backing API might support cookie-based authentication with a
redirect to a login page for the UI parts and token-based authentication
with a 401 response to unauthenticated requests for the API parts. Each
set of resources has its own WebSecurityConfigurerAdapter with a
unique order and its own request matcher. If the matching rules
overlap, the earliest ordered filter chain wins.
COPY
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends
WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.antMatcher("/match1/**")
.authorizeRequests()
.antMatchers("/match1/user").hasRole("USER")
.antMatchers("/match1/spam").hasRole("SPAM")
.anyRequest().isAuthenticated();
}
}
If you use the Spring Boot Actuator for management endpoints, you
probably want them to be secure, and, by default, they are. In fact, as
soon as you add the Actuator to a secure application, you get an
additional filter chain that applies only to the actuator endpoints. It is
defined with a request matcher that matches only actuator endpoints
and it has an order of ManagementServerProperties.BASIC_AUTH_ORDER ,
which is 5 fewer than the default SecurityProperties fallback filter, so
it is consulted before the fallback.
Method Security
COPY
@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SampleSecureApplication {
}
@Secured("ROLE_USER")
public String secure() {
return "Hello Security";
}
There are other annotations that you can use on methods to enforce
security constraints, notably @PreAuthorize and @PostAuthorize ,
which let you write expressions containing references to method
parameters and return values, respectively.
COPY
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
assert(authentication.isAuthenticated);
COPY
@RequestMapping("/foo")
public String foo(@AuthenticationPrincipal User user) {
... // do stuff with user
}
COPY
@RequestMapping("/foo")
public String foo(Principal principal) {
Authentication authentication = (Authentication) principal;
User = (User) authentication.getPrincipal();
... // do stuff with user
}
This can sometimes be useful if you need to write code that works when
Spring Security is not in use (you would need to be more defensive
about loading the Authentication class).
COPY
@Configuration
public class ApplicationConfiguration extends
AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
return new
DelegatingSecurityContextExecutorService(Executors.newFixedThr
eadPool(5));
}
Serverless
Batch