0% found this document useful (0 votes)
15 views65 pages

Spring Security. Authentication and Authorization

The document provides an overview of Spring Security, a framework for securing Spring-based applications through authentication and authorization processes. It covers key concepts such as the authentication process, CSRF protection, and various configuration methods including in-memory and JDBC authentication. Additionally, it discusses the UserDetails interface and password encoding mechanisms, emphasizing the importance of security in web applications.

Uploaded by

eramchegyt
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views65 pages

Spring Security. Authentication and Authorization

The document provides an overview of Spring Security, a framework for securing Spring-based applications through authentication and authorization processes. It covers key concepts such as the authentication process, CSRF protection, and various configuration methods including in-memory and JDBC authentication. Additionally, it discusses the UserDetails interface and password encoding mechanisms, emphasizing the importance of security in web applications.

Uploaded by

eramchegyt
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 65

SPRING

SECURITY
AUTHENTICATION AND
AUTHORIZATION PROCESS

Mykola Demchyna
Agenda

 Introduction
 Authentication Process
 Authorization Process
 Authorization Process

 References and Resources


INTRODUCTION
Spring Security Intro

• The Spring Security is a security framework that provides declarative


security for your Spring-based applications.
• Spring Security provides a complex security solution, handling authentication
and authorization at both the web request level and at the method
invocation level.
• Spring Security got its start as Acegi Security which was a powerful security
framework, but it had one big turn-off: it required a lot of XML configuration.
• With version 2.0, Acegi Security became Spring Security 2.0 and introduced a
new security-specific XML namespace for configuring security in Spring.
• Spring Security 3.0 added SpEL to the mix, simplifying security configuration
even more.
Spring Security Maven dependencies
• A minimal Spring Security Maven set of dependencies typically looks like the
following:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>

• If you are using additional features like LDAP, OpenID, etc. you will
need to include additional dependencies.
Authentication vs. Authorization

• Authentication refers to proving the correct


identity.
• Authorization refers to allowing a certain
action.
Spring Security Authentication
Process
• One of the fundamental ways
to secure a resource is to
make sure that the caller
is who they claim to be.
• This process of checking
credentials and making sure
that they are genuine is called
authentication.
• The following diagram shows
the fundamental process
Spring Security uses to
address this core security
requirement.
AUTHENTICATION
PROCESS
Default Security Setup

• By default Spring Boot include the SecurityAutoConfiguration class that


containing the initial security configuration.
• We can use some predefined properties, such as:

• If we don't configure the password using the predefined property


spring.security.user.password and start the application, we'll notice that a
default password is randomly generated and printed in the console log.
Default Security Setup

• To discard the security auto-configuration and add our own configuration, we


need to exclude the SecurityAutoConfiguration class.

@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class Application implements CommandLineRunner {

public static void main(String[] args) {


SpringApplication.run(Application.class, args);
}
}

• Or by adding some configuration into the application.properties file:

spring.autoconfigure.exclude=org.springframework.boot.autoconf
igure
.security.SecurityAutoConfiguration
Minimal Java Configuration

• If we want a more flexible configuration, with multiple users and roles, the
first step is to create Spring Security configuration class that creates a
servlet Filter (known as the springSecurityFilterChain)

@Configuration
@EnableWebSecurity
public class WebSecurityConfigurer {
. . .
}

• To enable Spring Security integration with Spring MVC add the


@EnableWebSecurity annotation to your configuration.
Cross Site Request Forgery (CSRF)

• Cross Site Request Forgery, also known as one-click attack or session


riding and abbreviated as CSRF or XSRF, is a type of malicious exploit of a
website where unauthorized commands are transmitted from a user that the
web application trusts.
Cross Site Request Forgery (CSRF)

• Spring provides comprehensive support for protecting against Cross Site


Request Forgery (CSRF) attacks.
• Spring Security exposed the CSRF Token as an HttpServletRequest attribute
named _csrf.
• For example, the following will allow accessing the CSRF Token in a JSP:

<p>Header name: ${_csrf.headerName}</p>


<p>Parameter name: ${_csrf.parameterName}</p>
<p>CSRF Token: ${_csrf.token}</p>
Cross Site Request Forgery (CSRF)

