Spring Security using HTTP headers
Solution 1
the minimal code addition is to define a filter and add it to the security configuration, smth like
XHeaderAuthenticationFilter.java
@Component
public class XHeaderAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String xAuth = request.getHeader("X-Authorization");
User user = findByToken(xAuth);
if (user == null) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token invalid");
} else {
final UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
}
}
//need to implement db user validation...
private User findByToken(String token) {
if (!token.equals("1234"))
return null;
final User user = new User(
"username",
"password",
true,
true,
true,
true,
Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
return user;
}
}
SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
.and()
.addFilterBefore(new XHeaderAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
another approach is to use spring's AOP
to define annotation of some logic to perform before entering the annotated controller method
Solution 2
You should avoid using default org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
since it gets client supplied username and password from the parameters of your request and you really need to get them from the headers.
So, you should write a custom AuthenticationFilter
extending referred UsernamePasswordAuthenticationFilter
to change its behaviour to fit your requirements:
public class HeaderUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public HeaderUsernamePasswordAuthenticationFilter() {
super();
this.setFilterProcessesUrl("/**");
this.setPostOnly(false);
}
/* (non-Javadoc)
* @see org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#obtainPassword(javax.servlet.http.HttpServletRequest)
*/
@Override
protected String obtainPassword(HttpServletRequest request) {
return request.getHeader(this.getPasswordParameter());
}
/* (non-Javadoc)
* @see org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#obtainUsername(javax.servlet.http.HttpServletRequest)
*/
@Override
protected String obtainUsername(HttpServletRequest request) {
return request.getHeader(this.getPasswordParameter());
}
}
This filter example extends org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
listens to every request and gets username
and password
from headers instead of parameters
.
Then you should change the configuration this way, setting your filter in the UsernamePasswordAuthenticationFilter
position:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAt(
new HeaderUsernamePasswordAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/index.html").permitAll()
.antMatchers("/swagger-ui.html").hasRole("ADMIN")
.anyRequest().authenticated();
}
Solution 3
In memory authentication would serve your purpose
@Configuration
@EnableWebMvc
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1").password("password1").roles("USER")
.and()
.withUser("user2").password("password2").roles("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().fullyAuthenticated();
http.httpBasic();
}
}
Related videos on Youtube
Chayma Atallah
Updated on July 21, 2022Comments
-
Chayma Atallah almost 2 years
I am trying to add security to my Spring Boot application. My current application is using REST controllers and every time I get a
GET
orPOST
request I read the HTTP header to retrieve the user and password in order to validate them against the properties file I have all my users stored. I want to change this to using Spring Security and this is what I got so far:public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/index.html").permitAll() .antMatchers("/swagger-ui.html").hasRole("ADMIN") .anyRequest().authenticated(); } @Bean public UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User.withUsername("admin").password("password").roles("ADMIN").build()); } }
How can I tell the
configure
method that the user credentials are to be retrieved from the header and not a login form? -
Chayma Atallah about 7 yearsThank you for your answer but I have more than one user (I just posted on as an example)
-
gladiator about 7 yearssee this you can create your own AuthenticationManager and add user accounts to it docs.spring.io/spring-boot/docs/current/reference/html/…
-
Chayma Atallah about 7 yearsOK thanks but how do I read the role now in my properties file now?
-
jlumietu about 7 yearsPlease edit your post including your properties file structure. You must build a
UserDetailsService
which reads the entries from your file -
Pino almost 4 yearsInteresting example. In my code I check for the existence of a security context at the beginning of the filter to avoid accessing the DB for each request. Of course I also allow session creation.
-
shahaf almost 4 years@Pino , yes, that would be more efficient, keep in mind that usually when using headers auth it comes hand in hand with stateless... so basically there isn't any session you can get from the context... but this code is a minimal and can be extended vastly...