UsernamePasswordAuthenticationFilter in spring Security doesn't get invoke - spring

I wanted to pass in JSON instead of using params while logging in. So what I do is I create a filter, however, the strange thing is that the filter itself doesn't get invoke at all (Or basically when I try logging in, the request by pass it, completely ignore my filter). The request go straight to my AuthenticationHandler. I have gone through many posts and I still have no clue of why would this happen, especially when I replicate the same structure of code in Java but it works perfectly as intended...
Did I miss something obvious? Here's the UsernamePasswordAuthenticationFilter and my security config. My Java version works fine, but my Kotlin version completely ignores the filter.
It doesn't return 404 as well, it returns my AuthenticationFailureHandler.
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.ObjectMapper
import lombok.Getter
import org.apache.commons.io.IOUtils
import org.springframework.http.HttpMethod
import org.springframework.security.authentication.AuthenticationServiceException
import org.springframework.security.authentication.InternalAuthenticationServiceException
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import java.io.IOException
import java.nio.charset.Charset
class JsonLoginFilter : UsernamePasswordAuthenticationFilter() {
#Throws(AuthenticationException::class)
override fun attemptAuthentication(request: HttpServletRequest, response: HttpServletResponse?): Authentication {
if (!HttpMethod.POST.matches(request.method)) {
throw AuthenticationServiceException("Authentication method not supported: " + request.method)
}
val payload: String
try {
payload = IOUtils.toString(request.inputStream, Charset.defaultCharset())
val auth = ObjectMapper().readValue(payload, JsonAuthenticationParser::class.java)
// println(auth.username)
// println(auth.password)
val authRequest = UsernamePasswordAuthenticationToken(auth.username, auth.password)
return this.authenticationManager.authenticate(authRequest)
} catch (e: IOException) {
throw InternalAuthenticationServiceException("Could not parse authentication payload")
}
}
#Getter
data class JsonAuthenticationParser #JsonCreator
constructor(#param:JsonProperty("username")
val username: String,
#param:JsonProperty("password")
val password: String)
}
My Security config in Kotlin
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler
#EnableWebSecurity
class WebSecurity: WebSecurityConfigurerAdapter() {
#Autowired
private lateinit var entryConfig: EntryConfig
#Autowired
private lateinit var failAuth: FailAuthentication
#Autowired
private lateinit var successAuthentication: SuccessAuthentication
#Autowired
private lateinit var authenticationHandler: AuthenticationHandler
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http
.authorizeRequests()
.antMatchers("/api/v1/traveller/add","/api/v1/symptoms","/api/v1/flights","/api/v1/user/login","/api/v1/user/logout").permitAll()
.antMatchers("/api/v1/user/**","/api/v1/traveller/**").hasRole("ADMIN")
.antMatchers("/**").authenticated()
.and()
.addFilterAt(authenFilter(), UsernamePasswordAuthenticationFilter::class.java)
.formLogin().loginProcessingUrl("/api/v1/user/login")
.successHandler(successAuthentication).failureHandler(failAuth)
.and()
.exceptionHandling().authenticationEntryPoint(entryConfig)
.and()
.cors()
.and()
.logout().logoutUrl("/api/v1/user/logout")
.clearAuthentication(true)
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.logoutSuccessHandler(HttpStatusReturningLogoutSuccessHandler())
.permitAll()
//
http
.csrf()
.disable()
}
#Throws(Exception::class)
override fun configure(auth: AuthenticationManagerBuilder) {
auth.authenticationProvider(authenticationHandler)
}
#Bean
#Throws(Exception::class)
fun authenFilter(): JsonLoginFilter {
var filter : JsonLoginFilter = JsonLoginFilter()
filter.setAuthenticationManager(authenticationManagerBean())
filter.setAuthenticationSuccessHandler(successAuthentication)
filter.setAuthenticationFailureHandler(failAuth)
return filter
}
#Bean
fun passwordEncoder(): BCryptPasswordEncoder {
return BCryptPasswordEncoder()
}
}
My Java version, slightly differ but I believe it should have the same structure
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
System.out.println("hello");
if (! HttpMethod.POST.matches(request.getMethod())) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String payload;
try {
payload = IOUtils.toString(request.getInputStream(), Charset.defaultCharset());
JsonAuthenticationParser auth = new ObjectMapper().readValue(payload, JsonAuthenticationParser.class);
System.out.println(auth.username);
System.out.println(auth.password);
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(auth.username, auth.password);
return this.getAuthenticationManager().authenticate(authRequest);
} catch (IOException e) {
throw new InternalAuthenticationServiceException("Could not parse authentication payload");
}
}
#Getter
static class JsonAuthenticationParser {
private final String username;
private final String password;
#JsonCreator
public JsonAuthenticationParser(#JsonProperty("username") String username, #JsonProperty("password") String password) {
this.username = username;
this.password = password;
}
}
}
Security config in Java
import hard.string.security.AuthenticationHandler;
import hard.string.security.EntryConfig;
import hard.string.security.FailAuthhentication;
import hard.string.security.SuccessAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private EntryConfig entryConfig;
#Autowired
private FailAuthhentication failAuth;
#Autowired
private SuccessAuthentication successAuthentication;
#Autowired
private AuthenticationHandler authenticationHandler;
#Bean
public JsonAuthenticationFilter authenticationFilter() throws Exception {
JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
// filter.setContinueChainBeforeSuccessfulAuthentication(true);
filter.setAuthenticationSuccessHandler(successAuthentication);
filter.setAuthenticationFailureHandler(failAuth);
return filter;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// http://stackoverflow.com/questions/19500332/spring-security-and-json-authentication
http
.authorizeRequests()
.antMatchers("/login", "/logout", "/register",
"/debug/**").permitAll()
.antMatchers("/**").authenticated()
.and()
.addFilterAt(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.formLogin().loginProcessingUrl("/login")
.successHandler(successAuthentication).failureHandler(failAuth)
.and()
.exceptionHandling().authenticationEntryPoint(entryConfig)
.and()
.cors()
.and()
.logout().logoutUrl("/logout")
.clearAuthentication(true)
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
.permitAll();
//
http
.csrf()
.disable();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationHandler);
}
#Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
Thanks for the help