• CSRF protection is enabled by default


• However, it is simple to disable CSRF protection if it makes sense for your
application.
@Override
protected void configure(HttpSecurity http) throws Exception {

...

http.csrf().disable();
}
Form Login Java Configuration
@Configuration
• When we want to @EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
provide their own login
page, we can customize @Override
protected void configure(HttpSecurity http) throws Exception {
WebSecurityConfigurer http.authorizeRequests()
Adapter and then .anyRequest().authenticated()
override the configure .and()
.formLogin()
method. .loginPage("/login-form")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/home")
.failureUrl("/login-form?error=true")
Log In process .permitAll()
.and()
.logout()
.logoutUrl("/perform-logout")
.logoutSuccessUrl("/login-form")
Log Out .deleteCookies("JSESSIONID")
process }
}
Form Login Java Configuration

• Previous configuration means that all we need to do is create a login-


page.html file and LoginController class with the following contents:

<h2>LogIn Page</h2>
<div th:if="${param.error}">Invalid username and password.</div>
<div th:if="${param.logout}">You have been logged out.</div>
<form th:action="@{/login}" method="POST">
<label>Username:</label >
<input type="text" name="username" /><br>
<label >Password:</label > @Controller
<input type="password" name="password" /><br> public class LoginController {
<input type="submit" value="LogIn" /> @GetMapping("/login-form")
</form> public String login() {
return "login-page";
}
}
The HttpSecurity class

• The HttpSecurity class allows configuring web based security for specific http
requests.
Method Short description
Allows restricting access based upon the HttpServletRequest
authorizeRequests()
using
httpBasic() Configures HTTP Basic authentication.
formLogin() Specifies to support form based authentication.
logout() Provides logout support.
rememberMe() Allows configuring of Remember Me authentication.
anonymous() Allows configuring how an anonymous user is represented.
csrf() Adds CSRF support.
Allows configuring the HttpSecurity to only be invoked when
antMatcher(String antPattern)
matching the provided ant pattern.
Allows configuring the HttpSecurity to only be invoked when
regexMatcher(String pattern)
matching the provided regex pattern.
Allows configuring the HttpSecurity to only be invoked
mvcMatcher(String mvcPattern)
when matching the provided Spring MVC pattern.
The HttpSecurity class
Method Short description
addFilter(Filter filter) Adds a Filter that must be an instance of or extend
one of the Filters provided within the Security
framework.
addFilterBefore(Filter filter, Class Allows adding a Filter before one of the known Filter
beforeFilter) classes.
addFilterAfter(Filter filter, Class Allows adding a Filter after one of the known Filter
afterFilter) classes.
addFilterAt(Filter filter, Class atFilter) Adds the Filter at the location of the specified Filter
class.
exceptionHandling() Allows configuring exception handling.
authenticationProvider(AuthenticationProvider Allows adding an additional AuthenticationProvider to
provider) be used
userDetailsService(UserDetailsService service) Allows adding an additional UserDetailsService to be
used
sessionManagement() Allows configuring of Session Management.
cors() Adds a CorsFilter to be used.
headers() Adds the Security headers to the response.
Handling LogIn process

• The most basic configuration defaults to automatically generating a login page


