How can I add newly signed up user in the Spring boot security config? - spring

I am working Spring-Boot, Spring Security with basic Authentication. I will send login url from my client application written in AngularJS via RESTful API call.
Everything works as expected. All the users in the DB configured in the SecurityConfiguration.java as below.
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
List<User> users = userService.getUsers();
for (User user : users) {
auth.inMemoryAuthentication().withUser(user.getUserName()).password(user.getPassword())
.roles(user.getRole().getName());
}
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/server/rest/secure/**")
.hasRole("ADMIN").and()
.httpBasic().realmName(REALM).authenticationEntryPoint(getBasicAuthEntryPoint());
}
#Bean
public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint() {
return new CustomBasicAuthenticationEntryPoint();
}
CustomBasicAuthenticationEntryPoint.java
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
public class CustomBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
#Override
public void commence(final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName() + "");
PrintWriter writer = response.getWriter();
writer.println("HTTP Status 401 : " + authException.getMessage());
response.setHeader("WWW-Authenticate", "FormBased");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
#Override
public void afterPropertiesSet() throws Exception {
setRealmName("MY_TEST_REALM");
super.afterPropertiesSet();
}
}
So If I signup a new user which will inserted in the DB but not added in the above implementation. So authentication fails.
How can refresh the above implementation whenever i'm and doing signup of a new user

When doing authentication with db, you should do the following:
#Service("userDetailsService")
#Transactional
public class MUserDetailService implements UserDetailsService {
#Autowired
AppUserDao appUserDao;
#Override
public UserDetails loadUserByUsername(final String appUserName) throws UsernameNotFoundException {
AppUser appUser = appUserDao.findByName(appUserName);
if (appUser == null) throw new UsernameNotFoundException(appUserName);
else{
return new User(appUser.getUsername(),appUser.getPassword(),appUser.getActive(),true,true,true,getGrantedAuthorities(appUser));
}
}
private List<GrantedAuthority> getGrantedAuthorities(AppUser appUser){
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (Authority authority : appUser.getAuthorities()){
authorities.add(new SimpleGrantedAuthority(authority.getAuthorityName()));
}
return authorities;
}
}
and then define SecurityConfiguration as follows:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Autowired
#Qualifier("userDetailsService")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
}

Related

My authentication exceptions are not handled

I am currently trying to create a fullstack app, with Angular 14 and spring boot,
i am stack with authentication.
my problem is that i use my own form to get the password and the username from the user, then trying to authenticate in the backend, i created an Authentication Filter, in which i override the attemptAuthentication() method, which recives a JSON object containing the username and password,
Then i test if the username exists if not i throw UserNotFoundException , if the password is wrong i throw BadCredentialsException then if everything went well i return an authentication object, here is the method:
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
// JSON body authentication
try {
System.err.println("attempting authentication");
LoginBody loginBody = new ObjectMapper().readValue(request.getInputStream(), LoginBody.class);
AppUser user = this.userService.loadUserByUsername(loginBody.getUsername());
if (user == null) {
throw new UserNotFoundException("No user with this username") {
};
}
if ( user.getPassword().equals(passwordEncoder.encode(loginBody.getPassword()))) {
throw new BadCredentialsException("Bad credentials") {
};
}
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginBody.getUsername(),loginBody.getPassword()));
} catch (Exception e) {
System.err.println(e.getMessage());
throw new AuthenticationException(e.getMessage()) {
} ;
}
i have created an exeption handler which works fine for my controller methods whith have the endpoint /api/... , but not for the authentication with the endpoint /auth/login, all it returns is the HTTP status 403 (forbidden) like in this image
here is my exception handler class
package com.webapps.Focus.exceptions;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
#ControllerAdvice
public class UserExceptionController {
#ExceptionHandler(value = UserNotFoundException.class)
public ResponseEntity<Object> exception(UserNotFoundException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.NOT_FOUND);
}
#ExceptionHandler(value = BadCredentialsException.class)
public ResponseEntity<Object> exception(BadCredentialsException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
}
}
I appreciate your help.
According to this article, Exceptionhandler doesn't handle spring security exceptions, like AuthenticationException, hence nothing except UNAUTHORIZED status is shown as an answer,
one solution is to create a customized implementation for AuthenticationFailureHandler interface, then override onAuthenticationFailureonAuthenticationFailure() method, in which you use your own exception handling like in this example:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
#Component("userAuthFailureHandler")
public class UserAuthenticationFailureHandler implements AuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception)
throws IOException, ServletException {
try {
Map<String, String> status = new HashMap<>();
status.put("status", HttpStatus.UNAUTHORIZED.toString());
status.put("value", HttpStatus.UNAUTHORIZED.value() + "");
status.put("reason", HttpStatus.UNAUTHORIZED.getReasonPhrase());
status.put("error", exception.getMessage());
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
new ObjectMapper().writeValue(response.getOutputStream(), status);
}catch (Exception e) {
throw e;
}
}
}
Then in SecurityConfig class, consider injecting a bean with Qualifier("userAuthFailureHandler") , then set the attribute AuthenticationFailureHandler of your AuthenticationFilter to that bean:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
private AuthenticationFailureHandler failureHandler;
private AuthenticationEntryPoint authEntryPoint;
public SecurityConfig(...
#Qualifier("delegatedAuthenticationEntryPoint") AuthenticationEntryPoint authEntryPoint,
#Qualifier("userAuthFailureHandler")AuthenticationFailureHandler failureHandler) {
...
this.authEntryPoint = authEntryPoint;
this.failureHandler = failureHandler;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// configure the stateless authentication
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
...
JWTAuthenticationFilter authenticationFilter = new JWTAuthenticationFilter(authenticationManagerBean(), userService, passwordEncoder);
authenticationFilter.setFilterProcessesUrl("/auth/login");
authenticationFilter.setAuthenticationFailureHandler(this.failureHandler);
http.addFilter(authenticationFilter);
http.addFilterBefore(new JWTAuthorisationFilter(), UsernamePasswordAuthenticationFilter.class);
// allow security exceptions handling to component with qualifier delegatedAuthenticationEntryPoint
http.exceptionHandling().authenticationEntryPoint(authEntryPoint);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
Then delegate security exception handling to your ow implementation of AuthenticationEntryPoint like below
//This class will help handle security exceptions that couldn't be handled by ControllerAdvice
#Component("delegatedAuthenticationEntryPoint")
public class DelegatedAuthenticationEntryPoint implements AuthenticationEntryPoint {
private HandlerExceptionResolver resolver;
public DelegatedAuthenticationEntryPoint( #Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
this.resolver = resolver;
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
resolver.resolveException(request, response, null, authException);
}
}
I had the same problem. It happened because of anyRequest().authenticated() in Security Configuration: "/error" page is blocked too. So u should write something like this: authorizeHttpRequests(auth -> auth.requestMatchers("/error").permitAll() or authorizeHttpRequests().requestMatchers("/error").permitAll() as you wish.

401 Unauthorized on every Request made to REST API [duplicate]

This question already has an answer here:
Custom security is not working when extending the WebSecurityConfigurerAdapter class in different package
(1 answer)
Closed 3 years ago.
I get a 401 unauthorized no matter what ever the request I try. I am even unable to get into #PostMapping("/signup") and print to the console. Spring doesn't show any errors. I only get 401 unauthorized when I try POST to signup with PostMan. Here, I am posting the code for WebSecurityConfig and REST Controller to signup with my REST API.
To access the whole code, please visit https://github.com/BhargaviNadendla/Discussion-Forum--Spring-Boot-Angular
WebSecurityConfig.java:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
prePostEnabled = true
)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsServiceImpl userDetailsService;
#Autowired
private JwtAuthEntryPoint unauthorizedHandler;
#Bean
public JwtAuthTokenFilter authenticationJwtTokenFilter() {
return new JwtAuthTokenFilter();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().
authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().formLogin().disable();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
RestController:
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
#RequestMapping("/api/auth")
public class AuthRestAPIs {
#Autowired
AuthenticationManager authenticationManager;
#Autowired
UserDAO userRepository;
#Autowired
RoleDAO roleRepository;
#Autowired
PasswordEncoder encoder;
#Autowired
JwtProvider jwtProvider;
#PostMapping("/signin")
public ResponseEntity<?> authenticateUser(#Valid #RequestBody LoginForm loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtProvider.generateJwtToken(authentication);
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
return ResponseEntity.ok(new JwtResponse(jwt, userDetails.getUsername(), userDetails.getAuthorities()));
}
#PostMapping("/signup")
public ResponseEntity<?> registerUser(#Valid #RequestBody SignUpForm signUpRequest) {
System.out.println("In rest----------------------------------");
if (userRepository.existsByUsername(signUpRequest.getUsername())) {
return new ResponseEntity<>(new ResponseMessage("Fail -> Username is already taken!"),
HttpStatus.BAD_REQUEST);
}
if (userRepository.existsByEmail(signUpRequest.getEmail())) {
return new ResponseEntity<>(new ResponseMessage("Fail -> Email is already in use!"),
HttpStatus.BAD_REQUEST);
}
// Creating user's account
User user = new User(signUpRequest.getName(), signUpRequest.getUsername(), signUpRequest.getEmail(),
encoder.encode(signUpRequest.getPassword()));
Set<String> strRoles = signUpRequest.getRole();
Set<Role> roles = new HashSet<>();
strRoles.forEach(role -> {
switch (role) {
case "admin":
Role adminRole = roleRepository.findByName(RoleName.ROLE_ADMIN)
.orElseThrow(() -> new RuntimeException("Fail! -> Cause: User Role not find."));
roles.add(adminRole);
break;
default:
Role userRole = roleRepository.findByName(RoleName.ROLE_USER)
.orElseThrow(() -> new RuntimeException("Fail! -> Cause: User Role not find."));
roles.add(userRole);
}
});
user.setRoles(roles);
userRepository.save(user);
return new ResponseEntity<>(new ResponseMessage("User registered successfully!"), HttpStatus.OK);
}
}
AuthTokenFilter.java
package com.springboot.forumforall.jwtauth.security.jwt;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;
import com.springboot.forumforall.jwtauth.security.services.UserDetailsServiceImpl;
public class JwtAuthTokenFilter extends OncePerRequestFilter {
#Autowired
private JwtProvider tokenProvider;
#Autowired
private UserDetailsServiceImpl userDetailsService;
private static final Logger logger = LoggerFactory.getLogger(JwtAuthTokenFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
String jwt = getJwt(request);
if (jwt != null && tokenProvider.validateJwtToken(jwt)) {
String username = tokenProvider.getUserNameFromJwtToken(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
logger.error("Can NOT set user authentication -> Message: {}", e);
}
filterChain.doFilter(request, response);
}
private String getJwt(HttpServletRequest request) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
return authHeader.replace("Bearer ", "");
}
return null;
}
}
Your problem is here:
#Override
protected void configure(HttpSecurity http) throws Exception {
http...
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
..
}
Which sould be:
#Override
protected void configure(HttpSecurity http) throws Exception {
http...
.anyRequest().authenticated()
.antMatchers("/api/auth/**").permitAll()
..
}

Spring boot security get username and password from authentication login to access rest services

I am new to Spring. Client requests to access the rest services, giving username and password in http login provided by Spring, as shown in the image. I don't want to save credentials('username and password') in the application.properties. When I provide the credentials and enter login button, I need to read data (in my case username-'root' and pwd-'root') provided by the user from login and use it in my algorithm, do the process and then authenticate. Is there a way?
Please help me, if anyone has any idea.
authentication login screen
Here is my sample code:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private MyBasicAuthenticationEntryPoint authEntryPoint;
#Autowired
private MyUserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// auth.inMemoryAuthentication().withUser("user1").password("user1Pass").roles("ADMIN")
// .and().withUser("user2").password("user2Pass").roles("ADMIN");
auth.authenticationProvider(authenticationProvider());
}
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
// provider.setPasswordEncoder(new BCryptPasswordEncoder());
return provider;
}
// I am trying like this but not sure is this the right way
public void details(User user) {
String name = user.getName();
String password = user.getPassword();
System.out.println("name " + name + "password" + password);
}
// I am trying like this but not sure is this the right way
public void userDetails(UsernamePasswordAuthenticationFilter filter) {
String usernameParameter = filter.getUsernameParameter();
System.out.println(usernameParameter);
String passwordParameter = filter.getPasswordParameter();
System.out.println(passwordParameter);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated();
http.httpBasic().authenticationEntryPoint(authEntryPoint);
}
}
#Component
public class MyBasicAuthenticationEntryPoint extends
BasicAuthenticationEntryPoint{
#Override
public void commence(HttpServletRequest request, HttpServletResponse
response,
AuthenticationException authException) throws IOException,
ServletException {
response.addHeader("WWW-Authenticate", "Basic realm=" +
getRealmName());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter printWriter= response.getWriter();
printWriter.println("Http Status 401-" + authException.getMessage());
}
#Override
public void afterPropertiesSet() throws Exception {
//RealName appears in the login window
setRealmName("Rashmi");
super.afterPropertiesSet();
}
}
#SpringBootApplication
public class SpringRestfulWebServiceApplication extends
SpringBootServletInitializer {
#Autowired
CustomerDetailsController customerDetailsController;
public static void main(String[] args) {
SpringApplication.run(SpringRestfulWebServiceApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder
application) {
return application.sources(SpringRestfulWebServiceApplication.class);
}
}

Spring Security Always returning 403 forbidden, Access denied

I want to enable admin to access admin page and do admin stuff, but when I try to do that by setting that the url with /admin/** can only be accessed by user with role admin, it returns 403 Forbidden, access denied. But the user has authorities set to ROLE_ADMIN I checked. What am I doing wrong?
My Controller for user login
#RestController
public class UserController {
#Autowired
AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private AuthorityService authorityService;
#Autowired
private UserAuthorityService userAuthorityService;
#Autowired
TokenUtils tokenUtils;
#Autowired
private UserService userService;
#RequestMapping(value = "/api/login", method = RequestMethod.POST, produces = "text/html")
public ResponseEntity<String> login(#RequestBody LoginDTO loginDTO) {
try {
// System.out.println(loginDTO.getUsername() + " " + loginDTO.getPassword());
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
loginDTO.getUsername(), loginDTO.getPassword());
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
UserDetails details = userDetailsService.loadUserByUsername(loginDTO.getUsername());
return new ResponseEntity<String>(tokenUtils.generateToken(details), HttpStatus.OK);
} catch (Exception ex) {
return new ResponseEntity<String>("Invalid login", HttpStatus.BAD_REQUEST);
}
}
#RequestMapping(value = "/api/register", method = RequestMethod.POST, produces = "text/html")
public ResponseEntity<String> register(#RequestBody RegisterDTO registerDTO) {
try {
System.out.println(registerDTO);
User user = userService.findUserByUsername(registerDTO.getUsername());
// // Check if user with that username exists
if(user != null){
// User with that username is found
return new ResponseEntity<String>("User with that username exists", HttpStatus.BAD_REQUEST);
}
// We need to save the user so his ID is generated
User newUser = userService.saveUser(new User(registerDTO));
UserAuthority userAuthority = userAuthorityService.save(new UserAuthority(newUser, authorityService.findOneByName("User")));
Set<UserAuthority> authorities = new HashSet<>();
authorities.add(userAuthority);
newUser.setUserAuthorities(authorities);
User savedUser = userService.save(newUser);
return new ResponseEntity<String>("You have registered successfully with username " + savedUser.getUsername(), HttpStatus.OK);
} catch (Exception ex) {
return new ResponseEntity<String>("Invalid register", HttpStatus.BAD_REQUEST);
}
}
}
I can say that I test my app with postman and login and registration are working fine. When the user is logged in I can the token with the correct data and users authorities, but why when I try to access /admin/building/add url it is returning 403 error?
My Controller for adding building for admin page:
#RestController
public class BuildingController {
#Autowired
private BuildingService buildingService;
#RequestMapping(value = "/admin/building/add", method = RequestMethod.POST, produces = "text/html")
public ResponseEntity<String> addBuilding(#RequestBody BuildingDTO buildingDTO) {
try{
Building newBuilding = new Building(buildingDTO);
return new ResponseEntity<String>(newBuilding.getName(), HttpStatus.OK);
}catch (Exception ex) {
return new ResponseEntity<String>("Data was not valid", HttpStatus.BAD_REQUEST);
}
}
}
My SecurityConfiguration.java
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configureAuthentication(
AuthenticationManagerBuilder authenticationManagerBuilder)
throws Exception {
authenticationManagerBuilder
.userDetailsService(this.userDetailsService).passwordEncoder(
passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public AuthenticationTokenFilter authenticationTokenFilterBean()
throws Exception {
AuthenticationTokenFilter authenticationTokenFilter = new AuthenticationTokenFilter();
authenticationTokenFilter
.setAuthenticationManager(authenticationManagerBean());
return authenticationTokenFilter;
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/index.html", "/view/**", "/app/**", "/", "/api/login", "/api/register").permitAll()
// defined Admin only API area
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest()
.authenticated()
.and().csrf().disable();
//if we use AngularJS on client side
// .and().csrf().csrfTokenRepository(csrfTokenRepository());
//add filter for adding CSRF token in the request
httpSecurity.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
// Custom JWT based authentication
httpSecurity.addFilterBefore(authenticationTokenFilterBean(),
UsernamePasswordAuthenticationFilter.class);
}
/**
* If we use AngularJS as a client application, it will send CSRF token using
* name X-XSRF token. We have to tell Spring to expect this name instead of
* X-CSRF-TOKEN (which is default one)
* #return
*/
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
I should mention that I am using Angularjs for frontend, but even so I can login and the correct authorities are displayed for that user. But for some reason I can not access the admin page, even if I login as admin.
Also I tried .hasAuthority("ROLE_ADMIN") and .hasRole("ROLE_ADMIN")(which displays an error for ROLE_) and so I changed it to .hasRole("ADMIN") but it is still not working.
In the database the role for admin is saved as ROLE_ADMIN.
Try like this :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.config.http.SessionCreationPolicy;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private static String REALM="MY_TEST_REALM";
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("ADMIN");
auth.inMemoryAuthentication().withUser("tom").password("abc123").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/user/**").hasRole("ADMIN")
.and().httpBasic().realmName(REALM).authenticationEntryPoint(getBasicAuthEntryPoint())
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//We don't need sessions to be created.
}
#Bean
public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
return new CustomBasicAuthenticationEntryPoint();
}
/* To allow Pre-flight [OPTIONS] request from browser */
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
}
For a complet configuration example : Secure Spring REST API using Basic Authentication
import org.springframework.context.annotation.Configuration;
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
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();// We don't need sessions to be created.
}
}
This did it for me. Now I am able to submit my post requests successfully
Try this in SecurityConfig:
.antMatchers("/api/admin").access("hasRole('ADMIN')")
.antMatchers("/api/user").access("hasRole('ADMIN') or hasRole('USER')")