Ok, After spending days to find the bug. I found out that the filter doesn't automatically link with loginProcessingUrl. You need to specify what url you want to do the filter on or else it will just apply the filter only to localhost:xxxx/login
I just going to leave this question up here just in case someone run into this stupid problem like myself.
fun authenFilter(): JsonLoginFilter {
var filter : JsonLoginFilter = JsonLoginFilter()
filter.setAuthenticationManager(authenticationManagerBean())
filter.setAuthenticationSuccessHandler(successAuthentication)
filter.setAuthenticationFailureHandler(failAuth)
filter.setFilterProcessesUrl("/api/v1/user/login") //HERE
return filter
}

Related

Always getting redirected from /authorized to /login page using new spring authorization server

I am using new spring authorization server. And everything was working fine with version 0.3.1. But after migration to 1.0.0. When I am trying to login (and I am supposed to be redirected to /authorized?code=) I am always getting redirected back to login. Could somebody please explain me what is going wrong? Maybe config for security should be specified in one place only?
Thank you.
AuthorizationServerConfig
package oauth2.config;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import oauth2.converter.AuthorizationClientConverter;
import oauth2.handler.FederatedIdentityAuthenticationSuccessHandler;
import oauth2.repository.AuthorizationClientRepository;
import oauth2.repository.ClientRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.RequestMatcher;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.Duration;
import java.util.UUID;
#Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private AuthorizationClientConverter authorizationClientConverter;
#Autowired
private FederatedIdentityAuthenticationSuccessHandler federatedIdentityAuthenticationSuccessHandler;
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer();
RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
http
.securityMatcher(endpointsMatcher)
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
.authorizeHttpRequests(auth -> {
auth.anyRequest().authenticated();
})
.formLogin(Customizer.withDefaults())
.oauth2Login(Customizer.withDefaults())
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.apply(authorizationServerConfigurer);
return http.build();
}
#Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
return context -> {
JwtClaimsSet.Builder claims = context.getClaims();
if (context.getTokenType().equals(OAuth2TokenType.ACCESS_TOKEN)) {
claims.claim("claim", "zabur_claim");
}
};
}
#Bean
public RegisteredClientRepository registeredClientRepository(ClientRepository clientRepository) {
RegisteredClient registeredClient = RegisteredClient.withId("messaging-client")
.clientId("messaging-client")
.clientSecret(passwordEncoder.encode("secret"))
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://127.0.0.1:8080/authorized")
.scope("message.read")
.scope("message.write")
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.build();
AuthorizationClientRepository registeredClientRepository = new AuthorizationClientRepository(authorizationClientConverter, clientRepository);
registeredClientRepository.save(registeredClient);
return registeredClientRepository;
}
#Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
#Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder()
.issuer("http://localhost:8080")
.build();
}
#Bean
public TokenSettings tokenSettings() {
return TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofMinutes(5))
.build();
}
private RSAKey generateRsa() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// #formatter:off
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
// #formatter:on
}
private KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
}
SecurityConfig
package oauth2.config;
import oauth2.handler.FederatedIdentityAuthenticationSuccessHandler;
import oauth2.handler.FormLoginAuthenticationSuccessHandler;
import oauth2.service.impl.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private FederatedIdentityAuthenticationSuccessHandler federatedIdentityAuthenticationSuccessHandler;
#Autowired
private FormLoginAuthenticationSuccessHandler formLoginAuthenticationSuccessHandler;
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringRequestMatchers("/signUp", "/logout"))
.authorizeHttpRequests(auth -> {
auth.requestMatchers("/logout", "/signUp", "/authorized").permitAll();
auth.anyRequest().authenticated();
})
.formLogin(formLogin -> formLogin.successHandler(formLoginAuthenticationSuccessHandler))
.oauth2Login(oauth2Login -> oauth2Login.successHandler(federatedIdentityAuthenticationSuccessHandler));
return http.build();
}
#Bean
public DaoAuthenticationProvider authenticationProvider(CustomUserDetailsService customUserDetailsService) {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setPasswordEncoder(passwordEncoder);
authenticationProvider.setUserDetailsService(customUserDetailsService);
return authenticationProvider;
}
}
I am trying to login with OAuth2 and expecting to be redirected to the /authorized?code= but after that I am redirected to /login.
Might you are using lot more code to serve your purpose. I integrated OAuth 2 in my Application using Spring security 6.0.0 and Spring Authorization Server 1.0.0. It made me sweating lot. But I got success. For that I shared my Authorization server configuration as it did.
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http
.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0
http
.exceptionHandling((exceptions) -> exceptions
.authenticationEntryPoint(
new LoginUrlAuthenticationEntryPoint("/login"))
)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return http.build();
}
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE + 1)
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
http
.cors().and().csrf().disable()
.headers().frameOptions().sameOrigin()
.httpStrictTransportSecurity().disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
I think it may help you a little bit or you may get an idea what actually going on in your code.
SecurityFilterChain by default masks any request for authentication, it acts as a safety net, shadowing any permitAll() matcher. This is somehow not clear in the documentation, as per my understanding for the documentation, and needs to be better clarified.
Allowable paths must be declared in a SecurityFilterChain Bean, while authenticated and authorized paths must be kept in another SecurityChain Bean. To differentiate between allowed and authorized paths, use '.securityMaters()', as shown in the example below:
#Bean
#Order(0)
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringRequestMatchers("/signUp", "/logout"))
.securityMatcher("/logout", "/signUp", "/authorized")
.authorizeHttpRequests(auth -> {
auth.anyRequest().permitAll();
});
return http.build();
}
#Bean
#Order(1)
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringRequestMatchers("/signUp", "/logout"))
.authorizeHttpRequests(auth -> {
auth.anyRequest().authenticated();
})
.formLogin(formLogin -> formLogin.successHandler(formLoginAuthenticationSuccessHandler))
.oauth2Login(oauth2Login -> oauth2Login.successHandler(federatedIdentityAuthenticationSuccessHandler));
return http.build();
}
Try it and let me know how it goes with you!

