My Custom UserDetailsService
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
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 br.com.fimd.entidades.Usuario;
import br.com.fimd.service.UsuarioService;
#Transactional(readOnly=true)
#Service("userDetailsServiceImpl")
public class UserDetailsServiceImpl implements UserDetailsService{
#Autowired
private UsuarioService usuarioService;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Usuario usuario = usuarioService.findUserByEmail(email);
if(usuario == null) {
throw new UsernameNotFoundException("Usuário nao encontrado.");
}
return new User(usuario.getEmail(), usuario.getSenha(), usuario.getAuthorities());
}
}
My Security Configuration
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.builders.WebSecurity;
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.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("userDetailsServiceImpl")
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().disable().
csrf().disable().authorizeRequests()
.antMatchers("/home").permitAll()
.antMatchers("/public/**").permitAll()
.antMatchers("/private/**").hasRole("USER")
//.antMatchers("/admin*").access("hasRole('ROLE_ADMIN')")
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
//.addFilterBefore(new JWTAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/assets/**");
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
My User Entity
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#Entity
#Table(name = "usuarios")
#EntityListeners(AuditingEntityListener.class)
#JsonIgnoreProperties(value = { "createdAt", "updatedAt" }, allowGetters = true)
public class Usuario implements UserDetails, Serializable{
private static final long serialVersionUID = 4038437690572999966L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long id;
#NotBlank
private String nome;
#NotBlank
private String email;
#NotBlank
private String senha;
#NotBlank
private String cpf;
#Column
private boolean ativo;
#ManyToMany
#JoinTable(name="perfil_usuario", joinColumns=
{#JoinColumn(name="user_id")}, inverseJoinColumns=
{#JoinColumn(name="tipo_perfil")})
private Set<Perfil> perfis = new HashSet<>();
#OneToMany(mappedBy = "usuario", cascade = CascadeType.ALL)
private List<Investimento> investimentos;
#OneToMany(mappedBy = "usuario", cascade = CascadeType.ALL)
private List<Extrato> extratos;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCpf() {
return cpf;
}
public void setCpf(String cpf) {
this.cpf = cpf;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public String getSenha() {
return senha;
}
public void setSenha(String senha) {
this.senha = senha;
}
public boolean isAtivo() {
return ativo;
}
public void setAtivo(boolean ativo) {
this.ativo = ativo;
}
public Set<Perfil> getPerfis() {
return perfis;
}
public void setPerfis(Set<Perfil> perfis) {
this.perfis = perfis;
}
public List<Investimento> getInvestimentos() {
return investimentos;
}
public void setInvestimentos(List<Investimento> investimentos) {
this.investimentos = investimentos;
}
public List<Extrato> getExtratos() {
return extratos;
}
public void setExtratos(List<Extrato> extratos) {
this.extratos = extratos;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.perfis;
}
#Override
public String getPassword() {
return this.senha;
}
#Override
public String getUsername() {
return this.email;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
My Perfil Entity
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import org.springframework.security.core.GrantedAuthority;
#Entity
public class Perfil implements GrantedAuthority{
private static final long serialVersionUID = 1L;
#Id
private String tipoPerfil;
#ManyToMany(mappedBy="perfis")
private List<Usuario> usuarios;
public List<Usuario> getUsuarios() {
return usuarios;
}
public void setUsuarios(List<Usuario> usuarios) {
this.usuarios = usuarios;
}
public String getTipoPerfil() {
return tipoPerfil;
}
public void setTipoPerfil(String tipoPerfil) {
this.tipoPerfil = tipoPerfil;
}
#Override
public String getAuthority() {
return this.tipoPerfil;
}
}
My Spring Filter Initializer
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
#Configuration
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
When i call a "/private/service" my loadUserByUsername not being called never, my application ever send me a 403 forbidden, access denied.
Why that?
I tried a lot of tutorials from internet and my code seems to be correct, i'm using spring starter 2.0.5.RELEASE
I already tried to call the userDetailsService from a #Bean method in SecurityConfiguration
Your security configuration is not complete, you must provide as well the login information:
.formLogin()
.loginPage("/login.html")
.defaultSuccessUrl("/home")
.failureUrl("/login.html?error=true")
Otherwise all your requests will be unauthorized. Please see this tutorial:
https://www.baeldung.com/spring-security-login
Your Custom UserDetails service will be called only when the application will receive a POST to login url with username and password, otherwise it will not have what data to authorize.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 21 days ago.
Improve this question
I've been trying to create a spring security logic to authorize users (inserted into my database) to do different things based on their roles (simple). I'm supposed to have ROLE_USER and ROLE_ADMIN, but I don't think any of them work. Please help. I'll try to put every bit of important code here (even the imports).
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.springframework.security.core.GrantedAuthority;
import com.vitoria.enums.RoleName;
#Entity
#Table(name = "TB_ROLE")
public class RoleModel implements GrantedAuthority, Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID roleId;
#Enumerated(EnumType.STRING)
#Column(nullable = false, unique = true)
private RoleName roleName;
#Override
public String getAuthority() {
return this.roleName.toString();
}
public UUID getRoleId() {
return roleId;
}
public void setRoleId(UUID roleId) {
this.roleId = roleId;
}
public RoleName getRoleName() {
return roleName;
}
public void setRoleName(RoleName roleName) {
this.roleName = roleName;
}
}
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
#Entity
#Table(name = "TB_USER")
public class UserModel implements UserDetails, Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID userId;
#Column(nullable = false, unique = true)
private String username;
#Column(nullable = false)
private String password;
#ManyToMany
#JoinTable(name = "TB_USERS_ROLES",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id"))
private List<RoleModel> roles;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.roles;
}
#Override
public String getPassword() {
return this.password;
}
#Override
public String getUsername() {
return this.username;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
public UUID getUserId() {
return userId;
}
public void setUserId(UUID userId) {
this.userId = userId;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
}
public enum RoleName {
ROLE_ADMIN,
ROLE_USER;
}
import javax.transaction.Transactional;
import org.springframework.security.core.userdetails.User;
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 com.vitoria.models.UserModel;
import com.vitoria.repositories.UserRepository;
#Service
#Transactional
public class UserDetailsServiceImpl implements UserDetailsService {
final UserRepository userRepository;
public UserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserModel userModel = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));
return new User(userModel.getUsername(), userModel.getPassword(), true, true, true,true, userModel.getAuthorities());
}
}
import org.springframework.data.jpa.repository.JpaRepository;
import com.vitoria.models.RoleModel;
public interface RoleRepository extends JpaRepository<RoleModel, Long> {
RoleModel findByRoleName(String roleName);
}
import java.util.Optional;
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.vitoria.models.UserModel;
#Repository
public interface UserRepository extends JpaRepository<UserModel, UUID> {
Optional<UserModel> findByUsername(String username);
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeHttpRequests()
.anyRequest().authenticated()
.and()
.csrf().disable();
return http.build();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.vitoria.models.Flowers;
import com.vitoria.repositories.FlowersRepository;
#RestController
#CrossOrigin(origins = "*", maxAge = 3600)
#EnableAutoConfiguration
#RequestMapping("/flowers")
public class FlowersController {
#Autowired
private FlowersRepository repo;
#PreAuthorize("hasRole('ROLE_USER')")
#GetMapping
public ResponseEntity<List<Flowers>> findAll(){
List<Flowers> allFlowers=repo.findAll();
return ResponseEntity.ok().body(allFlowers);
}
#PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_USER')")
#PostMapping("/insert")
public ResponseEntity<Flowers> insert(#RequestBody Flowers flower){
Flowers entity=flower;
repo.save(entity);
return ResponseEntity.ok().body(entity);
}
#PreAuthorize("hasRole('ROLE_ADMIN')")
#DeleteMapping("/delete/{id}")
public ResponseEntity<Void> deleteById(#PathVariable Integer id){
repo.deleteById(id);
return ResponseEntity.noContent().build();
}
}
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.vitoria.models.UserModel;
import com.vitoria.repositories.UserRepository;
#RestController
#RequestMapping("/users")
public class UserController {
#Autowired
private UserRepository repo;
#PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_USER')")
#GetMapping
public ResponseEntity<List<UserModel>> findAll(){
List<UserModel> users=repo.findAll();
return ResponseEntity.ok().body(users);
}
#PreAuthorize("hasRole('ROLE_USER')")
#GetMapping("/{username}")
public ResponseEntity<Optional<UserModel>> findByUsername(#RequestParam("username")String username){
Optional<UserModel> user=repo.findByUsername(username);
return ResponseEntity.ok().body(user);
}
#PreAuthorize("hasRole('ROLE_ADMIN')")
#PostMapping("/save")
public ResponseEntity<UserModel> insert(#RequestBody UserModel user){
UserModel entity=user;
user.setPassword(passwordEncoder().encode(user.getPassword()));
repo.save(entity);
return ResponseEntity.ok().body(entity);
}
private PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
my database looks like this:
tb_user
tb_role
tb_users_roles
I think this is all.
Please keep in mind that when I try to make ->any<- request to any endpoint it comesback unauthorized. SO, I tried something else: taking off the role permission (using the #PreAuthorize("permitAll()")) of get all users and I still get 401 as return! Please please help me.
I'm building my own store website, and I'm doing good so far, but I've come accross this error when I try to invoke this method confirmationTokenRepository.save(Object). I get an error message: "Cannot invoke "com.marin.thrift.registration.token.ConfirmationTokenRepository.save(Object)" because "this.confirmationTokenRepository" is null". I'm trying to send a token which will be "linked" to a users email which he will have to click to enable his account. I can see the user inside the database, but can't get token:
ConfirmationTokenService.java
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Service;
#Service
#AllArgsConstructor
#NoArgsConstructor
public class ConfirmationTokenService {
private ConfirmationTokenRepository confirmationTokenRepository;
public void saveConfirmationToken(ConfirmationToken token) {
confirmationTokenRepository.save(token);
}
}
ConfirmationTokenRepository.java
package com.marin.thrift.registration.token;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
#Repository
public interface ConfirmationTokenRepository extends JpaRepository<ConfirmationToken, Long> {
Optional<ConfirmationToken> findByToken(String token);
}
ConfirmationToken.java
package com.marin.thrift.registration.token;
import com.marin.thrift.entity.User;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
#Data
#NoArgsConstructor
#Table(name = "token")
#Entity
public class ConfirmationToken {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "token", nullable = false)
private String token;
#Column(name = "createdAt", nullable = false)
private LocalDateTime createdAt;
#Column(name = "expiredAt")
private LocalDateTime expiredAt;
#Column(name = "confirmedAt")
private LocalDateTime confirmedAt;
#ManyToOne
#JoinColumn(nullable = false, name = "user_id")
private User user;
public ConfirmationToken(String token, LocalDateTime createdAt, LocalDateTime expiredAt, User user) {
this.token = token;
this.createdAt = createdAt;
this.expiredAt = expiredAt;
this.user = user;
}
}
UserService.java
package com.marin.thrift.service;
import com.marin.thrift.dao.UserRepository;
import com.marin.thrift.entity.User;
import com.marin.thrift.registration.token.ConfirmationToken;
import com.marin.thrift.registration.token.ConfirmationTokenService;
import lombok.AllArgsConstructor;
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 java.time.LocalDateTime;
import java.util.UUID;
#Service
#AllArgsConstructor
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
private final static String USER_NOT_FOUND = "user with email %s not found";
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final ConfirmationTokenService confirmationTokenService;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
return userRepository.findByUsername(email).orElseThrow(() -> new
UsernameNotFoundException(String.format(USER_NOT_FOUND, email)));
}
public String singUpUser(User user) {
boolean userExists = userRepository.findByUsername(user.getEmail()).isPresent();
if (userExists) {
return "user already in place";
}
String encodedPassword = bCryptPasswordEncoder.encode(user.getPassword());
user.setPassword(encodedPassword);
userRepository.save(user);
String token = UUID.randomUUID().toString();
ConfirmationToken confirmationToken = new ConfirmationToken(token, LocalDateTime.now(), LocalDateTime.now().plusMinutes(15), user);
confirmationTokenService.saveConfirmationToken(confirmationToken);
return token;
}
WebSecurityConfig.java
package com.marin.thrift.security.config;
#Configuration
#AllArgsConstructor
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserService userService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable().authorizeRequests()
.antMatchers("/api/v*/registration/**").permitAll()
.anyRequest().authenticated().and().formLogin();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(bCryptPasswordEncoder);
provider.setUserDetailsService(userService);
return provider;
}
I have a spring controller that let's me sign in and supposed to return user details(roles, username) in response when entering correct credentials but instead only return the jwt token and username. Here's the api response:
{
"username": "adam",
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZGFtIiwicm9sZXMiOlsiUk9MRV9BRE1JTiJdLCJpYXQiOjE1NTcyMzUxMTMsImV4cCI6MTU1NzIzODcxM30.PksRTzgYu6r79KNmc4YDNXGqO1Ke63oOzzoPjURUY9k"
}
My controller:
package com.example.demo.controller;
import com.example.demo.domain.User;
import com.example.demo.repository.UserRepository;
import com.example.demo.security.jwt.JwtTokenProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import static org.springframework.http.ResponseEntity.ok;
#RestController
#RequestMapping("/auth")
public class AuthController {
#Autowired
AuthenticationManager authenticationManager;
#Autowired
JwtTokenProvider jwtTokenProvider;
#Autowired
UserRepository users;
#PostMapping("/signin")
public ResponseEntity signin(#RequestBody User user) {
try {
String username = user.getUsername();
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, user.getPassword()));
String token = jwtTokenProvider.createToken(username, this.users.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("Username " + username + "not found")).getRoles());
Map<Object, Object> model = new HashMap<>();
model.put("username", username);
model.put("token", token);
model.put("roles", user.getRoles());
return ok(model);
} catch (AuthenticationException e) {
throw new BadCredentialsException("Invalid username/password supplied");
}
}
}
My entity:
package com.example.demo.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSetter;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static java.util.stream.Collectors.toList;
#Entity
#Table(name="users")
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class User implements UserDetails {
private static final long serialVersionUID = 357523406648925755L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
#NotEmpty
#Column(name="username")
private String username;
#Column(name="firstname")
private String firstName;
#Column(name="lastname")
private String lastName;
#NotEmpty
#Column(name="password")
private String password;
#Column(name = "email")
#NotEmpty()
private String email;
#Column(name = "enabled")
private boolean enabled;
#ElementCollection(fetch = FetchType.EAGER)
#Builder.Default
private List<String> roles = new ArrayList<>();
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.roles.stream().map(SimpleGrantedAuthority::new).collect(toList());
}
#JsonIgnore
#Override
public String getPassword() {
return this.password;
}
#JsonSetter
public void setPassword(String password) {
this.password = password;
}
#Override
public String getUsername() {
return this.username;
}
#JsonIgnore
#Override
public boolean isAccountNonExpired() {
return true;
}
#JsonIgnore
#Override
public boolean isAccountNonLocked() {
return true;
}
#JsonIgnore
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
I've been debugging for 10 hours and can't seem to figure out why I'm continuously getting bad credentials errors within Spring Security.
I can actually see that I'm grabbing the user from the database in my userdetailsservice. The passwords match up correctly (not hashing/encoding anything currently), but as I dive into the framework, I get the mismatch creds exception.
I'm honestly out of ideas, I feel like I have rewritten this code 3-4 times now, but to no avail.
I'm hitting /login to generate the token.
Jwt Security Config
import com.schachte.asciiphile.security.messaging.JwtAuthenticationEntryPoint;
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.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
#Configuration
#Order(1)
public class JwtSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String ROOT_CTX_MATCH_PATH = "/phile/**";
#Autowired
private JwtAuthenticationEntryPoint entryPoint;
#Qualifier("userDetailsServiceImpl")
#Autowired
private UserDetailsService userDetailsService;
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(new JwtLoginFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
http.headers().cacheControl();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
}
Jwt Login Filter
import com.fasterxml.jackson.databind.ObjectMapper;
import com.schachte.asciiphile.model.JwtAuthententicationToken;
import com.schachte.asciiphile.model.User;
import com.schachte.asciiphile.security.util.JwtGenerator;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.auth0.jwt.JWT;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
import java.io.IOException;
import java.util.Date;
import java.util.List;
public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {
private JwtGenerator jwtGenerator = new JwtGenerator();
private AuthenticationManager authenticationManager;
public JwtLoginFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
public Authentication attemptAuthentication(
HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException {
User creds = null;
try {
creds = new ObjectMapper()
.readValue(req.getInputStream(), User.class);
} catch (IOException e) {
e.printStackTrace();
}
List<GrantedAuthority> grantedAuthorities = AuthorityUtils
.commaSeparatedStringToAuthorityList(creds.getRole());
return authenticationManager.authenticate(
new JwtAuthententicationToken(
creds.getUsername(),
creds.getPassword(),
grantedAuthorities
)
);
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, auth);
String token = JWT.create()
.withSubject(((User) auth.getPrincipal()).getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + 864_000_000))
.sign(HMAC512("secret".getBytes()));
response.addHeader("Authorization", "Token " + token);
}
}
Jwt Authentication Token
import lombok.Data;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.List;
#Data
public class JwtAuthententicationToken extends UsernamePasswordAuthenticationToken {
private String username;
private String password;
private List<GrantedAuthority> grantedAuthorities;
public JwtAuthententicationToken(String username, String password, List<GrantedAuthority> grantedAuthorities) {
super(null, null);
this.username = username;
this.password = password;
this.grantedAuthorities = grantedAuthorities;
}
#Override
public Object getCredentials() {
return null;
}
#Override
public Object getPrincipal() {
return this.username;
}
}
Custom User Details
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class CustomUserDetails extends User implements UserDetails {
private Collection<? extends GrantedAuthority> authorities;
public CustomUserDetails(final User user, Collection<? extends GrantedAuthority> authorities) {
super(user);
this.authorities = authorities;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
#Override
public String getUsername() {
return super.getUsername();
}
#Override
public String getPassword() {
return super.getPassword();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
User
import javax.persistence.*;
import lombok.Data;
#Entity
#Data
public class User {
public User() {}
public User(String username, String pass, String role) {
this.username = username;
this.password = pass;
this.role = role;
}
public User(User username) {
this.email = username.getEmail();
this.password = username.getPassword();
this.premium = username.getPremium();
this.storedBytes = username.getStoredBytes();
this.username = username.getUsername();
}
#Id
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
#Column(name = "premium")
private int premium;
#Column(name = "storedbytes")
private int storedBytes;
#Column(name = "role")
private String role;
}
User Detail Service
import com.schachte.asciiphile.model.CustomUserDetails;
import com.schachte.asciiphile.model.User;
import com.schachte.asciiphile.repository.UserRepo;
import org.springframework.beans.factory.annotation.Autowired;
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.stereotype.Service;
import java.util.Optional;
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepo applicationUserRepository;
public UserDetailsServiceImpl(UserRepo applicationUserRepository) {
this.applicationUserRepository = applicationUserRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> applicationUser = applicationUserRepository.findByUsername(username);
if (!applicationUser.isPresent()) {
throw new UsernameNotFoundException(username);
}
return new CustomUserDetails(applicationUser.get(), AuthorityUtils
.commaSeparatedStringToAuthorityList(applicationUser.get().getRole()));
}
}
I have a problem, I'm testing an api with spring boot and oauth2, but when requesting the token the same is generated and sent to the browser, however when sending to the resource I only get access danied, below the codes:
ServerAuthorizationApplication
package br.com.serverAuthorization;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ServerAuthorizationApplication {
public static void main(String[] args) {
SpringApplication.run(ServerAuthorizationApplication.class, args);
}
}
AuthorizationServerConfig
package br.com.serverAuthorization.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.store.InMemoryTokenStore;
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
public static final String RESOURCE_ID = "arip";
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(new InMemoryTokenStore()).authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.checkTokenAccess("hasRole('CLIENT')");
}
#Override
public void configure(ClientDetailsServiceConfigurer client) throws Exception {
client.inMemory()
.withClient("clientapp")
.secret("123456")
.authorizedGrantTypes("password")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.and()
.withClient("clientcred")
.secret("123456")
.authorizedGrantTypes("client_credentials")
.scopes("trust")
.resourceIds(RESOURCE_ID)
.and()
.withClient("clientauthcode")
.secret("123456")
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.and()
.withClient("jsclient")
.secret("123456")
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.authorities("CLIENT")
.redirectUris("http://localhost:8080/contacts")
.accessTokenValiditySeconds(3600)
.autoApprove(true);
}
}
ResourceServerConfig
package br.com.serverAuthorization.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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.RemoteTokenServices;
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
public static final String RESOURCE_ID = "arip";
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/contacts").hasRole("ADMIN");
//http.authorizeRequests().antMatchers("/api/staff").hasRole("STAFF");
//http.authorizeRequests().antMatchers("/api/client").access("#oauth2.hasScope('trust')");
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
RemoteTokenServices tokenService = new RemoteTokenServices();
tokenService.setClientId("jsclient");
tokenService.setClientSecret("123456");
tokenService.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
resources.resourceId(RESOURCE_ID).tokenServices(tokenService);
}
}
SecurityConfig
package br.com.serverAuthorization.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("passw0rd").roles("ADMIN");
auth.inMemoryAuthentication().withUser("staff").password("passw0rd").roles("STAFF");
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/contacts").authenticated();
}
}
HomeController
package br.com.serverAuthorization.controllers;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import br.com.serverAuthorization.models.Contact;
#RestController
#RequestMapping("/contacts")
public class HomeController {
private List<Contact> listContact = new ArrayList<Contact>();
#GetMapping
public ResponseEntity<Principal> listAll(Principal user){
System.out.println("Entro");
listContact.add(new Contact(1, "Marcos Paulo Souza Miranda", "marcospsmiranda#gmail.com"));
listContact.add(new Contact(2, "João Pedro Souza Miranda", "joaopedro#gmail.com"));
listContact.add(new Contact(3, "Radames Aurelio Miranda", "radames#gmail.com"));
listContact.add(new Contact(4, "Lucelia de Souza Silva Miranda", "lucelia#gmail.com"));
return new ResponseEntity<>(user, HttpStatus.OK);
}
}
Contact
package br.com.serverAuthorization.models;
public class Contact {
private Integer id;
private String nome;
private String email;
public Contact(Integer id, String nome, String email) {
super();
this.id = id;
this.nome = nome;
this.email = email;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}