Spring boot basic authentication

I'm using spring boot security to help me to make authentication...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and().csrf().disable().authorizeRequests()
.anyRequest().authenticated().and().httpBasic();
}
}
I have a rest service to make login (on my controller) thats a post request that i send email and password and i like to use this service to make the authentication...
But i'm new on spring-boot / java... Can some one help me to make that right way?
Thanks.
You need to permit access to the login endpoint (at least). E.g.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login", "/error").permitAll()
.antMatchers("/**").authenticated().and().exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"));
}
If I were you I would remove the #EnableWebSecurity (and let Spring Boot do it's job) as well. And then in the login endpoint you need to set the security context, e.g.
#PostMapping
public void authenticate(#RequestParam Map<String, String> map,
HttpServletRequest request, HttpServletResponse response) throws Exception {
Authentication result = authService.authenticate(map.get("username"), map.get("password"));
SecurityContextHolder.getContext().setAuthentication(result);
handler.onAuthenticationSuccess(request, response, result);
}
The authService should throw BadCredentialsException if the user cannot be authenticated. Here's a sample app that I used in a blog once: https://github.com/dsyer/mustache-sample/blob/7be8459173d0b65b6d44d05f86e581d358ea9b2e/src/main/java/com/example/DemoApplication.java#L177
Change add method in SpringSecurityConfig.java like Below
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserAuthenticationService userAuthenticationService;
#Autowired
private CustomAuthenticationProvider authenticationProvider;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(this.authenticationProvider).userDetailsService(this.userAuthenticationService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and().csrf().disable().authorizeRequests()
.anyRequest().authenticated().and().httpBasic();
}}
Create CustomAuthenticationProvider.
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private UserAuthenticationService userAuthenticationService;
#Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String emailId = authentication.getName();
String password = (String) authentication.getCredentials();
UserDetails user = this.userAuthenticationService.loadUserByUsername(emailId);
if (user == null) {
throw new UsernameNotFoundException("Username not found.");
}
//Your password encoder here
if (!password.equals(user.getPassword())) {
throw new UsernameNotFoundException("Wrong password.");
}
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
return new UsernamePasswordAuthenticationToken(user, password, authorities);
}}
Create Custom UserService
#Service
public class UserAuthenticationService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmailAddressWithRole(email);
if (user == null) {
throw new UsernameNotFoundException("Username not found for " + email);
}
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
for (Role roles : user.getRoles()) {
grantedAuthorities.add(new SimpleGrantedAuthority(roles.getRoleName()));
}
return new UserAuthenticationWrapperDto(user.getId(), user.getEmailAddress(), user.getPassword(),
user.getUserType(), user.getCompany().getId(), grantedAuthorities,user.getName());
}}

Resources