Deployed Spring App is not getting routed to correct URL on first logins - spring

I deployed a Spring App to Heroku. I am using Spring Security for logging in and registration. My problem is that for new users, when they initially log-in, it takes them to the base URL (the URL that Heroku gave me for my site). All of my main html files are in a folder named "cheese". The problem is that it directs me to the main URL (instead of "/cheese/account", which is where I direct it to be routed in my SecurityConfig), and I get a white label error.
This only happens the first time. When they log on again, it takes them to the correct URL, which is "/cheese/account". Also, once in a while, I will click on the base URL that heroku gave for my site, and it gives me just that URL, and doesn't direct me to "/cheese/login". This will happen if I try to access the URL from an incognito window.
I dont have this problem at all when running it locally. Here is the relevant code...Let me know if you need anything, in addition.
SecurityConfig
package com.example.demo;
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.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.crypto.password.PasswordEncoder;
import javax.sql.DataSource;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select email as principal, password as credentials, true from customer where email=?")
.authoritiesByUsernameQuery("select customer_email as principal, role_id as role from user_roles where customer_email=?")
.passwordEncoder(passwordEncoder()).rolePrefix("ROLE_");
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.csrf().disable()
.authorizeRequests()
.antMatchers(
"/**/webjars/**",
"/cheese/signup",
"/cheese/login",
"/cheese/success").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/cheese/login")
.defaultSuccessUrl("/cheese/account")
.permitAll();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
UserController
package com.example.demo.controllers;
import com.example.demo.models.Customer;
import com.example.demo.models.data.CustomerDao;
import com.example.demo.models.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping("cheese")
public class UserController {
#Autowired
private CustomerDao customerDao;
#Autowired
UserService userService;
#RequestMapping(value = "login")
public String loginPage(Model model) {
model.addAttribute("title", "Login Page");
model.addAttribute("customer", new Customer());
return "cheese/login";
}
#RequestMapping(value = "account")
public String accountInfo(Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Customer customer = customerDao.findByEmail(authentication.getName());
model.addAttribute("name", customer.getName());
model.addAttribute("customer", customer);
return "cheese/account";
}
#GetMapping("signup")
public String displaySignUpForm(Model model) {
model.addAttribute("title", "Sign Up");
model.addAttribute("customer", new Customer());
return "cheese/signup";
}
#PostMapping(value = "signup")
public String processSignUp(Model model, #ModelAttribute Customer customer, Errors errors) {
if (errors.hasErrors()) {
return "cheese/signup";
}
userService.createUser(customer);
return "cheese/success";
}
}
MainController
package com.example.demo.controllers;
import com.example.demo.models.Cheese;
import com.example.demo.models.data.CheeseDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
#RequestMapping(value = "cheese")
#Controller
public class MainController {
#Autowired
CheeseDao cheeseDao;
#RequestMapping(value = "")
public String hello(Model model) {
model.addAttribute("title", "Grocery List");
model.addAttribute("cheeses", cheeseDao.findAll());
return "cheese/index";
}
#GetMapping("add")
public String displayAddCheeseForm(Model model) {
model.addAttribute("title", "Add Cheese");
model.addAttribute("cheese", new Cheese());
return "cheese/add";
}
#PostMapping("add")
public String processAddCheeseForm(Model model,
#ModelAttribute #Valid Cheese cheese,
Errors errors) {
if (errors.hasErrors()) {
return "cheese/add";
}
cheeseDao.save(cheese);
return "redirect:";
}
#RequestMapping(value = "remove", method = RequestMethod.GET)
public String displayRemoveCheeseForm(Model model) {
model.addAttribute("cheeses", cheeseDao.findAll());
model.addAttribute("title", "Remove Cheese");
return "cheese/remove";
}
#RequestMapping(value = "remove", method = RequestMethod.POST)
public String processRemoveCheeseForm(Model model, #RequestParam int[] cheeseIds) {
for (int id : cheeseIds) {
cheeseDao.deleteById(id);
}
return "redirect:";
}
}

Related

