Spring Security roles are not working - spring

I have configured spring security in my app,authentication is working well but authorization is not working mean #secured() annotation is not working.i am getting error when i access url "There was an unexpected error (type=Forbidden, status=403).
Access is denied".
My spring config is
#Autowired
private MongoDBAuthenticationProvider authenticationProvider;
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().defaultSuccessUrl("/resource")
.and().logout().and().authorizeRequests()
.antMatchers("/logout").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest()
.authenticated()
.and().csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
My controller is
#RestController
#RequestMapping("/user")
public class UserController {
#Autowired
UserService userService;
#Secured(value={"ROLE_ADMIN"})
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public void getUser() {
System.out.println("working");
}
}
Database user is
{ "_id" : ObjectId("555982a5360403572551660c"), "username" : "user", "password" : "pass", "role" : "ADMIN" }
My mongodb auth provider
#Service
public class MongoDBAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider{
#Autowired
MongoUserDetailsService mongoUserDetailsService;
#Autowired MongoTemplate mongoTemplate;
#Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
}
#Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
UserDetails loadedUser;
try {
loadedUser = mongoUserDetailsService.loadUserByUsername(username);
} catch (Exception repositoryProblem) {
throw new InternalAuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
}
if (loadedUser == null) {
throw new InternalAuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
}
User domain
public class User {
#Id
private String id;
#NotNull
private String name;
private int age;
private String username;
private String password;
private String role;
public User() {
super();
}
public User(String name,String username,
String password, String role) {
super();
this.name = name;
this.username = username;
this.password = password;
this.role = role;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
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 String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}

Add this bean in Spring Security Config File
#Bean
public RoleVoter roleVoter() {
RoleVoter roleVoter = new RoleVoter();
roleVoter.setRolePrefix("");
return roleVoter;
}
And write secured annotation like this
#Secured(value={"ADMIN"})

#Secured(value={"ADMIN"})
Instead of
#Secured(value={"ROLE_ADMIN"})
You also could try
#PreAuthorize("hasRole('ADMIN')")
If #Secured annotation still doesn't work

Related

Spring security authentication fails with Custom user

I am trying to authenticate with Custom User that implements UserDetails. Here is my custome User class. (This class is also extended by other classes like Citizen and Employee as well).
#Entity
#Table(name = "user")
#Inheritance(strategy = InheritanceType.JOINED)
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Integer id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
#Column(name = "phone")
private String phone;
#Column(name = "address")
private String address;
#Column(name = "status")
private boolean isActive;
#CreationTimestamp
#Column(name = "created_at")
private LocalDate createdAt;
#UpdateTimestamp
#Column(name = "updated_at")
private LocalDate updatedAt;
#Transient
private Set<GrantedAuthority> authorityList;
#ManyToMany
#JoinTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "id"))
private Set<Role> roles;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return false;
}
#Override
public boolean isAccountNonLocked() {
return false;
}
#Override
public boolean isCredentialsNonExpired() {
return false;
}
#Override
public boolean isEnabled() {
return false;
}
public void setUsername(String username) {
this.username = username;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorityList;
}
#Override
public String getPassword() {
return password;
}
public void setAuthorityList(Set<GrantedAuthority> authorityList) {
this.authorityList = authorityList;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public boolean isActive() {
return isActive;
}
public void setActive(boolean active) {
isActive = active;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public LocalDate getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDate createdAt) {
this.createdAt = createdAt;
}
public LocalDate getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDate updatedAt) {
this.updatedAt = updatedAt;
}
}
Also I have implemented UserDetailsService as
#Service
public class UserDetailsServiceImpl implements UserDetailsService{
#Autowired
private UserRepository userRepository;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
for (Role role : user.getRoles()){
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
}
user.setAuthorityList(grantedAuthorities);
return user;// new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
}
And WebSecurityConfig as
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsServiceImpl userDetailsService;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/registration", "/newreport", "/login*", "/signin/**", "/signup/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.csrf().disable()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login").permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
#Override
protected UserDetailsService userDetailsService() {
return userDetailsService;
}
}
Authentication works find if i return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities); inside UserDetailsServiceImpl.
But as soon i return User class object user. Authentication fails.
I am not sure what i am missing here. Any help would be appreciated. Thanks in advance.
Because your UserDetails implementation always return false for the following methods:
#Override
public boolean isAccountNonExpired() {
return false;
}
#Override
public boolean isAccountNonLocked() {
return false;
}
#Override
public boolean isCredentialsNonExpired() {
return false;
}
#Override
public boolean isEnabled() {
return false;
}
In order to pass the authentication , all the above methods should return true.

I am unable to generate access token?

I am applying spring security in my project...and
I have a problem in my access token generation?
How can I generate access token ??
UserPrincipal
public class UserPrincipal implements UserDetails {
private Long id;
private String username;
private String emailAddress;
private String password;
private String phoneNumber;
private String age;
private String bio;
private String sex;
private String occupation;
private String partySupport;
private Date joiningDate;
private String status;
private Address address;
private Collection<? extends GrantedAuthority> authorities;
public UserPrincipal(Long id, String username, String emailAddress, String password, String phoneNumber, String age, String bio, String sex, String occupation, String partySupport, Date joiningDate, String status, Address address, Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.username = username;
this.emailAddress = emailAddress;
this.password = password;
this.phoneNumber = phoneNumber;
this.age = age;
this.bio = bio;
this.sex = sex;
this.occupation = occupation;
this.partySupport = partySupport;
this.joiningDate = joiningDate;
this.status = status;
this.address = address;
this.authorities = authorities;
}
public static UserPrincipal create(User user)
{
List<GrantedAuthority> authorities = user.getRoles().stream().map(role ->
new SimpleGrantedAuthority(role.getName().name())
).collect(Collectors.toList());
return new UserPrincipal(
user.getId(),
user.getUsername(),
user.getEmailAddress(),
user.getPassword(),
user.getPhoneNumber(),
user.getAge(),
user.getBio(),
user.getSex(),
user.getOccupation(),
user.getPartySupport(),
user.getJoiningDate(),
user.getStatus(),
user.getAddress(),
authorities
);
}
public Long getId() {
return id;
}
public String getEmailAddress() {
return emailAddress;
}
public String getPhoneNumber() {
return phoneNumber;
}
public String getAge() {
return age;
}
public String getBio() {
return bio;
}
public String getSex() {
return sex;
}
public String getOccupation() {
return occupation;
}
public String getPartySupport() {
return partySupport;
}
public Date getJoiningDate() {
return joiningDate;
}
public String getStatus() {
return status;
}
public Address getAddress() {
return address;
}
#Override
public String getUsername() {
return username;
}
#Override
public String getPassword() {
return password;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserPrincipal that = (UserPrincipal) o;
return Objects.equals(id, that.id);
}
#Override
public int hashCode() {
return Objects.hash(id);
}
}
UserController
#RestController
#RequestMapping("/api")
#CrossOrigin(value = "http://localhost:4200", allowedHeaders = "*")
#Configuration
public class UserController {
#Autowired
private UserService userService;
#Autowired
private UserRepository userRepository;
#Autowired
private PollRepository pollRepository;
#Autowired
private VoteRepository voteRepository;
#Autowired
private PollService pollService;
private Object model;
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
#GetMapping("/user/all")
#PreAuthorize("hasRole('ADMIN')")
public List<User> getUsers() {
return userService.getUsers();
}
#GetMapping("/user/getCount")
#PreAuthorize("hasRole('ADMIN')")
public HashMap<String, String> getCount() {
int totalUsers = getUsers().size();
int activeUsers = userService.getCountByActive();
int inactiveUsers = userService.getCountByInactive();
HashMap<String, String> userStatus = new HashMap<>();
userStatus.put("Total",String.valueOf(totalUsers));
userStatus.put("Active", String.valueOf(activeUsers));
userStatus.put("Inactive",String.valueOf(inactiveUsers));
System.out.println(userStatus);
// System.out.println("Inactive Users" + inactiveUsers);
return userStatus;
}
#GetMapping("/user/{id}")
#PreAuthorize("hasRole('ADMIN')")
public Optional<User> getUser(#PathVariable Long id) {
return userService.getUser(id);
}
#DeleteMapping("/user/{id}")
#PreAuthorize("hasRole('ADMIN')")
public boolean deleteUser(#PathVariable Long id) {
userService.deleteUser(id);
return true;
}
#PutMapping("/user")
#PreAuthorize("hasRole('ADMIN')")
public User updateUser(#RequestBody User user) {
return userService.updateUser(user);
}
#PostMapping("/user")
public String createUser(#RequestBody User user) {
System.out.print("Email Address :" + user.getEmailAddress());
User user1 = userService.createUser(user);
if (user1 != null) {
return "success";
} else {
return "failed";
}
}
SecurityConfig
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
CustomUserDetailsService customUserDetailsService;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean(BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
DefaultHttpFirewall firewall = new DefaultHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
return firewall;
}
#Override
public void configure(WebSecurity web) throws Exception {
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability")
.permitAll()
.antMatchers(HttpMethod.GET, "/api/polls/**", "/api/user/**")
.permitAll()
.anyRequest()
.authenticated();
// Add our custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
i tried in postman but there is an error 401 unauthorized shown..
i dont know what is the miss part which i have not added??
can anyone please suggest me what should i do??
Thanks in Advance!

Spring security with JWT always returns 401 unauthorized

1
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Resource(name = "userService")
private UserDetailsService userDetailsService;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
/*auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select login as principal, mot_de_passe as credentials, flag_compte_actif as enabled from utilisateur where login = ?")
.authoritiesByUsernameQuery("SELECT utilisateur.login as principal, profil.designation as role FROM utilisateur INNER JOIN user_profil ON utilisateur.id_user = user_profil.iduserpk INNER JOIN profil ON user_profil.idprofilpk = profil.id_profil WHERE utilisateur.login = ? ")
.rolePrefix("ROLE_");
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());*/
auth.inMemoryAuthentication()
.withUser("admin")
.password("password")
.roles("Administrateur");
}
#Bean
public JwtAuthenticationFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationFilter();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("Akal configure method begin");
//http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
http.cors().and()
.csrf().disable().
authorizeRequests()
.antMatchers("/token/generate").permitAll()
.anyRequest().authenticated()
.and().formLogin().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
System.out.println("Akal configure method");
http
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
// #Bean
// public BCryptPasswordEncoder passwordEncoder(){
// return new BCryptPasswordEncoder();
// }
#Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
}
2
#RestController
#CrossOrigin("*")
public class AuthenticationController {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Autowired
private UtilisateurRepository userRepo;
#PostMapping(value = "/token/generate")
public ResponseEntity<?> register(#RequestBody LoginUser loginUser) throws AuthenticationException {
System.out.println("We're in man!");
final Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
loginUser.getUsername(),
loginUser.getPassword()
)
);
System.out.println("(Username, Password): (" + loginUser.getUsername() + ", " + loginUser.getPassword() + ")");
SecurityContextHolder.getContext().setAuthentication(authentication);
final Utilisateur user = userRepo.findByLogin(loginUser.getUsername());
final String token = jwtTokenUtil.generateToken(user);
System.out.println("Token Controller Access=> Token Generated: " + token);
return ResponseEntity.ok(new AuthToken(token));
}
}
3
public class AuthToken {
private String token;
public AuthToken(){
}
public AuthToken(String token){
this.token = token;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
4
public class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
System.out.println("Filtering on...........................................................");
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
//response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Authorization, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
5
#Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
#Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
6
public class JwtAuthenticationFilter extends OncePerRequestFilter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
String header = req.getHeader("Authorization");
String username = null;
String authToken = null;
if (header != null && header.startsWith("Bearer ")) {
authToken = header.replace("Bearer ","");
try {
username = jwtTokenUtil.getUsernameFromToken(authToken);
} catch (IllegalArgumentException e) {
logger.error("an error occured during getting username from token", e);
} catch (ExpiredJwtException e) {
logger.warn("the token is expired and not valid anymore", e);
} catch(SignatureException e){
logger.error("Authentication Failed. Username or Password not valid.");
}
} else {
logger.warn("couldn't find bearer string, will ignore the header");
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN")));
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(req));
logger.info("authenticated user " + username + ", setting security context");
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(req, res);
}
}
7
#Component
public class JwtTokenUtil implements Serializable {
static final long EXPIRATIONTIME = 864_000_000; // 10 days
static final String SECRET = "secret";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
public String generateToken(Utilisateur user) {
return doGenerateToken(user.getLogin());
}
private String doGenerateToken(String subject) {
Claims claims = Jwts.claims().setSubject(subject);
claims.put("scopes", Arrays.asList(new SimpleGrantedAuthority("ROLE_Administrateur")));
return Jwts.builder()
.setClaims(claims)
.setIssuer("http://devglan.com")
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
.signWith(SignatureAlgorithm.HS256, SECRET)
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (
username.equals(userDetails.getUsername())
&& !isTokenExpired(token));
}
}
8
public class LoginUser {
private String username;
private String password;
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;
}
}
I only posted these 2 classes, because honestly I have 8 configuration classes, it's gonna be a pain to read! And it's custom JWT code too, but if it's necessary to post it all, let me know.
Other than that, I just cannot identify the problem! Spring console doesn't show any errors whatsoever and when I try to request from Postman, here the outcome:
result
And when I run the request from the browser, it doesn't say 401, it just says bad credentials even though they're correct and I tried with dozens of users too to make sure
Thank you!
Update: I posted the rest of the classes because the problem might not be related to just these 2
In Spring Security 5, if you are using auth.inMemoryAuthentication(), you won't be able to use BCryptPasswordEncoder or StandardPasswordEncoder. You must use your own UserDetailsService in order to get a user and password. Or if you need to test your code, just return NoOpPasswordEncoder.getInstance() in your passwordEncoder() method
SecurityConfig.class
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AccountService accountService; //your own implementation of UserDetailsService
....
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(true)
.userDetailsService(accountService)
.passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
....
}
AccountService.class
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class AccountService implements UserDetailsService {
#Autowired
private AccountRepository accountRepository; //Your database repository
#Autowired
private PasswordEncoder passwordEncoder;
#PostConstruct
protected void initialize() {
save(new Account("user", "demo", "ROLE_USER"));
save(new Account("admin", "admin", "ROLE_ADMIN"));
}
#Transactional
public Account save(Account account) {
account.setPassword(passwordEncoder.encode(account.getPassword()));
accountRepository.save(account);
return account;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = accountRepository.findOneByEmail(username);
if(account == null) {
throw new UsernameNotFoundException("user not found");
}
return createUser(account);
}
public void signin(Account account) {
SecurityContextHolder.getContext().setAuthentication(authenticate(account));
}
private Authentication authenticate(Account account) {
return new UsernamePasswordAuthenticationToken(createUser(account), null, Collections.singleton(createAuthority(account)));
}
private User createUser(Account account) {
return new User(account.getEmail(), account.getPassword(), Collections.singleton(createAuthority(account)));
}
private GrantedAuthority createAuthority(Account account) {
return new SimpleGrantedAuthority(account.getRole());
}
}
Account.class
#SuppressWarnings("serial")
#Entity
#Table(name = "account")
public class Account implements java.io.Serializable {
#Id
#GeneratedValue
private Long id;
#Column(unique = true)
private String email;
#JsonIgnore
private String password;
private String role = "ROLE_USER";
private Instant created;
protected Account() {
}
public Account(String email, String password, String role) {
this.email = email;
this.password = password;
this.role = role;
this.created = Instant.now();
}
public Long getId() {
return id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public Instant getCreated() {
return created;
}
}
You are not using PasswordEncoder in your globalUserDetails() method. Spring security by default take encoded password. Your code should be like.
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(passwordEncoder)
.withUser("admin")
.password("password")
.roles("Admin");
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
You are using do not need dataSource because you are using inMemoryAuthenticatin().

Spring Starter Security not authenticating

When I add a User with "ROLE_USER" permissions, I am unable to authenticate. 401s are returned consistently when attempting to authenticate with username: "username" and password: "password".
I can see in the JSON that's output that the BCryptPasswordEncoder is encoding passwords as it should be, but regardless of whether I use the original password or encoded version, I'm still unable to authenticate.
I've been working on this for a couple of days to no avail. Is there anything I'm missing?
Code is below --
DatabaseLoader:
User user = new User("first", "last", "username", "password", "email", "phone", new String[] {"ROLE_USER"});
userRepository.save(user);
DetailsService:
#Component
public class DetailsService implements UserDetailsService {
#Autowired
UserRepository users;
#Override
public UserDetails loadUserByUsername(String userUsername) throws UsernameNotFoundException {
User user = users.findByUsername(userUsername);
if (user == null) {
throw new UsernameNotFoundException(userUsername + " was not found");
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getUserPassword(),
AuthorityUtils.createAuthorityList(user.getUserRoles())
);
}
}
WebSecurityConfig:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
DetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(User.PASSWORD_ENCODER);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
}
User:
#Entity
public class User {
public static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();
private long userId;
private String userFirstName;
private String userLastName;
private String username;
#JsonIgnore
private String userPassword;
private String userPhone;
private String userEmail;
#JsonIgnore
private String[] userRoles;
public User() {}
public User(String userFirstName, String userLastName, String username, String userPassword, String userPhone, String userEmail, String[] userRoles) {
this.userFirstName = userFirstName;
this.userLastName = userLastName;
this.username = username;
setUserPassword(userPassword);
this.userPhone = userPhone;
this.userEmail = userEmail;
this.userRoles = userRoles;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
#Column
public String getUserFirstName() {
return userFirstName;
}
public void setUserFirstName(String userFirstName) {
this.userFirstName = userFirstName;
}
#Column
public String getUserLastName() {
return userLastName;
}
public void setUserLastName(String userLastName) {
this.userLastName = userLastName;
}
#Column
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Column
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = PASSWORD_ENCODER.encode(userPassword);
}
#Column
public String getUserPhone() {
return userPhone;
}
public void setUserPhone(String userPhone) {
this.userPhone = userPhone;
}
#Column
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
#Column
public String[] getUserRoles() {
return userRoles;
}
public void setUserRoles(String[] userRoles) {
this.userRoles = userRoles;
}
}
Your question isn't very clear about problem. But i guess you are stuck in user authentication with spring starter security.
You should check this question