at the URL "/login", redirecting to "/login?error" for authentication failure.
• To override this behavioral you can use methods from FormLoginConfigurer
and AbstractAuthenticationFilterConfigurer classes.
Method Short description
loginPage(String loginPage) Specifies the URL to send users to if login is required.
loginProcessingUrl(String url) Specifies the URL to validate the credentials (default is
"/login").
failureUrl(String url) The URL to send users if authentication fails (default is "/login?
error").
defaultSuccessUrl(String url) Specifies where users will go after authenticating successfully if
they have not visited a secured page prior to authenticating.
successHandler(AuthenticationSuccessHa
Specifies the AuthenticationSuccessHandler to be used.
ndler handler)
failureHandler(AuthenticationFailureHa Specifies the AuthenticationFailureHandler to use when
ndler handler) authentication fails.
Handling LogOut process

• When using the WebSecurityConfigurerAdapter, logout capabilities are


automatically applied.

• The default is that accessing the URL "/logout" will log the user out by*:
• Invalidating the HTTP Session.
• Cleaning up any RememberMe authentication that was configured.
• Clearing the SecurityContextHolder.
• Redirect to "/login?logout" .

• However, you also have various options to further customize your logout
requirements.
* If CSRF protection is enabled (default), then the request must also be a POST.
Handling LogOut process

• To override standard LogOut process behavioral you can use methods from
LogoutConfigurer class.
Method Short description
The URL that triggers log out to occur (default is
logoutUrl(String url)
"/logout").
logoutSuccessUrl(String url) The URL to redirect to after logout has occurred.
logoutSuccessHandler(LogoutSuccessHandle
Sets the LogoutSuccessHandler to use.
r handler)
Configures SecurityContextLogoutHandler to invalidate
invalidateHttpSession(Boolean status)
the HttpSession at the time of logout.
Allows specifying the names of cookies to be removed
deleteCookies(String... cookieNames)
on logout success.
addLogoutHandler(LogoutHandler handler) Adds a LogoutHandler.
Specifies if SecurityContextLogoutHandler
clearAuthentication(Boolean status) should clear the Authentication at the time of
logout.
In-Memory Authentication

• To perform in-memory authentication AuthenticationManagerBuilder


provides inMemoryAuthentication() method which returns
InMemoryUserDetailsManagerConfigurer using which we can add user with the
method withUser(...).
• This method returns UserDetailsBuilder using which we assign password by
the method password(...). It again returns UserDetailsBuilder and add it
now role with its method roles(...).
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("mike").password("{noop}1111").roles("WRITER");
auth.inMemoryAuthentication().withUser("nick").password("{noop}2222").roles("READER");
}
In-Memory Authentication

• Also Spring Security supports the use of an external properties file with
includes info about users.
• The properties file should contain entries in the form:
username=password,grantedAuthority[,grantedAuthority][,enabled|
disabled]
JDBC Authentication

• The AuthenticationManagerBuilder also builds AuthenticationManager using


which JDBC and LDAP authentication is performed.
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring-security-db");
dataSource.setUsername("root"); dataSource.setPassword("1111");
return dataSource;
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}

• The DataSource bean pointing at a database containing the standard


Spring Security user data tables.
JDBC Authentication

• The standard JDBC implementation requires DB Tables to load the password,


account status (enabled or disabled) and a list of authorities (roles) for the
user.
CREATE TABLE users ( MySQL DataBase Shema
username VARCHAR(50) NOT NULL,
password VARCHAR(100) NOT NULL,
enabled TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY (username)
);

CREATE TABLE authorities (


username VARCHAR(50) NOT NULL,
authority VARCHAR(50) NOT NULL,
FOREIGN KEY (username) REFERENCES users(username)
);

CREATE UNIQUE INDEX ix_auth_username


on authorities (username, authority);
UserDetails and UserDetailsService

• The UserDetails is a core interface in Spring Security. It represents a


principal, but in an extensible and application-specific way.
• Think of UserDetails as the adapter between your own user database and
what Spring Security needs inside the SecurityContextHolder.
• On successful authentication, UserDetails is used to build the
Authentication object that is stored in the SecurityContextHolder.
• Your DAO can implements special interface called UserDetailsService that has
only one method which accepts a String-based username argument and
returns a UserDetails object:

UserDetails loadUserByUsername(String username)


