Spring Security 403 even with correct username and password , i can't authenticate - spring

I'm trying to build a spring boot rest API with JWT role-based authentication, I'm stuck at the login part in spring security.
I'm currently using spring boot, spring data JPA (hibernate under the hood ), and Oracle 11g database.
All the tables get created and I can sign up but can't login.
WebSecurityConfig.java
import org.springframework.context.annotation.*;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.dao.*;
import org.springframework.security.config.annotation.authentication.builders.*;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.*;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private UserDetailsServiceImpl userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Bean
public UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST,"/users/**").permitAll()
.antMatchers("/roles").hasAnyAuthority("ADMIN")
.anyRequest().authenticated()
.and().addFilter(new JWTAuthorizationFilter(authenticationManager()))
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
UserDetails.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public class UserDetails implements org.springframework.security.core.userdetails.UserDetails {
private User user;
#Autowired
private UsersRepository usersRepository;
public UserDetails(UsersRepository usersRepository) {
this.usersRepository = usersRepository;
}
public UserDetails(User user) {
this.user = user;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<Role> roles = user.getRoles();
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
#Override
public String getPassword() {
return user.getPassword();
}
#Override
public String getUsername() {
return user.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return user.isEnabled();
}
}
UserDetailsServiceImpl.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UsersRepository usersRepository;
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user = usersRepository.getUserByUsername(username);
System.out.println("Found user in repo : "+user.getUsername()+" "+user.getPassword()+" "+user.getRoles());
if (user == null) {
throw new UsernameNotFoundException("Could not find user");
}
return new UserDetails(user);
}
}
JWTAuthenticationFilter.java
import com.auth0.jwt.JWT;
import com.bte.ifrs_server.entities.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
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;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
public Authentication attemptAuthentication(HttpServletRequest req,
HttpServletResponse res) throws AuthenticationException {
System.out.println("Attempting authentication");
try {
User creds = new ObjectMapper()
.readValue(req.getInputStream(), User.class);
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),
new ArrayList<>())
);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#Override
protected void successfulAuthentication(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain,
Authentication auth) throws IOException, ServletException {
System.out.println("Successfull Auth !!");
String token = JWT.create()
.withSubject(((User) auth.getPrincipal()).getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.sign(HMAC512(SECRET.getBytes()));
//Printing the access token into the response
PrintWriter out = res.getWriter();
res.setContentType("application/json");
res.setCharacterEncoding("UTF-8");
//Creating access token object to return it as a response
AccessToken accessToken=new AccessToken(HEADER_STRING,TOKEN_PREFIX,token);
//Set the access token as a JSON response body
Gson gson = new Gson();
String access_token=gson.toJson(accessToken);
out.print(access_token);
out.flush();
//Adding the access token to response header
res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
}
}
JWTAuthorizationFilter.java
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
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;
import java.util.ArrayList;
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
public JWTAuthorizationFilter(AuthenticationManager authManager) {
super(authManager);
}
#Override
protected void doFilterInternal(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain) throws IOException, ServletException {
String header = req.getHeader(HEADER_STRING);
if (header == null || !header.startsWith(TOKEN_PREFIX)) {
chain.doFilter(req, res);
return;
}
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
String token = request.getHeader(HEADER_STRING);
if (token != null) {
// parse the token.
String user = JWT.require(Algorithm.HMAC512(SECRET.getBytes()))
.build()
.verify(token.replace(TOKEN_PREFIX, ""))
.getSubject();
if (user != null) {
return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
}
return null;
}
return null;
}
}
AccessToken.java
public class AccessToken {
String header,prefix,value;
public AccessToken(String header, String prefix, String value) {
this.header = header;
this.prefix = prefix;
this.value = value;
}
}
SecurityConstants.java
import java.util.Arrays;
import java.util.List;
public class SecurityConstants {
public static final String SECRET = "SecretKeyToGenJWTs";
public static final long EXPIRATION_TIME = 864_000_000; // 10 days
public static final String TOKEN_PREFIX = "Bearer ";
public static final String HEADER_STRING = "Authorization";
public static final String SIGN_UP_URL = "/users/sign-up";
public static final List<String> PUBLIC_ROUTES = Arrays.asList("/users/sign-up" , "/users/login" , "/roles/**");
}
Role.java
import javax.persistence.*;
#Entity
#Table(name = "roles")
public class Role {
#Id
#Column(name = "role_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_generator")
#SequenceGenerator(name="id_generator", sequenceName = "role_id_sequence",allocationSize = 1)
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
User.java
import java.util.*;
import javax.persistence.*;
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_generator")
#SequenceGenerator(name="id_generator", sequenceName = "user_id_sequence",allocationSize = 1)
private Long id;
private String username;
private String password;
private boolean enabled;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(
name = "users_roles",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
and the main app:
IfrsServerApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#EnableJpaRepositories
#SpringBootApplication
public class IfrsServerApplication {
public static void main(String[] args) {
SpringApplication.run(IfrsServerApplication.class, args);
}
}
The code compiles and the server runs I can signup but authentication returns 403 after attempting to login ('/login').
Any Help will be appreciated. Thanks in advance.

You've shared quite a bit of code, so there may be other issues here, but one that I'll point out is that in your JWTAuthorizationFilter, you are not granting any authorities to the user:
return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
The last parameter is what authorities the user has.
Configurations like:
.antMatchers("/roles").hasAnyAuthority("ADMIN")
will always return a 403 in that case.
The first solution I'd recommend is using Spring Security's built-in support for JWTs instead of rolling your own. There's a JWT login sample that looks quite similar to what you are trying to achieve.
Alternatively, you can try changing how you are calling that constructor so that you grant a list of authorities (like new SimpleGrantedAuthority("ADMIN")). The downside here is that you'll have a lot more code to maintain.

Related

How to fix "Bad credentials" error using authentication manager?

I'm doing a project in which you have to register some users and also giving them a rol (user by default). After I've registered a user, I added jwt auth and I was able to get the jwt response, but after trying to implement some filters on it, the code started to fail.
At this point I've commented the filter implementation method and also inside my WebSecurityConfig.
It's supposed that I'll receive a username and password inside my endpoint ("authenticate/").
#RequestMapping(
value = {"authenticate", "authenticate/"},
method = RequestMethod.POST,
consumes = {
MediaType.APPLICATION_FORM_URLENCODED_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE,
MediaType.APPLICATION_JSON_VALUE
},
produces = MediaType.APPLICATION_JSON_VALUE
)
public #ResponseBody AuthResponse login(AuthRequest authRequest) throws Exception
{
return this.authService.authenticate(authRequest);
}
AuthRequest is username and password.
#AllArgsConstructor
#NoArgsConstructor
#Setter
#Getter
public class AuthResponse
{
private String username;
private String password;
}
But the error is when I try to authenticate the user using the AuthenticationManager.
AuthService authenticate method
public AuthResponse authenticate(AuthRequest authRequest) throws Exception
{
//System.out.println(authRequest.getUsername() +"," + authRequest.getPassword() + "," + this.bCryptPasswordEncoder.encode(authRequest.getPassword()));
try {
this.authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())
);
} catch (BadCredentialsException e) {
//Here is the error
throw new Exception("Incorrect username or password", e);
}
final UserDetails userDetails = usersDetailService.loadUserByUsername(authRequest.getUsername());
final String jwt = jwtUtil.generateToken(userDetails);
//this.logService.save(new Log(null, userDetails.getUsername(), jwt, null));
System.out.println(jwt);
return new AuthResponse(jwt);
}
Error inside postman console.
"timestamp": "2021-04-03T19:23:01.510+00:00",
"status": 403,
"error": "Forbidden",
"trace": "java.lang.Exception: Incorrect username or password\n\tat com.cncipo.nl.auth.service.AuthService.authenticate2(AuthService.java:60)\n\tat com.cncipo.nl.controller.SessionRestController.auth(SessionRestController.java:85)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.lang.reflect.Method.invoke(Method.java:498)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:652)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)\n\tat org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)\n\tat org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:105)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)\n\tat org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)\n\tat org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)\n\tat org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)\n\tat org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)\n\tat org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.lang.Thread.run(Thread.java:748)\nCaused by: org.springframework.security.authentication.BadCredentialsException: Bad credentials\n\tat org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:141)\n\tat org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)\n\tat org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:201)\n\tat org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:518)\n\tat com.cncipo.nl.auth.service.AuthService.authenticate2(AuthService.java:56)\n\t... 86 more\n",
"message": "Access Denied",
"path": "/api/authenticate"
}
I'll add the WebSecurityConfig and the JwtFilter in case there is something that I missed and it's causing the error.
JwtFilter
//#Component
public class JwtRequestFilter extends OncePerRequestFilter
{
#Autowired
private UsersDetailService usersDetailService;
#Autowired
private JwtUtil jwtUtil;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
{
/* Get the header for auth */
final String authHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
System.out.println("Flag of header it's null when I implemented" + authHeader);
/* Extract jwt and username */
if (authHeader != null && authHeader.startsWith("Bearer "))
{
jwt = authHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}
/* Extract user details */
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null)
{
UserDetails userDetails = this.usersDetailService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails))
{
/* Create default new jwt auth token */
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
/* Handling the control to the next filter chain */
filterChain.doFilter(request, response);
}
}
WebSecurityConfig
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private UsersDetailService usersDetailService;
//#Autowired
//private JwtRequestFilter jwtRequestFilter;
#Bean
public BCryptPasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(usersDetailService);
}
/* Bean of AuthManager due to it used to work in older version of spring */
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
/* Disable security */
http.csrf().disable();
/* User info page requires login as admin and user role. If no login, redirect */
http.authorizeRequests().antMatchers("users").access("hasAnyRole('admin', 'user')");
/* Only for admin */
http.authorizeRequests().antMatchers("logs", "admin").access("hasRole('admin')");
/* The pages does not require login/auth */
http.authorizeRequests().antMatchers("login", "logout", "/authenticate/, login/")
.permitAll();//.anyRequest().authenticated();
/* Using sessiong managment for intercept jwt auth . Spring won't create session, jwt will manage them*/
//http.exceptionHandling().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
UsersDetailService, MyUserDetails implements UserDetails from import org.springframework.security.core.userdetails.UserDetails;
#Service
public class UsersDetailService implements UserDetailsService
{
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
User user = this.userRepository.getUserByUsername_user(username);
if (user == null) { throw new UsernameNotFoundException("Could not find user"); }
return new MyUserDetails(user);
}
}
Try the following settings:
In your SecurityConfig
#Autowired
private JwtFilterRequest jwtFilterRequest;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/forgetPassword").permitAll()
.antMatchers("/registerUser").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and().formLogin().loginPage("/login").loginProcessingUrl("/login")
.defaultSuccessUrl("/index.html").failureUrl("/login?error")
.and().logout().logoutUrl("/logout");
http.addFilterBefore(this.jwtFilterRequest, UsernamePasswordAuthenticationFilter.class);
}
Filter Class JWT (JwtFilterRequest):
import cl.project.admin.security.jwt.JwtUtil;
import cl.project.admin.security.service.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
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 JwtFilterRequest extends OncePerRequestFilter {
#Autowired
private JwtUtil jwtUtil;
#Autowired
private CustomUserDetailsService userDetailsService;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorizationHeader = request.getHeader("Authorization");
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
String jwt = authorizationHeader.substring(7);
String username = this.jwtUtil.extractUsername(jwt);
if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if(this.jwtUtil.validateToken(jwt, userDetails)){
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
}
filterChain.doFilter(request, response);
}
}
Your Custom UserDetailService:
import cl.project.admin.controllers.AttentionController;
import cl.project.admin.models.dao.IUserDao;
import cl.project.admin.models.entity.User;
import cl.project.admin.models.service.UserServiceImpl;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
#Service
public class CustomUserDetailsService implements UserDetailsService {
Logger logger = Logger.getLogger(CustomUserDetailsService.class);
#Autowired
private UserServiceImpl userService;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.findByUsername(username);
if(user == null) {
this.logger.error("Error al ingresar: " + username);
throw new UsernameNotFoundException(username);
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());
}
}
JWT Util
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
#Service
public class JwtUtil {
#Value("${keyJWTSpringSecurity}")
private static final String KEY = "passwordInYourApplicationProperties";
public String generateToken(UserDetails userDetail){
return Jwts.builder().setSubject(userDetail.getUsername()).setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000*60*60*5))
.signWith(SignatureAlgorithm.HS256, KEY).compact();
}
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(KEY).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
public String generateToken(String username) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, username);
}
public String generateTokenInfinity(String username) {
Map<String, Object> claims = new HashMap<>();
return createTokenInfinity(claims, username);
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 5))
.signWith(SignatureAlgorithm.HS256, KEY).compact();
}
private String createTokenInfinity(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 800))
.signWith(SignatureAlgorithm.HS256, KEY).compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}

