I am trying to secure a simple webservice with an AuthController providing a login and refresh endpoint. Hence auth/** should be open and all other apis should only be accessible with a valid token.
The auth endpoints work, however I have some troubles with the proper security configuration. I implemented the following JwtTokenFilter:
class JwtTokenFilter() : OncePerRequestFilter() {
@Autowired
private lateinit var jwtTokenService: JwtTokenService
@Autowired
private lateinit var refreshTokenService: RefreshTokenService
@Autowired
private lateinit var userDetailService: UserDetailService
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
val jwt = jwtTokenService.getTokenFromAuthHeader(request)
jwt?.let { token ->
try {
val claims = jwtTokenService.getClaimsFromToken(token)
val userDetails = userDetailService.loadUserByUsername(claims.subject)
val authentication = UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities)
authentication.details = WebAuthenticationDetailsSource().buildDetails(request)
SecurityContextHolder.getContext().authentication = authentication
refreshTokenService.updateRefreshToken(claims.subject)
} catch (ex: Exception) {
logger.warn("JWT-Token <$token> invalid token")
}
}
logger.trace("API request to <${request.requestURI}> with token <${!jwt.isNullOrEmpty()}>")
filterChain.doFilter(request, response)
}
}
The corresponding WebSecurity class:
@Configuration
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
class WebSecurityConfig() {
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain {
http.authorizeHttpRequests()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
http.csrf().disable()
http.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter::class.java)
return http.build()
}
@Bean
fun jwtTokenFilter(): JwtTokenFilter {
return JwtTokenFilter()
}
@Bean
fun authenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager? {
return authenticationConfiguration.authenticationManager
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
}
After adding the JwtTokenFilter to the security config I get connection-refused errors when I try to post to "auth/login". I also noticed that I am unable to debug into filterChain after adding the JwtTokenFilter bean to the config, so I guess there is some error in the filter implementation or registration?
Update to WebSecurityConfig:
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
@EnableWebSecurity(debug = true)
@Configuration
class WebSecurityConfig(
private val jwtTokenService: JwtTokenService,
private val refreshTokenService: RefreshTokenService,
private val userDetailService: UserDetailService
) {
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain {
http
.csrf().disable()
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
http.authorizeHttpRequests()
.antMatchers("/auth/**").permitAll()
http.authorizeHttpRequests()
.anyRequest().authenticated()
//http.apply(MyCustomDsl.customDsl(jwtTokenService, userDetailService, refreshTokenService))
http.addFilterBefore(JwtTokenFilter(jwtTokenService, userDetailService, refreshTokenService), UsernamePasswordAuthenticationFilter::class.java)
return http.build()
}
@Bean
fun authenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager? {
return authenticationConfiguration.authenticationManager
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
/* class MyCustomDsl(
private val jwtTokenService: JwtTokenService,
private val userDetailService: UserDetailService,
private val refreshTokenService: RefreshTokenService,
) : AbstractHttpConfigurer<MyCustomDsl, HttpSecurity>() {
companion object {
fun customDsl(jwtTokenService: JwtTokenService,userDetailService: UserDetailService, refreshTokenService: RefreshTokenService): MyCustomDsl {
return MyCustomDsl(jwtTokenService, userDetailService, refreshTokenService)
}
}
override fun configure(http: HttpSecurity) {
http.addFilterBefore(JwtTokenFilter(jwtTokenService, userDetailService, refreshTokenService), UsernamePasswordAuthenticationFilter::class.java)
}
}*/
}