Spring security with JWT when authorizing via telegram

I can’t correctly authorize through the telegram token, I seem to have done everything, but when I request I get a 403 error, although the context is correct
I don’t understand what the problem is, the context is authorized and there are roles, everything is configured, but it returns 403
SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=ru.alishev.springcourse.FirstSecurityApp.security.TelegramUserDetails#3e264c5e, Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[Include0]]]
SecurityConfig:
package ru.alishev.springcourse.FirstSecurityApp.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import ru.alishev.springcourse.FirstSecurityApp.services.TelegramDetailService;
/**
* #author Neil Alishev
*/
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final TelegramDetailService telegramDetailService;
private final JWTFilter jwtFilter;
#Autowired
public SecurityConfig(TelegramDetailService telegramDetailService, JWTFilter jwtFilter) {
this.telegramDetailService = telegramDetailService;
this.jwtFilter = jwtFilter;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// конфигурируем сам Spring Security
// конфигурируем авторизацию
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/tg_users/auth/telegram").hasRole("Include0")
.antMatchers("/authh/login", "/authh/registration", "/error", "/api/tg_users", "api/tg_users/auth/telegram").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/api/tg_users")
.loginProcessingUrl("/process_login")
.defaultSuccessUrl("/hello", true)
.failureUrl("/auth/login?error")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/auth/login")
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
// Настраиваем аутентификацию
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(telegramDetailService)
.passwordEncoder(getPasswordEncoder());
}
#Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
JWTFilter:
package ru.alishev.springcourse.FirstSecurityApp.config;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.JWTVerifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import ru.alishev.springcourse.FirstSecurityApp.security.JWTUtil;
import ru.alishev.springcourse.FirstSecurityApp.security.TelegramUserDetails;
import ru.alishev.springcourse.FirstSecurityApp.services.TelegramDetailService;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class JWTFilter extends OncePerRequestFilter {
private final JWTUtil jwtUtil;
private final TelegramDetailService telegramDetailService;
#Autowired
public JWTFilter(JWTUtil jwtUtil, TelegramDetailService telegramDetailService) {
this.jwtUtil = jwtUtil;
this.telegramDetailService = telegramDetailService;
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && !authHeader.isEmpty() && authHeader.startsWith("Bearer ")) {
String jwt = authHeader.substring(7);
// System.out.println(jwt);
if (jwt.isEmpty()) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Invalid JWT Token in Bearer Header");
} else {
try {
String username = jwtUtil.validateTokenAndRetrieveClaim(jwt);
// System.out.println(username);
TelegramUserDetails telegramUserDetails = telegramDetailService.loadUserByUsername(username);
// System.out.println("tut");
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(telegramUserDetails,
telegramUserDetails.getPassword(),
telegramUserDetails.getAuthorities());
if (SecurityContextHolder.getContext().getAuthentication() == null) {
SecurityContextHolder.getContext().setAuthentication(auth);
System.out.println(SecurityContextHolder.getContext());
}
} catch (JWTVerificationException ex) {
System.out.println("ne proshlo");
}
}
}
filterChain.doFilter(request, response);
}
}
JWTUtil:
package ru.alishev.springcourse.FirstSecurityApp.security;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.time.ZonedDateTime;
#Component
public class JWTUtil {
public String generateToken(String username) {
Date expirationDate = Date.from(ZonedDateTime.now().plusMinutes(60).toInstant());
// 60 минут действиe токена
return JWT.create()
.withSubject("Telegram user details")
.withClaim("username", username)
.withIssuedAt(new Date())
.withIssuer("Quiz game")
.withExpiresAt(expirationDate)
.sign(Algorithm.HMAC256("secret"));
}
public String validateTokenAndRetrieveClaim(String token) throws JWTVerificationException {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256("secret"))
.withSubject("Telegram user details")
.withIssuer("Quiz game")
.build();
DecodedJWT jwt = verifier.verify(token);
return jwt.getClaim("username").asString();
}
}
here is full hardcoding, but according to the idea it should work, but I get a 403 error
please help me fix
full code:
https://github.com/Include5/gameTG
I changed
.antMatchers("/api/tg_users/auth/telegram").hasRole("Include0")
to
.antMatchers("/api/tg_users/auth/telegram").hasAuthority("Include0")
and it worked