Java Spring - Active Directory- How can I Get AD User Details (telNumber, full name, mail , address, description)?

In my college project i would like to get user informations from an AD Server such as the telephone number, the mail, the full name after an authentication.
So i use the default spring security login page and after the authentication, i get the dn and the permissions with an Authentication object. I would like to know how can i get the details of an ad user.
I would like to get his phone number to send a message with an API. This part is already working. I just need to extract the Ad user details to do it.
You will find my code below :
SecurityConfiguration.java :
package com.le_chatelet.le_chatelet_back.ldap;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
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.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider;
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider =
new ActiveDirectoryLdapAuthenticationProvider( "mydomain.com", "ldap://adserverip:389");
activeDirectoryLdapAuthenticationProvider.setConvertSubErrorCodesToExceptions(true);
activeDirectoryLdapAuthenticationProvider.setUseAuthenticationRequestCredentials(true);
return activeDirectoryLdapAuthenticationProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception{
authenticationManagerBuilder
.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception{
httpSecurity
.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and()
.formLogin();
}
}
LoginController.java :
package com.le_chatelet.le_chatelet_back.ldap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.stream.Collectors;
#RestController
public class LoginController {
#Autowired
private UserInterface userInterface;
Logger logger = LoggerFactory.getLogger(LoginController.class);
#GetMapping("/hello")
public String sayHello()
{
return "hello world";
}
#GetMapping("/user")
#ResponseBody
public Authentication getLoggedUserDetail(Authentication authentication) {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//get username
String username = authentication.getName();
logger.info("username : "+username);
// concat list of authorities to single string seperated by comma
String authorityString = authentication
.getAuthorities()
.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
String role = "role_A";
boolean isCurrentUserInRole = authentication
.getAuthorities()
.stream()
.anyMatch(role::equals);
return authentication;
}
}
If someone can show me code example it would be appreciated.
You can set the a UserDetailsContextMapper on your Provider which allows custom strategy to be used for creating the UserDetails that will be stored as the principal in the Authentication.
provider.setUserDetailsContextMapper(new PersonContextMapper());
Then you can use the #AuthenticationPrincipal annotation in your Controller to get the Person (or a custom class) instance.
#GetMapping("/phone-number")
public String phoneNumber(#AuthenticationPrincipal Person person) {
return "Phone number: " + person.getTelephoneNumber();
}
You can find a full LDAP sample application provided by the Spring Security team.

Registration Issue with Spring Security 401 with Postman

