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
Related
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;
}
}
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();
}
}
I want to add user's id as custom claim into my token.
But i cant get users id in filter because dependency injection isnt working in filters. I tried using constructor of my UserService but in this service i have repository which im #Autowiring so in debug mode i have seen that userRepository field is null.
My question is how i will add this custom claim?
Maybe is it another way to add this.
I was following this tutorial (without "Aside" chapter)
https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/#User-Authentication-and-Authorization-on-Spring-Boot
this is my filter where im trying to add this claim
package com.kamczi.auth;
import com.auth0.jwt.JWT;
import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
import com.fasterxml.jackson.databind.ObjectMapper;
import static com.kamczi.auth.SecurityConstants.EXPIRATION_TIME;
import static com.kamczi.auth.SecurityConstants.HEADER_STRING;
import static com.kamczi.auth.SecurityConstants.SECRET;
import static com.kamczi.auth.SecurityConstants.TOKEN_PREFIX;
import com.kamczi.entities.User;
import com.kamczi.repository.UserRepository;
import com.kamczi.services.UserService;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
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;
/**
*
* #author Kamil
*/
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try{
User user = new ObjectMapper()
.readValue(request.getInputStream(), User.class);
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
user.getUsername(),
user.getPassword(),
new ArrayList<>())
);
} catch(IOException e){
throw new RuntimeException(e);
}
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
String username = ((org.springframework.security.core.userdetails.User) authResult.getPrincipal()).getUsername();
String token = JWT.create()
//.withClaim("id", userService.findByUsername(username).getUser_id()) need implementation
.withSubject(username)
.withExpiresAt(new Date(System.currentTimeMillis()+EXPIRATION_TIME))
.sign(HMAC512(SECRET.getBytes()));
response.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
}
}
Try to mark your filter with #Component. The #Autowired is working only with Spring-managed beans (components).
Or you can add the filter manually using the constructor and pass the repository to it.
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
UsersRepository usersRepo;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAt(new JWTAuthenticationFilter(usersRepo), UsernamePasswordAuthenticationFilter.class);
}
}
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
}
I am new in development of micro-services with jwt.
Here is my project structure:
First micro-service is used to authenticate users by jwt and Oauth2
using username and password. This microservice is called auth-service.
Login request url is like:
[http://localhost:9092/oauth/token?username=s#sawai.com&password=randomPassword&grant_type=password][1]
By calling this url we got jwt token like:
{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyX2lkIl0sInVzZXJfbmFtZSI6InNAc2F3YWkuY29tIiwic2NvcGUiOlsicmVhZCIsIndyaXRlIl0sInRlbmFudElkIjoic2F3YWkuY29tIiwic3lzdGVtR2VuZXJhdGVkUGFzc3dvcmQiOnRydWUsImlkIjoiNTYzOTFhYzAtZDc4OC00ODEyLThmYWMtODEwZTIyMjdjYmI1IiwiZXhwIjoxNTI0NzMxNzgwLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6ImY0ZTNmNTM5LWRkNDgtNGMxMy05OTg5LTcwM2E1NWYxMjNlYyIsImVtYWlsIjoic0BzYXdhaS5jb20iLCJjbGllbnRfaWQiOiJ0cnVzdGVkLWFwcCJ9.AS1tXpUcPMgEw63FrvPP-xGBz7qCi14Eqe29rDzTXPg","token_type":"bearer","refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyX2lkIl0sInVzZXJfbmFtZSI6InNAc2F3YWkuY29tIiwic2NvcGUiOlsicmVhZCIsIndyaXRlIl0sImF0aSI6ImY0ZTNmNTM5LWRkNDgtNGMxMy05OTg5LTcwM2E1NWYxMjNlYyIsInRlbmFudElkIjoic2F3YWkuY29tIiwic3lzdGVtR2VuZXJhdGVkUGFzc3dvcmQiOnRydWUsImlkIjoiNTYzOTFhYzAtZDc4OC00ODEyLThmYWMtODEwZTIyMjdjYmI1IiwiZXhwIjoxNTI0NzQ2MTgwLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjI1ZmJlY2IyLWRhODgtNDY1ZS1iM2I2LTFlN2NmYjBlYmVjMiIsImVtYWlsIjoic0BzYXdhaS5jb20iLCJjbGllbnRfaWQiOiJ0cnVzdGVkLWFwcCJ9.jSG5zUBzu9yGqnBueU7fkIZV6XhXD8oCkYCerwHkkOw","expires_in":14399,"scope":"read write","tenantId":"sawai.com","systemGeneratedPassword":true,"id":"56391ac0-d788-4812-8fac-810e2227cbb5","email":"s#sawai.com","jti":"f4e3f539-dd48-4c13-9989-703a55f123ec"}
On auth service database we just create a single table called users with following fields:
id varchar(255)
created_on datetime
last_modified_date datetime
email varchar(255)
enabled bit(1)
password varchar(255)
role varchar(255)
system_generated_password bit(1)
tenant_id varchar(255)
validate bit(1)
OK.
Now another micro-service is called company and in company service we have list of users(not same as auth service users, because auth service contains users for multiple micro-services like: Company, Candidate etc).
Now we want to maintain last_logged_on for company users. So admin can check when an user logged in last time.
What we try to do is: When user login using auth service and user type is company user then call company service and update users last_logged_on. For calling company service we need jwt-access-token because urls are secure on company side. So how can we get access token on auth service when we request to get jwt token.
Here is configuration for jwt with spring boot on auth side.
package com.cs.je.auth.config.jwt;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import com.cs.je.auth.enums.Role;
import com.cs.je.auth.model.User;
/**
* #author sawai
*
*/
#Configuration
#EnableAuthorizationServer
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
#Value("${auth.token.time}")
private int accessTokenValiditySeconds;
#Value("${refresh.token.time}")
private int refreshTokenValiditySeconds;
#Value("${security.oauth2.resource.id}")
private String resourceId;
#Value("${trusted.app.name}")
private String trustedAppName;
#Value("${trusted.app.secret}")
private String trustedAppSecret;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private CustomAccessTokenConverter customAccessTokenConverter;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(this.authenticationManager)
.tokenServices(tokenServices())
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
// we're allowing access to the token only for clients with 'ROLE_TRUSTED_CLIENT' authority
//.tokenKeyAccess("permitAll()")
.tokenKeyAccess("hasAuthority('ROLE_TRUSTED_CLIENT')")
.checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(trustedAppName)
.authorizedGrantTypes("client_credentials", "password", "refresh_token")
.authorities("ROLE_TRUSTED_CLIENT")
.scopes("read", "write")
.resourceIds(resourceId)
// .accessTokenValiditySeconds(accessTokenValiditySeconds)
// .refreshTokenValiditySeconds(refreshTokenValiditySeconds)
.secret(trustedAppSecret);
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
System.out.println("3333333333333");
DefaultAccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
tokenConverter.setUserTokenConverter(new DefaultUserAuthenticationConverter() {
#Override
public Authentication extractAuthentication(Map<String, ?> map) {
Authentication authentication = super.extractAuthentication(map);
System.out.println("222222222222");
// User is my custom UserDetails class
User user = new User();
user.setTenantId(map.get("tenantId").toString());
user.setEmail(map.get("email").toString());
user.setId(map.get("id").toString());
//user.setPassword(map.get("password").toString());
//System.out.println("date " + );
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
authorities.addAll(authentication.getAuthorities());
user.setGrantedAuthorities(authorities);
user.setRole(Role.valueOf(authorities.iterator().next().toString()));
//user.setSpecialKey(map.get("specialKey").toString());
return new UsernamePasswordAuthenticationToken(user,
authentication.getCredentials(), authentication.getAuthorities());
}
});
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("key");
converter.setAccessTokenConverter(customAccessTokenConverter);
converter.setAccessTokenConverter(tokenConverter);
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
defaultTokenServices.setAccessTokenValiditySeconds(accessTokenValiditySeconds);
defaultTokenServices.setRefreshTokenValiditySeconds(refreshTokenValiditySeconds);
defaultTokenServices.setReuseRefreshToken(false);
defaultTokenServices.setTokenEnhancer(tokenEnhancerChain);
return defaultTokenServices;
}
}
Here is Custom Token Enhance:
package com.cs.je.auth.config.jwt;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;
import com.cs.je.auth.enums.Role;
import com.cs.je.auth.model.User;
import com.cs.je.auth.rest.api.call.CustomRestTemplate;
import com.cs.je.auth.service.UserService;
import com.cs.je.auth.utils.EncTokenUtils;
import com.cs.je.auth.utils.UserUtils;
/**
* #author sawai
*
*/
#Component
public class CustomTokenEnhancer implements TokenEnhancer {
#Autowired
private UserService userService;
#Autowired
private CustomRestTemplate customRestTemplate;
#Value("${microservice.company.protocol}")
private String protocol;
#Value("${microservice.company.port}")
private String port;
#Value("${microservice.company.ip}")
private String ipAddress;
#Value("${microservice.company.user.api}")
private String userCreateUrl;
#Autowired
private TokenStore tokenStore;
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
Map<String, Object> additionalInfo = new HashMap<>();
if (authentication != null) {
User user = (User)authentication.getPrincipal();
additionalInfo.put("email", user.getEmail());
additionalInfo.put("tenantId", user.getTenantId());
additionalInfo.put("id", user.getId());
if (user.isSystemGeneratedPassword()) {
additionalInfo.put("systemGeneratedPassword", true);
}
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
System.out.println(accessToken.getRefreshToken());
System.out.println(accessToken.getRefreshToken().getValue());
System.out.println(accessToken.getTokenType());
/*if (user.getRole().equals(Role.ROLE_ADMIN) || user.getRole().equals(Role.ROLE_USER)) {
String token = accessToken.toString();
try {
System.out.println("before call");
//ResponseEntity<Object> responseEntity = customRestTemplate.exchange(protocol + "://" + ipAddress + ":" + port + userCreateUrl + "/" + user.getId() + "/last-loggedOn", token, EncTokenUtils.getEncToken(user.getEmail()), HttpMethod.PUT, null);
System.out.println("successfull");
} catch (Exception e) {
e.printStackTrace();
}
}*/
System.out.println("1111111111");
}
return accessToken;
}
}
Security Config
package com.cs.je.auth.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.cs.je.auth.constant.Constants;
import com.cs.je.auth.enums.Role;
import com.cs.je.auth.model.User;
import com.cs.je.auth.repository.UserRepository;
import com.cs.je.auth.service.UserService;
/**
* #author sawai
*
*/
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Autowired
private UserRepository userRepository;
/*#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/").permitAll()
.antMatchers(HttpMethod.POST ,"/user/**").hasAnyAuthority("ROLE_SUPER_USER", "ROLE_ADMIN")
.anyRequest().authenticated();
httpSecurity.csrf().disable();
httpSecurity.headers().frameOptions().disable();
httpSecurity.requestCache().requestCache(new NullRequestCache());
httpSecurity.httpBasic();
//httpSecurity.addFilterBefore(CORSFilter, ChannelProcessingFilter.class);
}*/
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
auth.userDetailsService(userService).passwordEncoder(passwordEncoder);
if (userRepository.count() < 1) {
User user = new User();
user.setEmail("jeAdmin#email.com");
user.setPassword("jeAdminUser");
user.setTenantId(Constants.JE_TENANT_ID);
user.setRole(Role.ROLE_SUPER_USER);
user.setValidate(true);
userService.create(user, null);
}
}
#Override
public void configure(WebSecurity webSecurity) {
webSecurity.ignoring().antMatchers("/api/candidate/**");
webSecurity.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
webSecurity.ignoring().antMatchers("/api/company/**");
webSecurity.ignoring().antMatchers("/api/forgotPassword/**");
//webSecurity.ignoring().antMatchers(HttpMethod.POST, "/oauth/**");
}
}
ResourceConfig.java
package com.cs.je.auth.config.jwt;
/**
* #author sawai
*
*/
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
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.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.savedrequest.NullRequestCache;
import com.cs.je.auth.filter.CORSFilter;
#Configuration
#EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {
#Value("${security.oauth2.resource.id}")
private String resourceId;
// The DefaultTokenServices bean provided at the AuthorizationConfig
#Autowired
private DefaultTokenServices tokenServices;
// The TokenStore bean provided at the AuthorizationConfig
#Autowired
private TokenStore tokenStore;
#Autowired
private CORSFilter corsFilter;
// To allow the rResourceServerConfigurerAdapter to understand the token,
// it must share the same characteristics with AuthorizationServerConfigurerAdapter.
// So, we must wire it up the beans in the ResourceServerSecurityConfigurer.
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId(resourceId)
.tokenServices(tokenServices)
.tokenStore(tokenStore);
}
public void configure(WebSecurity webSecurity) {
webSecurity.ignoring().antMatchers("/api/candidate/**");
// webSecurity.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
// webSecurity.ignoring().antMatchers(HttpMethod.POST, "/oauth/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/").permitAll().and().authorizeRequests().antMatchers("/console/**")
.permitAll().and().authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll().and()
// when restricting access to 'Roles' you must remove the "ROLE_" part role
// for "ROLE_USER" use only "USER"
//.antMatchers("/api/hello").access("hasAnyRole('USER')")
//.antMatchers("/api/admin").hasRole("ADMIN")
.authorizeRequests().antMatchers(HttpMethod.POST ,"/api/user/**").hasAnyAuthority("ROLE_SUPER_USER", "ROLE_ADMIN")
// restricting all access to /api/** to authenticated users
//.antMatchers("/**")
//.antMatchers("/api/**").authenticated();
.anyRequest().authenticated();
http.csrf().disable();
http.headers().frameOptions().disable();
http.requestCache().requestCache(new NullRequestCache());
http.httpBasic();
http.addFilterBefore(corsFilter, ChannelProcessingFilter.class);
}
}
All above config is on auth service side.
Now when user request for jwt token on auth, then we want to get access-token value on service layer, so i can call company service by secure url calling.
Please guide me how can we get access-token value when user request for jwt token. If you look in CustomTokenEnhancer then we tried to print access-token there by using following statements:
**System.out.println(accessToken.getRefreshToken());
System.out.println(accessToken.getRefreshToken().getValue());
System.out.println(accessToken.getTokenType());**
But values are similar to: 642e0cf2-9214-42d8-ae85-29e5cdfccef1
But we want actual token here.
Please guide me.
You can use that method
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String TOKEN_SEPERATOR = " ";
public static String getAccessToken(){
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
return Arrays.asList(request.getHeader(AUTHORIZATION_HEADER).split(TOKEN_SEPERATOR)).get(1);
}
return null;
}