Opaque Token Implementation in spring security

im trying to create a secured spring rest api for the security i want to use opaque token stored in the database so that if the client query on the api with a bearer token . the server will check on the database if the token exist if the token is valid and get the user and the privilege and check if the user have the authority to do the request. i've done some research on the net but didn't found result that can be understood by a beginner. how can i implement this.
method 1 found method 2 i have found this two methods but i dont know where too implements the database verification and validation
after a lot of research i've found this and it is working
first i've created a Authorization filter like this :
package com.example.bda_test_11.security;
import com.example.bda_test_11.model.BdaUser;
import com.example.bda_test_11.model.Token;
import com.example.bda_test_11.repository.TokenRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Slf4j
public class AuthorizationFilter extends BasicAuthenticationFilter {
private final TokenRepository tokenRepository;
public AuthorizationFilter(AuthenticationManager authenticationManager,TokenRepository tokenRepository) {
super(authenticationManager);
this.tokenRepository = tokenRepository;
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String tokenCode = request.getHeader(HttpHeaders.AUTHORIZATION);
log.info(tokenCode);
if(tokenCode == null ) {
filterChain.doFilter(request,response);
return;
}
Token token = tokenRepository.findByCode(tokenCode).orElse(null);
if (token == null) {
filterChain.doFilter(request,response);
return;
}
BdaUser user = token.getUser();
UsernamePasswordAuthenticationToken userToken = new UsernamePasswordAuthenticationToken(user.getLogin(),null,user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(userToken);
filterChain.doFilter(request,response);
}
}
and a UsernamePasswordAuthenticationFilter like this
package com.example.bda_test_11.security;
import com.example.bda_test_11.security.domain.LoginCredentials;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
#Slf4j
public class JsonObjectAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final ObjectMapper objectMapper = new ObjectMapper();
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
try{
BufferedReader reader = request.getReader();
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line=reader.readLine())!=null){
stringBuilder.append(line);
}
LoginCredentials authRequest = objectMapper.readValue(stringBuilder.toString(),LoginCredentials.class);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
authRequest.getLogin(),
authRequest.getPassword()
);
setDetails(request,token);
log.info(token.toString());
return this.getAuthenticationManager().authenticate(token);
} catch (IOException e){
throw new RuntimeException(e);
}
}
}
if the connection is successful we generate a token like :
package com.example.bda_test_11.security;
import com.example.bda_test_11.model.BdaUser;
import com.example.bda_test_11.model.Token;
import com.example.bda_test_11.repository.TokenRepository;
import com.example.bda_test_11.service.BdaUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Slf4j #Component
public class AuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private final TokenRepository tokenRepository;
private final BdaUserService userService;
#Autowired
public AuthSuccessHandler(TokenRepository tokenRepository, BdaUserService userService) {
this.tokenRepository = tokenRepository;
this.userService = userService;
}
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
UserDetails principal = (UserDetails) authentication.getPrincipal();
BdaUser user = userService.findByLogin(principal.getUsername());
Token token = new Token(user);
tokenRepository.save(token);
log.info(token.getCode());
response.addHeader("Authorization",token.getCode());
response.addHeader("Content-Type","application/json");
response.getWriter().write("{\"token\":"+token.getCode()+",\"login\":"+user.getLogin());
}
}
and then ive configured the filterChain bean like this
package com.example.bda_test_11.security;
import com.example.bda_test_11.repository.TokenRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
#Configuration
public class BdaSecurity {
private final AuthenticationManager authenticationManager;
private final AuthSuccessHandler authSuccessHandler;
private final TokenRepository tokenRepository;
#Autowired
public BdaSecurity(AuthenticationManager authenticationManager, AuthSuccessHandler authSuccessHandler, TokenRepository tokenRepository) {
this.authenticationManager = authenticationManager;
this.authSuccessHandler = authSuccessHandler;
this.tokenRepository = tokenRepository;
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.authorizeHttpRequests((auth)->{
try {
auth
.antMatchers("/api/admin").hasAuthority("ADMIN")
.antMatchers("/api/user").hasAuthority("USER")
.anyRequest().permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(authenticationFilter())
.addFilter(new AuthorizationFilter(authenticationManager,tokenRepository))
.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.httpBasic(Customizer.withDefaults());
return http.build();
}
#Bean
public JsonObjectAuthenticationFilter authenticationFilter() {
JsonObjectAuthenticationFilter filter = new JsonObjectAuthenticationFilter();
filter.setAuthenticationSuccessHandler(authSuccessHandler);
filter.setAuthenticationManager(authenticationManager);
return filter;
}
}

Spring Boot Keycloak Multi Tenant Configuration

I have a Keycloak instance and created two realms and one user for each realm.
Realm1 (Tenant1) -> User 1
Realm2 (Tenant2) -> User 2
And i have my spring boot application.yml (resource server - API) for one specific realm and fixed in my code.
keycloak:
realm: Realm1
auth-server-url: https://localhost:8443/auth
ssl-required: external
resource: app
bearer-only: true
use-resource-role-mappings: true
It's working and validate for Realm1.
but now i can receive requests from user2 (tenant2) and the token will not be valid because the public key (realm1) is not valid for the signed request jwt token (realm2).
What is the best way to allow multi tenancy and dynamically configuration for multi realms?
thanks,
There's a whole chapter on it: 2.1.18: Multi-Tenanacy
Instead of defining the keycloak config in spring application.yaml, keep multiple keycloak.json config files, and use a custom KeycloakConfigResolver:
public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
#Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
if (request.getPath().startsWith("alternative")) { // or some other criteria
InputStream is = getClass().getResourceAsStream("/tenant1-keycloak.json");
return KeycloakDeploymentBuilder.build(is); //TODO: cache result
} else {
InputStream is = getClass().getResourceAsStream("/default-keycloak.json");
return KeycloakDeploymentBuilder.build(is); //TODO: cache result
}
}
}
I'm not sure if this works well with the keycloak-spring-boot-starter, but I think it's enough to just wire your custom KeycloakConfigResolver in the KeycloakWebSecurityConfigurerAdapter:
#Configuration
#EnableWebSecurity
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Bean
public KeycloakConfigResolver keycloakConfigResolver() {
return new PathBasedKeycloakConfigResolver();
}
[...]
}
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
#DependsOn("keycloakConfigResolver")
#KeycloakConfiguration
#EnableGlobalMethodSecurity(jsr250Enabled = true)
#ConditionalOnProperty(name = "keycloak.enabled", havingValue = "true", matchIfMissing = true)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
/**
* Registers the KeycloakAuthenticationProvider with the authentication manager.
*/
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider authenticationProvider = new KeycloakAuthenticationProvider();
authenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(authenticationProvider);
}
/**
* Defines the session authentication strategy.
*/
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.cors()
.and()
.authorizeRequests().antMatchers(HttpMethod.OPTIONS)
.permitAll()
.antMatchers("/api-docs/**", "/configuration/ui",
"/swagger-resources/**", "/configuration/**", "/v2/api-docs",
"/swagger-ui.html/**", "/webjars/**", "/swagger-ui/**")
.permitAll()
.anyRequest().authenticated();
}
}
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.OIDCHttpFacade;
import java.io.InputStream;
import java.util.concurrent.ConcurrentHashMap;
public class PathBasedConfigResolver implements KeycloakConfigResolver {
private final ConcurrentHashMap<String, KeycloakDeployment> cache = new ConcurrentHashMap<>();
#Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
String path = request.getURI();
String realm = "realmName";
if (!cache.containsKey(realm)) {
InputStream is = getClass().getResourceAsStream("/" + realm + "-keycloak.json");
cache.put(realm, KeycloakDeploymentBuilder.build(is));
}
return cache.get(realm);
}
}
import org.keycloak.adapters.KeycloakConfigResolver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.context.annotation.Bean;
#SpringBootApplication()
public class Application {
public static void main(String[] args) {
SpringApplication.run(DIVMasterApplication.class, args);
}
#Bean
#ConditionalOnMissingBean(PathBasedConfigResolver.class)
public KeycloakConfigResolver keycloakConfigResolver() {
return new PathBasedConfigResolver();
}
}