Vaadin BeanCreationException: during trying to call save method of my service class

Hi I have a little Vaadin project. In there, I've a UserUtils.class which has a createNewUser method which looks like this:
LoginView:
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.login.LoginForm;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.Collections;
import static com.packagename.utils.UserUtils.createNewUser;
#Route("login")
#PageTitle("Login - packagename")
public class LoginView extends VerticalLayout implements BeforeEnterObserver {
private LoginForm login = new LoginForm();
private PasswordEncoder passwordEncoder;
public LoginView(){
createNewUser("daniel.tran", "cAWFCMaa22", true, "ADMIN");
addClassName("login-view");
setSizeFull();
setAlignItems(Alignment.CENTER);
setJustifyContentMode(JustifyContentMode.CENTER);
login.setAction("login");
add(
new H1("Willkommen!"),
login
);
}
#Override
public void beforeEnter(BeforeEnterEvent event) {
// Inform the user about an authentication error
if (!event.getLocation()
.getQueryParameters()
.getParameters()
.getOrDefault("error", Collections.emptyList())
.isEmpty()) {
login.setError(true);
}
}
}
UserUtils.class:
import com.packagename.backend.entity.UserEntity;
import com.packagename.backend.service.UserService;
import com.packagename.security.SecurityConfiguration;
import com.packagename.ui.views.login.LoginView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
public class UserUtils {
#Autowired
private LoginView loginView;
private static UserService userService;
private PasswordEncoder passwordEncoder;
public static void createNewUser(String pUsername, String pPassword, boolean pStatus, String pRole) {
if (!UserUtils.userExists(pUsername)) {
userService = new UserService();
PasswordEncoder passwordEncoder = SecurityConfiguration.passwordEncoder();
String encodedPassword = passwordEncoder.encode(pPassword);
UserEntity user = new UserEntity();
user.setUserName(pUsername);
user.setPassword(encodedPassword);
user.setStatus(pStatus);
user.setRoles(pRole);
userService.save(user);
}
}
private static boolean userExists(String pUsername) {
userService = new UserService();
UserEntity user = new UserEntity();
user.setUserName(pUsername);
boolean exists = userService.exists(user);
return exists;
}
}
UserService.class:
import com.packagename.backend.entity.UserEntity;
import com.packagename.backend.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
#Service
public class UserService {
private UserRepository userRepository;
private Logger LOGGER;
#Autowired
public UserService(UserRepository pUserRepository) {
this.userRepository = pUserRepository;
}
public UserService() {}
public List<UserEntity> findAll() {
return userRepository.findAll();
}
public long count() {
return userRepository.count();
}
public void delete(UserEntity user) {
userRepository.delete(user);
}
public void save(UserEntity user) {
if (user == null) {
LOGGER.log(Level.SEVERE, "Contact is null. Are you sure you have connected your form to the application?");
return;
}
userRepository.save(user);
}
public boolean exists(UserEntity user) {
Example<UserEntity> example = Example.of(user);
boolean exists = userRepository.exists(example);
return exists;
}
}
UserEntity.class:
import javax.persistence.*;
#Entity
#Table(name = "PSYS_USERS")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int userid;
private String userName;
private String password;
private boolean status;
private String roles;
public UserEntity(){}
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public String getRoles() {
return roles;
}
public void setRoles(String roles) {
this.roles = roles;
}
}
UserRepository.class
import com.packagename.backend.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<UserEntity, Integer> {
Optional<UserEntity> findByUserName(String userName);
}
And always when it comes to the situtation, trying to call the userService methods, then it throws the following exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.packagename.ui.views.login.LoginView': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.packagename.ui.views.login.LoginView]: Constructor threw exception; nested exception is java.lang.NullPointerException
I tried to create a default constructor, at the entity and also at the service class but nothing want help.
So far,
Daniel
new UserService(); - this is the problem.
you cannot instantiate spring components on your own, you have to let spring inject/autowire them.
Places where you can inject Spring components are spring components themselves, and with Vaadin, you can inject in your views that have a #Route annotation. LoginView is such a view. So there you inject the UserService, and pass it along to the createNewUser method.
// LoginView constructor
// userService is injected/autowired this way
public LoginView(UserService userService){
createNewUser("daniel.tran", "cAWFCMaa22", true, "ADMIN", userService);
addClassName("login-view");
setSizeFull();
setAlignItems(Alignment.CENTER);
setJustifyContentMode(JustifyContentMode.CENTER);
login.setAction("login");
add(
new H1("Willkommen!"),
login
);
}
// UserUtils
public static void createNewUser(String pUsername, String pPassword, boolean pStatus, String pRole, UserService userService) {
if (!UserUtils.userExists(pUsername, userService)) {
PasswordEncoder passwordEncoder = SecurityConfiguration.passwordEncoder();
String encodedPassword = passwordEncoder.encode(pPassword);
UserEntity user = new UserEntity();
user.setUserName(pUsername);
user.setPassword(encodedPassword);
user.setStatus(pStatus);
user.setRoles(pRole);
userService.save(user);
}
}
private static boolean userExists(String pUsername, UserService userService) {
UserEntity user = new UserEntity();
user.setUserName(pUsername);
boolean exists = userService.exists(user);
return exists;
}
By the way, UserUtils is not a Spring Component so you cant autowire the loginView there either - good thing it's not used anyway