throws UsernameNotFoundException;
UserDetails and UserDetailsService
public class User { @Service
private long id; public class UserService implements UserDetailsService {
private String username;
private String password; @Override
private String role; public UserDetails loadUserByUsername(String username) {
User user = getUser(username) // load user from storage
public User(long id,
String username, if (user == null) {
String password, throw new UsernameNotFoundException("User not found!");
String role) { }
this.id = id; UserBuilder userBuilder = withUsername(user.getUsername());
this.username = username; userBuilder.password(user.getPassword());
this.password = password; userBuilder.roles(user.getRole());
this.role = role;
} return userBuilder.build();
// getters and setters }
} }

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, UserDetailsService userDetailsService)
throws Exception {
auth.userDetailsService(userDetailsService);
}
UserDetails Interface
Implementation
public class User implements UserDetails {
private long id;
private String username;
private String password;
private Collection<? extends GrantedAuthority> roles;

public String[] getRoles() {


return roles.stream().map(GrantedAuthority::getAuthority).toArray(String[]::new);
}
public class Role implements GrantedAuthority {
@Override private long id;
public boolean isAccountNonExpired() { return true; } private String authority;
@Override // constructor, getters and setters
public boolean isAccountNonLocked() { return true; } @Override
@Override public String getAuthority() {
public boolean isCredentialsNonExpired() { return true; } return authority;
@Override }
public boolean isEnabled() { return true; } }
@Override
public Collection<? extends GrantedAuthority> getAuthorities() { return roles; }
}
UserDetails Interface
Implementation
@Service
public class UserService implements UserDetailsService {

private List<User> users = Arrays.asList(


new User(1, "mike", "{noop}1111", Arrays.asList(new Role("ROLE_WRITER"))),
new User(2, "nick", "{noop}2222", Arrays.asList(new Role("ROLE_READER")))
);

@Override
public UserDetails loadUserByUsername(String username) {

User user = users.stream()


.filter(u -> u.getUsername().equals(username))
.findFirst().orElse(null);

if (user == null) {
throw new UsernameNotFoundException("User not found!");
}

return user;
}
}
Password Encoding

• The password package of the spring-security-crypto module provides


support for encoding passwords.
• The PasswordEncoder is the central service interface that have two methods:

Method Short description


String encode(String rawPassword) Encode the raw password.
Verify the encoded password obtained
boolean matches(String rawPassword,
String encodedPassword) from storage matches the submitted raw
password after it too is encoded
Password Storage Format

• The general format for a password is:


{id}encodedPassword
• Such that id is an identifier used to look up which PasswordEncoder should be
used and encodedPassword is the original encoded password for the selected
PasswordEncoder.
• For example, the following might be a list of passwords encoded using different
{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
id.
{noop}password
{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99c
a763d8dc
{scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/
9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp
4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f276
05abcbc0
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#core-servi
ces-password-encoding
Define Password Encoder

• You can customize how passwords are encoded by exposing a


PasswordEncoder as a bean in our configuration.

@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

private List<User> users = Arrays.asList(


new User(1, "mike", "$2a$10$6U/5JW/Mj9AB20f8zAm3vOpTxCP/ShrEYYcl7v7OrWA4ZwCLR2H7u", ...),
new User(2, "nick", "$2a$10$vqkG1Lonp75WyLwQi3RAA.MJ8ElQXEHCFa5FmPUPwnXrc1JOEJB7m", ...)
);
Authentication Provider

• The Authentication Provider provides a mechanism for getting the user


details with which authentication can be performed.
• Spring Security provides a number of
Authentication Provider implementations,
as shown in the following diagram:
Custom Authentication Provider

• The simplest AuthenticationProvider implemented by Spring Security is


DaoAuthenticationProvider, which is also one of the earliest supported by the
framework.
• It leverages a UserDetailsService (as a DAO) in order to lookup the
username, password and GrantedAuthority s.
• It authenticates the user simply by comparing the password submitted in a
UsernamePasswordAuthenticationToken against the one loaded by the
UserDetailsService.
Custom Authentication Provider

• Spring Security follows a simple contract – an authentication request is


processed by an AuthenticationProvider and a fully authenticated object
with full credentials is returned.
• You can write a custom supports for authentication process by
implementing the AuthenticationProvider interface that have two methods:
Method Short description
Authentication authenticate(Authentication Returns a fully authenticated object including
authentication) credentials.
Returns true if this
boolean supports(Class<?> authentication) AuthenticationProvider supports the
indicated Authentication object.
Custom Authentication Provider
@Component
public class WebAuthenticationProvider implements AuthenticationProvider {

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails != null && passwordEncoder.matches(password, userDetails.getPassword())) {
return new UsernamePasswordAuthenticationToken(
userDetails.getUsername(),
userDetails.getPassword(),
userDetails.getAuthorities());
} else { return null; }
}
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, AuthenticationProvider provider)
throws Exception {
auth.authenticationProvider(provider);
}
Filter Chains

• Spring Security in the web tier is based on Servlet Filters.

Spring Security is installed as a


single Filter in the chain, and its
concrete type is
FilterChainProxy.
Important Spring Security Filters
SecurityContextPersistenceFilter
Execute once per request, populates the SecurityContextHolder with information obtained from
the configured SecurityContextRepository.

UsernamePasswordAuthenticationFilter
Process authentication, responds by default to “/login” URL.

AnonymousAuthenticationFilter
When there's no authentication object in SecurityContextHolder, it creates an anonymous
authentication object and put it there.

FilterSecurityInterceptor
Raise exceptions when access is denied.

ExceptionTranslationFilter
Catch any exceptions so that either an HTTP error response can be returned or an appropriate
AuthenticationEntryPoint can be launched.
Customizing Filter Chains
• The custom filters are configured inside configure(HttpSecurity http)
method of WebSecurityConfigurerAdapter.
• There are a couple of possible methods:
• addFilterBefore(filter, class) – adds a filter before the position of the specified
filter class.
• addFilterAfter(filter, class) – adds a filter after the position of the specified
filter class.
• addFilterAt(filter, class) – adds a filter at the location of the specified filter
class.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/login").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(webAuthenticationFilter,
UsernamePasswordAuthenticationFilter.class);
}
Customizing Filter Chains
• The UsernamePasswordAuthenticationFilter handles the authentication request
which extends from AbstractAuthenticationProcessingFilter and by default
responds to the URL “/login“.
@Component
public class WebAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