I had problem in spring security when I try to register a new user and tested it in the postman it keep giving me a 401 unauthorized response.
I checked all the filters, control, service repository and everything I already checked all the issues here and even searched a lot about it in google but no answer I hope some one had the answer.
this is the code below:
this is the Security Configuration:
package app.gym.v1.Utility.Config;
import app.gym.v1.Utility.Filter.JwtAccessDeniedHandler;
import app.gym.v1.Utility.Filter.JwtAuthenticationEntryPoint;
import app.gym.v1.Utility.Filter.JwtAuthorizationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import static app.gym.v1.Utility.Constant.SecurityConstant.*;
import static org.springframework.security.config.http.SessionCreationPolicy.*;
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private JwtAuthorizationFilter jwtAuthorizationFilter;
private JwtAccessDeniedHandler jwtAccessDeniedHandler;
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private UserDetailsService userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
public SecurityConfig(
JwtAuthorizationFilter jwtAuthorizationFilter,
JwtAccessDeniedHandler jwtAccessDeniedHandler,
JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint,
#Qualifier("userDetailsService")UserDetailsService userDetailsService,
BCryptPasswordEncoder bCryptPasswordEncoder) {
this.jwtAuthorizationFilter = jwtAuthorizationFilter;
this.jwtAccessDeniedHandler = jwtAccessDeniedHandler;
this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().and()
.sessionManagement().sessionCreationPolicy(STATELESS)
.and().authorizeRequests().antMatchers(PUBLIC_URLS).permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedHandler(jwtAccessDeniedHandler)
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);
}
#Bean
#Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManagerBean();
}
}
this is the Resource code:
package app.gym.v1.Resource;
import app.gym.v1.Model.User;
import app.gym.v1.Service.UserService;
import app.gym.v1.Utility.Exception.Domain.*;
import app.gym.v1.Utility.Exception.ExceptionHandling;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import static org.springframework.http.HttpStatus.OK;
#RestController
#RequestMapping(path = {"/","/user"})
public class UserControl extends ExceptionHandling {
private UserService userService;
#Autowired
public UserControl(UserService userService) {
this.userService = userService;
}
#PostMapping("/register")
public ResponseEntity<User> register(#RequestBody User user) throws UserNotFoundException, UsernameExistException, EmailExistException, IOException {
User newUser = userService.register(user.getUsername(), user.getEmail(), user.getPassword(), user.getRole());
return new ResponseEntity<>(newUser, OK);
}
}
this is the user implementation service:
package app.gym.v1.Utility.Impl;
import app.gym.v1.Model.User;
import app.gym.v1.Model.UserPrincipal;
import app.gym.v1.Repo.UserRepo;
import app.gym.v1.Service.UserService;
import app.gym.v1.Utility.Exception.Domain.*;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.transaction.Transactional;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import static app.gym.v1.Utility.Constant.UserImplConstant.*;
import static app.gym.v1.Utility.Enums.Role.*;
import static org.apache.commons.lang3.StringUtils.*;
#Service
#Transactional
#Qualifier("UserDetailsService")
public class UserServiceImpl implements UserService, UserDetailsService {
private Logger LOGGER = LoggerFactory.getLogger(getClass());
private UserRepo userRepo;
private BCryptPasswordEncoder passwordEncoder;
#Autowired
public UserServiceImpl(UserRepo userRepo, BCryptPasswordEncoder passwordEncoder) {
this.userRepo = userRepo;
this.passwordEncoder = passwordEncoder;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepo.findUserByUsername(username);
if (user == null) {
LOGGER.error("User with this phone number does not exist: " + username);
throw new UsernameNotFoundException("User with this phone number does not exist: " + username);
}else {
user.setLastLoginDateDisplay(user.getLastLoginDate());
user.setLastLoginDate(new Date());
userRepo.save(user);
UserPrincipal userPrincipal = new UserPrincipal(user);
LOGGER.info("Retrieving user with this phone number" + username);
return userPrincipal;
}
}
#Override
public User register(String username, String email, String password, String role) throws UserNotFoundException, UsernameExistException, EmailExistException {
validateNewUsernameAndEmail(EMPTY, username, email);
User user = new User();
user.setUserId(generateUserId());
user.setUsername(username);
user.setEmail(email);
user.setPassword(encodePassword(password));
user.setRole(USER.name());
user.setAuthorities(USER.getAuthorities());
user.setJoinDate(new Date());
user.setActive(true);
user.setNotLocked(true);
userRepo.save(user);
return user;
}
private String encodePassword(String password) {
return passwordEncoder.encode(password);
}
private String generateUserId() {
return RandomStringUtils.randomNumeric(20);
}
private String generatePassword() {
return RandomStringUtils.randomAlphanumeric(20);
}
private User validateNewUsernameAndEmail(String currentUsername, String newUsername, String newEmail) throws UserNotFoundException, UsernameExistException, EmailExistException {
User userByNewUsername = findUserByUsername(newUsername);
User userByNewEmail = findUserByEmail(newEmail);
if(isNotBlank(currentUsername)) {
User currentUser = findUserByUsername(currentUsername);
if(currentUser == null) {
throw new UserNotFoundException(NO_USER_FOUND_BY_USERNAME + currentUsername);
}
if(userByNewUsername != null && !currentUser.getId().equals(userByNewUsername.getId())) {
throw new UsernameExistException(USERNAME_ALREADY_EXISTS);
}
if(userByNewEmail != null && !currentUser.getId().equals(userByNewEmail.getId())) {
throw new EmailExistException(EMAIL_ALREADY_EXISTS);
}
return currentUser;
} else {
if(userByNewUsername != null) {
throw new UsernameExistException(USERNAME_ALREADY_EXISTS);
}
if(userByNewEmail != null) {
throw new EmailExistException(EMAIL_ALREADY_EXISTS);
}
return null;
}
}
}
the problem is with the registration my route is that(localhost:8080/user/register) or (localhost:8080/register).
I put a constant for them to make a public urls.
You need to annotate your SecurityConfig class with #Configuration or it won't be picked up.
If you do not have a custom security configuration set up properly, the application will use the default Spring Boot autoconfiguration which restricts access to all endpoints.