How do I use Bcrypt in my spring boot application to secure passwords?

My username and password is coming from angular to spring boot which stores it in mysql. I have simple model, repository, services and controller packages. My model is registration which has name username and password and while loggin in, the username and password is fetched from the registration table
My Registration Model Class
package com.example.angular.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="registration")
public class Registration {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
private String name;
private String username;
private String password;
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public Registration(String name, String username, String password) {
super();
this.name = name;
this.username = username;
this.password = password;
}
public Registration() {
super();
// TODO Auto-generated constructor stub
}
#Override
public String toString() {
return "Registration [id=" + id + ", name=" + name + ", username=" + username + ", password=" + password + "]";
}
}
My registration controller
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
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 com.example.angular.model.Registration;
import com.example.angular.service.RegistrationService;
#RestController
#CrossOrigin(origins="*", allowedHeaders = "*")
#RequestMapping("/register")
public class RegistrationController {
#Autowired
private RegistrationService res;
#PostMapping("/registeruser")
public ResponseEntity<Registration> registeruser(#RequestBody Registration reg)
{
Registration resk= res.registeruser(reg);
return new ResponseEntity<Registration>(resk,HttpStatus.OK);
}
#PostMapping("/login")
public ResponseEntity<Registration> loginuser(#RequestBody Registration reg)
{
List<Registration> regList = res.getusername(reg.getUsername(), reg.getPassword());
System.out.println("Logged in! ");
//return new ResponseEntity<Registration>(reg.getUsername(), HttpStatus.OK);
return null;
}
}
do I have to add any configuartion file in a package or do I have to use bcrypt in angular? Youtube videos are confusing please help
I think you want Spring Security. In this case you should use BCryptPasswordEncoder. Simply create Bean for encryption.
private static final String ADMIN = "ADMIN";
private static final String USER = "USER";
#Autowired
private UserDetailService userDetailService;
#Autowired
private DataSource dataSource;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).dataSource(dataSource)
.passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/admin").hasRole(ADMIN)
.antMatchers("/user").hasAnyRole(ADMIN, USER)
.antMatchers("/", "/register-user").permitAll()
.and().formLogin();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
If you just want to encrypt the password in BCrypt. You can use like this
String password = "password";
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String hashedPassword = passwordEncoder.encode(password);

Authentication failed (Bad Credentuals) in Spring Security with hibernate for REST

I've created a spring boot app with spring-data-rest.
My Rest API is working just fine. Then I imported the spring security. I've also done configurations after referring to a number of Web resources.
However, each time I send a request, I get Bad Credential Error The below are my codes
User.java
package com.innaun.model;
import org.springframework.data.rest.core.annotation.RestResource;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.HashSet;
import java.util.Set;
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
#Column(unique = true, nullable = false)
private String username;
#NotNull
#RestResource(exported = false )
private String password;
#NotNull
private boolean enabled;
#OneToMany
private Set<UserRole> userRoles = new HashSet<UserRole>(0);
public User() {
}
public User(String username, String password, boolean enabled) {
this.username = username;
this.password = password;
this.enabled = enabled;
}
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
UserRole.java
package com.innaun.model;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
#Entity
public class UserRole {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long userRoleId;
#NotNull
private String userRole;
#ManyToOne
private User user;
public UserRole() {
}
public UserRole(String userRole, User user) {
this.userRole = userRole;
this.user = user;
}
public Long getUserRoleId() {
return userRoleId;
}
public void setUserRoleId(Long userRoleId) {
this.userRoleId = userRoleId;
}
public String getUserRole() {
return userRole;
}
public void setUserRole(String userRole) {
this.userRole = userRole;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
UserRepository.java
package com.innaun.model;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
#RepositoryRestResource
public interface UserRepository extends CrudRepository<User, Long>{
User findByUsername(#Param("user") String user);
}
UserRoleRepository.java
package com.innaun.model;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
#RepositoryRestResource
public interface UserRoleRepository extends CrudRepository<UserRole, Long> {
}
AppUserDetailsService.java
package com.innaun.model;
import com.innaun.model.UserRepository;
import com.innaun.model.UserRole;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Service("appUserDetailsService")
public class AppUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Transactional
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
com.innaun.model.User user = userRepository.findByUsername(s);
List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRoles());
return buildUserForAuthentication(user, authorities);
}
private User buildUserForAuthentication(com.innaun.model.User user, List<GrantedAuthority> authorities){
return new User(user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles){
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
for (UserRole userRole : userRoles){
setAuths.add(new SimpleGrantedAuthority(userRole.getUserRole()));
}
List<GrantedAuthority> result = new ArrayList<GrantedAuthority>(setAuths);
return result;
}
}
ApplicationRESTSecurity.java
package com.innaun;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
#Configuration
#EnableWebSecurity
public class ApplicationRESTSecurity extends WebSecurityConfigurerAdapter {
#Qualifier("appUserDetailsService")
#Autowired
UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and().httpBasic()
.and().csrf()
.disable();
}
}
Also, I've added the below to add a test user to the database
package com.innaun;
import com.innaun.model.User;
import com.innaun.model.UserRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
public class PitchuApplication {
public static void main(String[] args) {
SpringApplication.run(PitchuApplication.class, args);
}
#Bean
CommandLineRunner init(UserRepository userRepository) {
return (args) -> {
userRepository.save(new User("myuser", "mypassword", true));
};
}
}
Just as I thought, the database now has the above user and the user is enabled.
Screenshot of the User data table
All the other tables are blank.
However when I tried the curl
curl -u myuser:mypassword localhost:8080
it returned
{"timestamp":1489090315435,"status":401,"error":"Unauthorized","message":"Bad credentials","path":"/"}
Can anyone explain where did I went wrong.
Your configuration looks fine to me. So, my best guess is that your password column in your database has length less than 60 which is the length of the hash BCrypt will produce.
I figured it out. And this was so simple mistake. the password I used to save a new user in the userRepository is raw instead of encrypted. I figured it out by:
//Create a new password encoder
private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
//Encode the password
String password = "mypassword";
String hashedPassword = passwordEncoder.encode(password);
//Create the user with the encoded password
User user = new User(myuser, hashedPassword, true);
//then persist
userRepository.save(user);

Custom User Details and Custom Authentication provider are never called

I need some additional data in in the user details of authenticated users. So i wrote a custom details service and as a second approach a custom authentication provider to enrich the data in the user object. But the principal object in the security context stays a string instead of becoming the desired user object and when i'm setting breakpoints im my custom details service and authentication porvider it looks like this code is never used by spring albeit my customized classes are listed in springs authentication manager builder.
This is my custom user details service:
package edu.kit.tm.cm.bamsg.bffweb.iamservice;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.HashSet;
import java.util.Set;
/*** #author schlund*/
public class CustomStudentDetailsService implements UserDetailsService {
private SecurityUserRepository securityUserRepository;
public CustomStudentDetailsService(SecurityUserRepository userSecurityRepository){
this.securityUserRepository=userSecurityRepository;
}
#Override
public SecurityUser loadUserByUsername(String kitID) throws UsernameNotFoundException {
try {
SecurityUser securityPerson = securityUserRepository.findByUsername(kitID);
if (securityPerson == null) {
return null;
}
return securityPerson;
}
catch (Exception e){
throw new UsernameNotFoundException("User not found");
}
}
private Set<GrantedAuthority> getAuthorities(SecurityUser securityPerson){
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(securityPerson.getRole());
authorities.add(grantedAuthority);
return authorities;
}
}
This is my custom authentication provider:
package edu.kit.tm.cm.bamsg.bffweb.iamservice;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
public Authentication authenticate(Authentication authentication ) throws AuthenticationException {
String password = authentication.getCredentials().toString().trim();
SecurityUser appUser = new SecurityUser();
return new UsernamePasswordAuthenticationToken(appUser, password, null);
}
#Override
public boolean supports(Class<? extends Object> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}
This is my web security config:
package edu.kit.tm.cm.bamsg.bffweb;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import edu.kit.tm.cm.bamsg.bffweb.iamservice.*;
#Configuration
#EnableOAuth2Sso
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan("edu.kit.tm.cm.bamsg.bffweb.iamservice")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String REALM = "bam";
#Autowired
private CustomAuthenticationProvider authProvider;
#Autowired
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout()
.and()
//endpoints without authentication
.authorizeRequests().antMatchers("/logged", "/userData").permitAll()
.and()
// default with authentication
.authorizeRequests().anyRequest().authenticated()
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
#Bean
public OAuth2FeignRequestInterceptor oAuth2FeignRequestInterceptor(OAuth2ClientContext context, OAuth2ProtectedResourceDetails details) {
return new OAuth2FeignRequestInterceptor(context, details);
}
#Bean
BasicAuthenticationEntryPoint getBasicAuthEntryPoint() {
BasicAuthenticationEntryPoint basicAuth = new BasicAuthenticationEntryPoint();
basicAuth.setRealmName(REALM);
return basicAuth;
}
}
And at least after authentication at the code line with the System.out.println the customized services should have been called, but unfortunatelly they are not. Breakpoints in the customized services have never been reached and the principal is still a string and not my customized user:
#ComponentScan("edu.kit.tm.cm.bamsg.bffweb.iamservice")
#RestController
#RequestMapping("/api/theses")
public class ThesisController {
#Autowired
private ThesisClient thesisClient;
#Autowired
private ThesisPersonLinker linker;
#Autowired
private ThesisPersonFilter filter;
#GetMapping
#PreAuthorize("hasRole('theses')")
public ResponseEntity<Collection<ThesisFrontendDTO>> findAllTheses() {
System.out.println(SecurityContextHolder.getContext().getAuthentication().getPrincipal());
The extended user class looks like that:
package edu.kit.tm.cm.bamsg.bffweb.iamservice;
import org.springframework.security.core.userdetails.User;
public class SecurityUser extends User{
String firstName;
String name;
String password;
private static final long serialVersionUID = 1L;
public SecurityUser() {
super("user", "none", null);
firstName = "Rainer";
name = "Schlund";
password = "meins";
}
public String getRole(){
return "Student";
}
}
The code contains some simplifications for testing like SecurityPerson always returning the same person, but i think that should not be a problem.
To address the problem of "principal object in the security context stays a string instead of becoming the desired user object" if you have gone through the Principal object it has getCreditantial() method returning object only , considering security user is principal object it is not providing enough information to become correct principal object.
Please take a look on UserDetailsPrincipal class for principal implementation :
public class UserDetailsPrincipal extends org.springframework.security.core.userdetails.User implements UserDetails {
/**
*
*/
private static final long serialVersionUID = 1L;
private Member user;
List<GrantedAuthority> authorities;
public UserDetailsPrincipal(Member user, List<GrantedAuthority> authorities ) {
super(user.getLogin(),user.getEncrytedPassword(),authorities);
this.authorities = authorities;
this.user = user;
}
// #Override
// public Collection<? extends GrantedAuthority> getAuthorities() {
// return this.authorities;
// }
#Override
public String getPassword() {
return user.getEncrytedPassword();
}
#Override
public String getUsername() {
return user.getLogin();
}
#Override
public boolean isAccountNonExpired() {
return !user.getIsExpired();
}
#Override
public boolean isAccountNonLocked() {
return !user.getIsLocked() || user.getIsLocked() == null;
}
#Override
public boolean isCredentialsNonExpired() {
return !user.getIsExpired() || user.getIsExpired() == null;
}
#Override
public boolean isEnabled() {
return user.getActive() == 1;
}
}
also used customAuthProvider like this :
#Slf4j
#Component("customAuthProvider")
#Transactional(readOnly = true,propagation = Propagation.REQUIRES_NEW)
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
#Qualifier("userDetailsServiceAdapter")
private UserDetailsServiceAdapter userDetailsService;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String login = authentication.getName();
String password = authentication.getCredentials().toString();
/* Member member = userRepository.findUserAccount(login); */
log.info("user for login inside custom auth service service : " + login);
if (!StringUtils.isEmpty(login) && !StringUtils.isEmpty(password)) {
try {
UserDetails userDetail = userDetailsService.loadUserByUsernameAndPassword(login, password);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetail,
userDetail.getPassword(), userDetail.getAuthorities());
token.setDetails(userDetail);
return token;
} catch (UsernameNotFoundException exception) {
return new UsernamePasswordAuthenticationToken(login, password, new ArrayList<>());
}
} else {
return new UsernamePasswordAuthenticationToken(login, password, new ArrayList<>());
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
If you want Spring security to use your Authentication provider you need to provide some entry point for providing auth credentials. Here is example of WebSecuritConfig class:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String REALM = "realm";
#Autowired
private CustomAuthenticationProvider authProvider;
#Autowired
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout()
.and()
// default with authentication
.authorizeRequests().anyRequest().authenticated()
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and().httpBasic().realmName(REALM).authenticationEntryPoint(getBasicAuthEntryPoint());
}
#Bean
BasicAuthenticationEntryPoint getBasicAuthEntryPoint() {
BasicAuthenticationEntryPoint basicAuth = new BasicAuthenticationEntryPoint();
basicAuth.setRealmName(REALM);
return basicAuth;
}
}
And you need to change SecurityUser constructor, because you cannot pass null authorities to super constructor:
public SecurityUser() {
super("user", "none", new ArrayList<>());
firstName = "Rainer";
name = "Schlund";
password = "meins";
}
When you provide Authentication provider, UserDetailsService is not used. So you need to use it in auth provider.

Resources