@Autowired
public WebAuthenticationFilter(WebAuthenticationManager webAuthenticationManager) {
setAuthenticationManager(webAuthenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
Authentication authentication = new UsernamePasswordAuthenticationToken(
request.getParameter("username"), request.getParameter("password")
);
return getAuthenticationManager().authenticate(authentication);
}
}
Customizing Filter Chains
• The UsernamePasswordAuthenticationFilter filter does the following
operations:
• First it checks for whether authentication is required or not based on our
HttpSecurity configuration. If authentication is not required, it simply invoke the
next filter in the chain.
• If authentication requires, then it calls the attemptAuthentication method and this
method can:
1. Return a populated authentication token for the
authenticated user, indicating successful authentication.
2. Return null, indicating that the authentication
process is still in progress.
3. Throw an AuthenticationException if the
authentication process fails.
Authentication Manager

• The AuthenticationManager is a Spring Security interface, so the


implementation can be anything we choose.
• The default implementation in Spring Security is called ProviderManager
and it delegates the fetching of persistent user information to a list of configured
AuthenticationProvider s, each of which is queried in turn to see if it can
perform the authentication.
• Each provider will either throw an exception or return a fully populated
Authentication object.
Custom Authentication Manager

• The interface AuthenticationManager only has one method:

Authentication authenticate(Authentication authentication)


throws AuthenticationException;

• This method attempts to authenticate the passed Authentication object,


returning a fully populated Authentication object (including granted
authorities) if successful.
Custom Authentication Manager
@Component
public class WebAuthenticationManager implements AuthenticationManager {

@Autowired
private List<AuthenticationProvider> authenticationProviders;

@Override
public Authentication authenticate(Authentication authentication) {
Authentication webAuthentication;
for (AuthenticationProvider authenticationProvider : authenticationProviders) {
webAuthentication = authenticationProvider.authenticate(authentication);
if (webAuthentication != null) {
return webAuthentication;
}
}
throw new BadCredentialsException("Bad user Credentials!");
}
}
Authentication Success / Fails Handler

• Spring security provides complete customization on authentication


success or fails handler.
• The AbstractAuthenticationProcessingFilter class define two methods:

Method Short description