SpringBoot tokenRepository,JdbcTokenRepository not save in table persistence_logins

Login work, but table persitence_logins remain empty.
I Follow the documentation here :
https://courses.baeldung.com/courses/learn-spring-security-the-starter-class/lectures/924437
Don't know how to change.
I need to Override something else ?
persistent_logins
username varchar(64) not null,
series varchar(64) primary key,
token varchar(65) not null,
last_used timestamp not null
SECURITY CONFIG
package com.example.java.configuration;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
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.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import java.sql.DriverManager;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
private DataSource dataSource;
private final String USERS_QUERY = "select email, password, active from user where email=?";
private final String ROLES_QUERY = "select u.email, r.role from user u inner join user_role ur on (u.id = ur.user_id) inner join role r on (ur.role_id=r.role_id) where u.email=?";
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.usersByUsernameQuery(USERS_QUERY)
.authoritiesByUsernameQuery(ROLES_QUERY)
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/signup").permitAll()
.antMatchers("/dottore").hasAuthority("DOTTORE")
.antMatchers("/home/**").hasAnyAuthority("USER").anyRequest()
.authenticated().and().csrf().disable()
.formLogin().loginPage("/login").usernameParameter("email").passwordParameter("password")
.failureUrl("/login?error=true")
.defaultSuccessUrl("/home/home")
.and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/")
.and().rememberMe()
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(60*60)
.and().exceptionHandling().accessDeniedPage("/access_denied");
}
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource);
return db;
}
}
APPLICATION PROPERTIES
#Peristence
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=pass
# hibernate configurations
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialet= org.hibernate.dialect.MySQL5Dialect
# thumeleaf configurations
spring.thymeleaf.mode= LEGACYHTML5
spring.thymeleaf.cache=false
USER CONTROLLER:
package com.example.java.controller;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.example.java.model.User;
import com.example.java.service.UserService;
import sun.jvm.hotspot.runtime.Threads;
import java.util.concurrent.TimeUnit;
#Controller
public class UserController {
#Autowired
private UserService userService;
#RequestMapping("/")
public ModelAndView main(){
ModelAndView model = new ModelAndView();
model.setViewName("user/login");
return model;
}
#RequestMapping(value= {"/login"}, method=RequestMethod.GET)
public ModelAndView login() {
ModelAndView model = new ModelAndView();
model.setViewName("user/login");
return model;
}
#RequestMapping(value= {"/signup"}, method=RequestMethod.GET)
public ModelAndView signup() {
ModelAndView model = new ModelAndView();
User user = new User();
model.addObject("user", user);
model.setViewName("user/signup");
return model;
}
#RequestMapping(value= {"/signup"}, method=RequestMethod.POST)
public ModelAndView createUser(#Valid User user, BindingResult bindingResult) throws InterruptedException {
ModelAndView model = new ModelAndView();
User userExists = userService.findUserByEmail(user.getEmail());
if(userExists != null) {
bindingResult.rejectValue("email", "error.user", "This email already exists!");
}
if(bindingResult.hasErrors()) {
model.setViewName("user/signup");
} else {
userService.saveUser(user);
model.addObject("msg", "User has been registered successfully!");
model.addObject("user", new User());
model.setViewName("user/signup");
}
return model;
}
#RequestMapping(value= {"/home/home"}, method=RequestMethod.GET)
public ModelAndView home() {
ModelAndView model = new ModelAndView();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
//Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
model.addObject("userName", user.getNome() + " " + user.getCognome());
model.setViewName("home/home");
return model;
}
#RequestMapping(value= {"/access_denied"}, method=RequestMethod.GET)
public ModelAndView accessDenied() {
ModelAndView model = new ModelAndView();
model.setViewName("errors/access_denied");
return model;
}
}
EDIT:
RESOLVED.
In security config I put:
.and().rememberMe().rememberMeParameter("my-remember-me")
And in login.html
<input type="checkbox" class="form-check-input" name="my-remember-me" id="remember-me" />