Name expected in an import annotation in Kotlin

I have an Spring Boot App (2.1.6) implemented with Kotlin. Is a Rest api that wants to have oAuth 2 with Keycloak.
I have this code in Java that compiles ok:
package com.talleres.paco.mako.config.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
#Configuration
#EnableWebSecurity
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ConditionalOnProperty(prefix = "rest.security", value = "enabled", havingValue = "true")
#Import({SecurityProperties.class})
public class SecurityConfigurer extends ResourceServerConfigurerAdapter {
#Autowired
private ResourceServerProperties resourceServerProperties;
#Autowired
private SecurityProperties securityProperties;
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(resourceServerProperties.getResourceId());
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http.cors()
.configurationSource(corsConfigurationSource())
.and()
.headers()
.frameOptions()
.disable()
.and()
.csrf()
.disable()
.authorizeRequests()
.antMatchers(securityProperties.getApiMatcher())
.authenticated();
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
if (null != securityProperties.getCorsConfiguration()) {
source.registerCorsConfiguration("/**", securityProperties.getCorsConfiguration());
}
return source;
}
#Bean
public JwtAccessTokenCustomizer jwtAccessTokenCustomizer(ObjectMapper mapper) {
return new JwtAccessTokenCustomizer(mapper);
}
#Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ProtectedResourceDetails details) {
OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(details);
//Prepare by getting access token once
oAuth2RestTemplate.getAccessToken();
return oAuth2RestTemplate;
}
}
When i convert to Kotlin i obtain a syntax error:
package com.talleres.paco.mako.config.security
import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.oauth2.client.OAuth2RestTemplate
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer
import org.springframework.web.cors.CorsConfigurationSource
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
#Configuration
#EnableWebSecurity
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ConditionalOnProperty(prefix = "rest.security", value = ["enabled"], havingValue = "true")
#Import({SecurityProperties.class})
class SecurityConfigurer : ResourceServerConfigurerAdapter() {
#Autowired
private val resourceServerProperties: ResourceServerProperties? = null
#Autowired
private val securityProperties: SecurityProperties? = null
#Throws(Exception::class)
override fun configure(resources: ResourceServerSecurityConfigurer) {
resources.resourceId(resourceServerProperties!!.resourceId)
}
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http.cors()
.configurationSource(corsConfigurationSource())
.and()
.headers()
.frameOptions()
.disable()
.and()
.csrf()
.disable()
.authorizeRequests()
.antMatchers(securityProperties!!.apiMatcher)
.authenticated()
}
#Bean
fun corsConfigurationSource(): CorsConfigurationSource {
val source = UrlBasedCorsConfigurationSource()
if (securityProperties?.corsConfiguration != null) {
source.registerCorsConfiguration("/**", securityProperties.corsConfiguration);
}
return source
}
#Bean
fun jwtAccessTokenCustomizer(mapper: ObjectMapper): JwtAccessTokenCustomizer {
return JwtAccessTokenCustomizer(mapper)
}
#Bean
fun oauth2RestTemplate(details: OAuth2ProtectedResourceDetails): OAuth2RestTemplate {
val oAuth2RestTemplate = OAuth2RestTemplate(details)
oAuth2RestTemplate.accessToken
return oAuth2RestTemplate
}
}
The error is in the line with the annotation import:
#Import({SecurityProperties.class})
I convert the code from Java to Kotlin with IntelliJ CE. The message is:
> Task :compileKotlin
e: D:\Workspaces\CleanArchitecture\mako\src\main\customized\kotlin\com\talleres\paco\mako\config\security\SecurityConfigurer.kt: (26, 34): Name expected
Thanks in advance.
I guess the tool that converts Java code to Kotlin is not always working. In this case #Import is defined in Java and it expects an array of classes, and you can use it in Kotlin by passing a vararg KClass (actually that works only for annotation's value field, otherwise you need to pass a proper array. More info here).
In other words, you need to change your code to: #Import(SecurityProperties::class).
EDIT: it seems like this issue was reported and fixed years ago: KT-10545. I also tried converting your Java code to Kotlin on my machine (using Kotlin 1.3.41) and the #Import statement was correctly generated.
Something funny, though, happened. The #ConditionalOnProperty line was converted to this:
#ConditionalOnProperty(prefix = "rest.security", value = "enabled", havingValue = "true")
which doesn't compile as "Assigning single elements to varargs in named form is forbidden". I'd be curious to see if it's a regression, as it looks correct in your snippet.

Resources