If authentication is successful, the resulting
Authentication object will be placed into the
void successfulAuthentication(...) SecurityContext for the current thread, which
is guaranteed to have already been created by
an earlier filter.
If authentication fails, it will delegate to the
configured failure handler to allow the
void unsuccessfulAuthentication(...)
failure information to be conveyed to the
client.
Authentication Success / Fails Handler

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, Authentication authResult) throws IOException, ServletException {

SecurityContext securityContext = SecurityContextHolder.getContext();


securityContext.setAuthentication(authResult);

response.sendRedirect("/home");
}

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException failed) throws IOException, ServletException {

SecurityContextHolder.clearContext();

response.sendRedirect("/login?error=true");
}
Handling Unauthorized Error

• The default behavior for unauthenticated users is to redirect to the login


page (or whatever is appropriate for the authentication mechanism in use).
• If you want to change that you need to configure an
AuthenticationEntryPoint, which is invoked when an unauthenticated user
attempts to access a protected resource.

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.GET,"/login").permitAll()
.anyRequest().authenticated();
http.exceptionHandling()
.authenticationEntryPoint(webAuthenticationEntryPoint);
}
Custom Authentication Entry Point

• A custom AuthenticationEntryPoint can be used to set necessary response


headers, content-type, send redirect and so on before sending the response
back to the client.

@Component
public class WebAuthenticationEntryPoint implements AuthenticationEntryPoint {

@Override
public void commence(HttpServletRequest request,
HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {

response.sendRedirect("/login");
}
}
Authorization
Process
Authorities
• All Authentication implementations store a list of GrantedAuthority objects.
• The GrantedAuthority objects are inserted into the Authentication object by
the AuthenticationManager and are later read by AccessDecisionManager s
when making authorization decisions.
• The GrantedAuthority is an interface with only one method:

String getAuthority();

• By returning a representation as a String, a GrantedAuthority can be easily


read by most AccessDecisionManager s.
• All AuthenticationProvider s included with the security architecture use
standard implementation SimpleGrantedAuthority to populate the
Authentication object.
Expression-Based Web Voter
• The WebExpressionVoter class enables us to use SpEL (Spring Expression
Language) to authorize the requests.
• We can enable annotation-based security using the
@EnableGlobalMethodSecurity annotation on any @Configuration instance.
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
...
}

• prePostEnabled – enables Spring Security pre / post annotations


• securedEnabled – determines if the @Secured annotation should be
enabled
• jsr250Enabled – allows us to use the @RoleAllowed annotation
Method Security Expressions

• There are four annotations which support expression attributes to allow pre
and post-invocation authorization checks and also to support filtering of
submitted collection arguments or return values:
• @PreAuthorize – checks the given expression before entering the method.
• @PostAuthorize – verifies the given expression after execution of the
method
and could alter the result.
• @PreFilter – filters a collection argument before executing the method.
• @PostFilter – filters the returned collection after execution of the method.
Common Built-In Expressions
SpEL expression What it evaluates to
authentication The user’s authentication object obtained from the
SecurityContext
principal The user’s principal object
hasRole(role) true if the user has been granted the specified role
hasAnyRole(roles) true if the user has been granted any of the roles specified
hasAuthority(authority) true if the current principal has the specified authority
hasAnyAuthority(authorities) true if the current principal has any of the supplied authorities

• The main difference between Role and Authority is that, roles have special semantics
– starting with Spring Security 4, the 'ROLE_' prefix is automatically added by any
role related method.
equivale
hasAuthority('ROLE_ADMIN') nt hasRole('ADMIN')
Common Built-In Expressions

SpEL expression What it evaluates to


permitAll Always evaluates to true
denyAll Always evaluates to false
hasIpAddress(IP_Address) The user’s IP address (only available in web security)
isAnonymous() true if the current user is an anonymous user
isAuthenticated() true if the current user is not anonymous
isFullyAuthenticated() true if the current user is neither an anonymous nor a remember-me
user
isRememberMe() true if the current user was automatically authenticated via
remember-me
hasPermission(Object true if the user has access to the provided target for the given
target, Object permission) permission. For example, hasPermission(object, 'read')
Method Security Expressions

• The @Secured annotation is used to specify a list of roles on a method.

@Secured({ "ROLE_VIEWER", "ROLE_EDITOR" })


public boolean isValidUsername(String username) {
return userRoleRepository.isValidUsername(username);
}

• The @RoleAllowed annotation is the JSR-250’s equivalent annotation of the