How to get jwt token string on service layer when user request first time using jwt, Oauth2, spring security?

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;
}

Spring Security : UserDetailsService works only once

I seem to be missing something fundamental here:
#SpringBootApplication
public class Application {
User u = new User("USER", "PASSWORD",AuthorityUtils.createAuthorityList(
"ROLE_USER", "ROLE_ADMINISTRATOR"));
#Bean
public UserDetailsService userDetailsService() {
// returning a new User object works fine for every request
return username -> new User("USER", "PASSWORD",
AuthorityUtils.createAuthorityList(
"ROLE_USER", "ROLE_ADMINISTRATOR"));
// returning a previously created User object
// works only for the first request,
// subsequent requests get a 401 error
// return username -> u;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
This Spring Boot (v1.5.1) application using the spring-boot-starter-security dependency knows of only one user as of now. Also, all of its endpoints should only be accessible to this very user. In all of the working examples I have seen, the UserDetailsService always returns a new object of type User, just like in the above example.
But when it returns a previously created object (like the object named u above), only the first request gets authenticated. Why ?
A good complete example, with JPA as well, can be found here
This is just an example. Password still needs to be encrypted/secured.
Application.java
package demo;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.repository.CrudRepository;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
#ComponentScan
#EnableAutoConfiguration
#EnableGlobalMethodSecurity(securedEnabled = true)
public class Application extends WebMvcConfigurerAdapter {
#Controller
protected static class HomeController {
#RequestMapping("/")
#Secured("ROLE_ADMIN")
public String home(Map<String, Object> model) {
model.put("message", "Hello World");
model.put("title", "Hello Home");
model.put("date", new Date());
return "home";
}
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/access").setViewName("access");
}
#Bean
public ApplicationSecurity applicationSecurity() {
return new ApplicationSecurity();
}
#Order(Ordered.HIGHEST_PRECEDENCE)
#Configuration
protected static class AuthenticationSecurity extends
GlobalAuthenticationConfigurerAdapter {
#Autowired
private Users users;
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(users);
}
}
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests().antMatchers("/login").permitAll().anyRequest()
.fullyAuthenticated().and().formLogin().loginPage("/login")
.failureUrl("/login?error").and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).and()
.exceptionHandling().accessDeniedPage("/access?error");
// #formatter:on
}
}
}
#Service
class Users implements UserDetailsService {
private UserRepository repo;
#Autowired
public Users(UserRepository repo) {
this.repo = repo;
}
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user = repo.findByName(username);
if (user == null) {
return null;
}
List<GrantedAuthority> auth = AuthorityUtils
.commaSeparatedStringToAuthorityList("ROLE_USER");
if (username.equals("admin")) {
auth = AuthorityUtils
.commaSeparatedStringToAuthorityList("ROLE_ADMIN");
}
String password = user.getPassword();
return new org.springframework.security.core.userdetails.User(username, password,
auth);
}
}
#Repository
interface UserRepository extends CrudRepository<User, Long> {
User findByName(String name);
}
#Entity
class User {
#GeneratedValue
#Id
private Long id;
private String name;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
I believe it is due to the Spring User object purging the password after authentication
from -> https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/core/userdetails/User.html
Note that this implementation is not immutable. It implements the CredentialsContainer interface, in order to allow the password to be erased after authentication. This may cause side-effects if you are storing instances in-memory and reusing them. If so, make sure you return a copy from your UserDetailsService each time it is invoked.

Resources