Does the method getUsername() of interface UserDetails indicate that there must be a attribute "username" in an entity impl the interface?

I'm studying springboot on a website. The website gives a example project for spring security, following is a part of the code:
User entity:
#Entity
public class User implements UserDetails {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotEmpty(message = "name no empty")
#Size(min=2, max=20)
#Column(nullable = false, length = 20)
private String name;
#NotEmpty(message = "email no empty")
#Size(max=50)
#Email(message= "wrong email format" )
#Column(nullable = false, length = 50, unique = true)
private String email;
#NotEmpty(message = "username no empty")
#Size(min=3, max=20)
#Column(nullable = false, length = 20, unique = true)
private String username;
#NotEmpty(message = "password no empty")
#Size(max=100)
#Column(length = 100)
private String password;
#Column(length = 200)
private String avatar;
#ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.EAGER)
#JoinTable(name = "user_authority", joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "authority_id", referencedColumnName = "id"))
private List<Authority> authorities;
protected User(){
}
public User(Long id, String name, String username, String email){
this.id = id;
this.name = name;
this.email = email;
this.username = username;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
public void setUsername(String username){
this.username = username;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> simpleAuthorities = new ArrayList<>();
for (GrantedAuthority authority : this.authorities){
simpleAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority()));
}
return simpleAuthorities;
}
public void setAuthorities(List<Authority> authorities) {
this.authorities = authorities;
}
#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 void setPassword(String password) {
this.password = password;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
#Override
public String toString(){
return String.format("User[id = %d, name = '%s', username = '%s', email = '%s']", id, name, username, email);
}
}
UserService implementation:
#Service
public class UserServiceImpl implements UserService, UserDetailsService {
#Autowired
private UserRepository userRepository;
#Transactional
#Override
public User saveOrUpdateUser(User user) {
return userRepository.save(user);
}
#Transactional
#Override
public User registerUser(User user) {
return userRepository.save(user);
}
#Transactional
#Override
public void removeUser(Long id) {
userRepository.delete(id);
}
#Override
public User getUserById(Long id) {
return userRepository.findOne(id);
}
#Override
public Page<User> listUsersByNameLike(String name, Pageable pageable) {
name = "%" + name + "%";//匹配相似
Page<User> users = userRepository.findByNameLike(name, pageable);
return users;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username);
}
}
Security Configuration:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
private static final String KEY = "waylau.com";
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder);
return authenticationProvider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/css/**", "/js/**", "/fonts/**", "/index").permitAll()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/admins/**").hasRole("ADMIN") /
.and()
.formLogin()
.loginPage("/login").failureUrl("/login-error")
.and().rememberMe().key(KEY)
.and().exceptionHandling().accessDeniedPage("/403");
http.csrf().ignoringAntMatchers("/h2-console/**");
http.headers().frameOptions().sameOrigin();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
}
What I focus is the attribute "username" of User.java. There is no problem when running codes above.
But after altered "username" to another name such as "accountname", it throws following exception
UserDetailsService returned null...
I know the problem is related to 'getUsername()'. This getter is also a overide method of UserDetails interface.
Take into consideration, the getter becomes this:
#Override
public String getUsername() {
return getAccountname();
}
But still not working. Does it mean the name of the attribute cannot be altered?

Resources