@Secured annotation.
@RolesAllowed({ "ROLE_VIEWER", "ROLE_EDITOR" })
public boolean isValidUsername(String username) {
return userRoleRepository.isValidUsername(username);
}
Method Security Expressions
• Both @PreAuthorize and @PostAuthorize annotations provide expression-
based access control .
• You can access properties on the arguments using ‘#’ symbol and name of
parameters.
@PreAuthorize("hasRole('EDITOR') or hasRole('VIEWER') and
#username == authentication.principal.username")
public boolean isValidUsername(String username) {
return userRoleRepository.isValidUsername(username);
}

• Also, the @PostAuthorize annotation provides the ability to access the method
result using the built-in name returnObject in the expression.
@PostAuthorize("hasRole('EDITOR') or hasRole('VIEWER') and
returnObject.username == authentication.principal.username")
public User loadUser(String username) {
return userRoleRepository.loadUserByUserName(username);
}
Method Security Expressions

• Spring Security also provides @PreFilter and @PostFilter annotations to filter


a collection argument before executing the method and a returned
collection after executing the method.
@PreFilter("filterObject != authentication.principal.username")
public String joinAllUsernamesExceptCurrent(List<String> usernames) {
return usernames.stream().collect(Collectors.joining(";"));
}
In this case, we're joining all usernames except for the one who is authenticated.

@PostFilter("filterObject != authentication.principal.username")
public List<String> loadAllUsernamesExceptCurrent() {
return userRoleRepository.getAllUsernames();
}

In this case, the name filterObject refers to the current object in the
returned collection.
Method Security Expressions

• You can also put security annotations at class level and use multiple
security annotations on one method :

@PreAuthorize("hasRole('EDITOR')")
public class UserService {

@PreAuthorize("#username == authentication.principal.username")
@PostAuthorize("returnObject.username == authentication.principal.username")
public User loadUser(String username) {
return userRoleRepository.loadUserByUserName(username);
}
}
Securing the View
• To securing the View use the Thymeleaf tag library:

xmlns:sec="http://www.thymeleaf.org/extras/spring-security"

• The Spring Security’s JSP tag library is small and includes only three tags:

Thymeleaf property What it does


sec:authentication Renders details about the current authentication
sec:authorize Conditionally renders its body content if the user is granted
certain authorities or if a SpEL expression evaluates to true
Securing the View
<div sec:authorize="isAuthenticated()">
<form th:action="@{/perform-logout}" method="post">
<input type="submit" value="LogOut">
</form>
</div>

After LogOut process


Forbidden / Access Denied Handler
• Whenever a user attempts to access a page that is restricted to roles they do
not have, the application will return a 403 status code, which means Access
Denied.
• By default, Spring Security has an ExceptionTranslationFilter defined which
handles exceptions of type AuthenticationException and
AccessDeniedException.
• You can customize the 403 error handling process by using
@Override
accessDeniedHandler() methods
protected while
void configure(HttpSecurity http) throws Exception {
configuring the http.authorizeRequests()
HttpSecurity .antMatchers(HttpMethod.GET,"/login").permitAll()
element. .anyRequest().authenticated();

http.exceptionHandling()
.accessDeniedHandler(webAccessDeniedHandler);
}
Forbidden / Access Denied Handler

• Next you need to create a class that implements the AccessDeniedHandler


interface and overrides the handle() method.
@Component
public class WebAccessDeniedHandler implements AccessDeniedHandler {

@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {

response.sendRedirect("/access-denied");
}
}

• Advantage that you can define custom logic to be executed before


redirecting to the 403 page.
REFERENCES
AND
RESOURCES
References and Resources

• Spring Security - https://spring.io/projects/spring-security


• Spring Security Reference -
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/
• Baeldung >> Spring Authentication -
https://www.baeldung.com/category/spring/tag/authentication/
• Base64 Decoder / Encoder - https://www.base64decode.org/
• Bcrypt Password Generator - https://www.browserling.com/tools/bcrypt
• Spring in Action, 4th Edition -
http://www.allitebooks.org/spring-in-action-4th-edition/
SoftServe Confidential

You might also like