I was beginner in spring security JWT authentication, I am trying to authenticate the login using authentication controller. But when I am trying to test the api through controller I am getting 401 Unauthorized in postman
WebSecurityConfig.java
package com.cognizant.auth.microservice.config;
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.authentication.AuthenticationManager;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private UserDetailsService jwtUserDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// configure AuthenticationManager so that it knows from where to load
// user for matching credentials
// Use BCryptPasswordEncoder
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// We don't need CSRF for this example
httpSecurity.csrf().disable()
// dont authenticate this particular request
.authorizeRequests().antMatchers("/authenticate").permitAll().antMatchers(HttpMethod.OPTIONS, "/**")
.permitAll().
// all other requests need to be authenticated
anyRequest().authenticated().and().
// make sure we use stateless session; session won't be used to
// store user's state.
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
AuthController.java
package com.cognizant.auth.microservice.controller;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.cognizant.auth.microservice.config.JwtTokenUtil;
import com.cognizant.auth.microservice.model.JwtResponse;
import com.cognizant.auth.microservice.model.LoginRequest;
#RestController
#CrossOrigin
public class AuthController {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Autowired
private UserDetailsService jwtInMemoryUserDetailsService;
#RequestMapping(value = "/authenticate", method = RequestMethod.POST)
public ResponseEntity<?> createAuthenticationToken(#RequestBody LoginRequest authenticationRequest)
throws Exception {
System.out.println("Inside");
authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword());
final UserDetails userDetails = jwtInMemoryUserDetailsService
.loadUserByUsername(authenticationRequest.getUsername());
String token;
token = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new JwtResponse(token));
}
private void authenticate(String username, String password) throws Exception {
Objects.requireNonNull(username);
Objects.requireNonNull(password);
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS", e);
}
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.cognizant.authMicroservice</groupId>
<artifactId>authMicroservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>AuthorizationMicroservice</name>
<description>Authorization Microservice that taking care to login and session</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Can anyone help me where I was wrong.
Thanks in Advance.
Probably you use a custom jwtRequestFilter to validate the tokens. In this case then you need to exclude this logic fron been applied to the authenticate request.
Use the following if case in your jwtRequestFilter
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
if (!request.getRequestURI().equals("/authenticate" )) {
... Validate token or some other code
}
chain.doFilter(request, response);
}
I did this configuration and it worked, you need to add the two configurations into WebSecurityConfig, thus:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// we don't need CSRF because our token is invulnerable
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and()
// don't create session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
// allow anonymous resource requests
.antMatchers("/v2/api-docs", // swagger
"swagger-ui/**",
"/webjars/**", // swagger-ui webjars
"/swagger-resources/**", // swagger-ui resources
"/configuration/**", // swagger configuration
"/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js")
.permitAll().antMatchers("/auth/**").permitAll().anyRequest().authenticated();
// Custom JWT based security filter
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
// disable page caching
httpSecurity.headers().cacheControl();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/v3/api-docs",
"/swagger-ui.html",
"/swagger-ui/**");
}
Related
Main Application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#ComponentScan(basePackages = {"com.example.backend.hostezza.repository", "com.example.backend.hostezza.entities" })
#SpringBootApplication (exclude = { SecurityAutoConfiguration.class })
public class BackendHostezzaApplication {
public static void main(String[] args) {SpringApplication.run(BackendHostezzaApplication.class, args);}
}
POM file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>Backend-Hostezza</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Backend-Hostezza</name>
<description>CTD - Proyecto Integrador - Equipo6</description>
<properties>
<java.version>18</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-security</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
</dependencies>
<build>
<finalName>hostezza</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Security Configuration
import com.example.Backend.Hostezza.Security.Jwt.JwtEntryPoint;
import com.example.Backend.Hostezza.Security.Jwt.JwtTokenFilter;
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.authentication.AuthenticationManager;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
AppUserService appUserService;
#Autowired
JwtEntryPoint jwtEntryPoint;
#Bean
public JwtTokenFilter jwtTokenFilter() {
return new JwtTokenFilter();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(appUserService).passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/authentication/signup").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
.antMatchers(HttpMethod.GET, "/bookings", "/bookings/product/**").permitAll()
.antMatchers(HttpMethod.GET, "/categories/**").permitAll()
.antMatchers(HttpMethod.GET, "/cities/**").permitAll()
.antMatchers(HttpMethod.GET, "/features/**").permitAll()
.antMatchers(HttpMethod.GET, "/policies/**").permitAll()
.antMatchers(HttpMethod.GET, "/products/**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
JWT Provider
import com.example.Backend.Hostezza.Security.AppUser;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
#Component
public class JwtProvider {
private static final Logger logger = Logger.getLogger(JwtProvider.class);
private SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
#Value("${jwt.expiration}")
private int expiration;
public String generateToken(Authentication authentication) {
Map<String, Object> claims = new HashMap<>();
AppUser appUser = (AppUser) authentication.getPrincipal();
claims.put("user_info",appUser);
return Jwts.builder()
.setSubject(appUser.getUsername())
.addClaims(claims)
.setIssuedAt(new Date())
.setExpiration(new Date(new Date().getTime() + expiration * 99999))
.signWith(key)
.compact();
}
public String getEmailFromToken(String token) {
return Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody().getSubject();
}
public Boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(key).parseClaimsJws(token);
return true;
} catch (MalformedJwtException e) {
logger.error("Token formed incorrectly");
} catch (UnsupportedJwtException e) {
logger.error("Token not supported");
} catch (ExpiredJwtException e) {
logger.error("Token expired");
} catch (IllegalArgumentException e) {
logger.error("Token empty");
} catch (SignatureException e) {
logger.error("Signature failed");
}
return false;
}
}
JWT Token FIlter
import com.example.Backend.Hostezza.Security.AppUserService;
import org.apache.log4j.Logger;
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 javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JwtTokenFilter extends OncePerRequestFilter {
private static final Logger logger = Logger.getLogger(JwtTokenFilter.class);
#Autowired
JwtProvider jwtProvider;
#Autowired
AppUserService appUserService;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
String token = getToken(request);
if (token != null && jwtProvider.validateToken(token)) {
String emailUser = jwtProvider.getEmailFromToken(token);
UserDetails userDetails = appUserService.loadUserByUsername(emailUser);
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(userDetails,
null, userDetails.getAuthorities());
auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
logger.info("Usuario con email: " + emailUser + " autenticado");
SecurityContextHolder.getContext().setAuthentication(auth);
}
} catch (Exception e) {
logger.error("Fallo en el metodo doFilterInternal " + e.getMessage());
}
filterChain.doFilter(request, response);
}
private String getToken(HttpServletRequest request) {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer "))
return header.substring(7);
return null;
}
}
JWT EntryPoint
import org.apache.log4j.Logger;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class JwtEntryPoint implements AuthenticationEntryPoint {
private static final Logger logger = Logger.getLogger(JwtEntryPoint.class);
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
logger.error("Failed on commence method");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "You are not authorized");
}
}
UserService
import com.example.Backend.Hostezza.Entities.User;
import com.example.Backend.Hostezza.Repository.UserRepository;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.List;
#Service
#Transactional
public class UserService {
private static final Logger logger = Logger.getLogger(UserService.class);
private UserRepository userRepository;
#Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User newUser(User user) {
logger.debug("Saving user: " + user);
return userRepository.save(user);
}
public List<User> getAllUsers() {
logger.debug("Listando usuarios: ");
return userRepository.findAll();
}
public User userByEmail(String email) {
logger.debug("Buscando usuario con email: " + email);
return userRepository.findByEmail(email);
}
public Boolean existsUserByEmail(String email) {
return userRepository.existsByEmail(email);
}
}
User Repository
import com.example.Backend.Hostezza.Entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
Boolean existsByEmail(String email);
}
Authentication Controller
import com.example.Backend.Hostezza.Entities.Role;
import com.example.Backend.Hostezza.Entities.User;
import com.example.Backend.Hostezza.Security.Jwt.JwtProvider;
import com.example.Backend.Hostezza.Security.Payload.LoginRequest;
import com.example.Backend.Hostezza.Security.Payload.LoginResponse;
import com.example.Backend.Hostezza.Security.Payload.RegisterRequest;
import com.example.Backend.Hostezza.Service.EmailSenderService;
import com.example.Backend.Hostezza.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
#CrossOrigin (origins = "*")
#RestController
#RequestMapping("/authentication")
public class AuthenticationControler {
#Autowired
PasswordEncoder passwordEncoder;
#Autowired
AuthenticationManager authenticationManager;
#Autowired
UserService userService;
#Autowired
JwtProvider jwtProvider;
#Autowired
EmailSenderService emailSender;
#PostMapping("/signup")
public ResponseEntity<?> register(#Valid #RequestBody RegisterRequest registerRequest, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("invalid data");
}
if (userService.existsUserByEmail(registerRequest.getEmail())) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("this email has already been registered");
}
User user = new User(registerRequest.getName(),
registerRequest.getSurname(),
registerRequest.getEmail(),
passwordEncoder.encode(registerRequest.getPassword()),
""enter image description here
);
Role role = new Role();
role.setId(2L);
user.setRole(role);
userService.newUser(user);
String registerBody = emailSender.styleRegisterBody(registerRequest.getName());
emailSender.sendEmail(registerRequest.getEmail(), "You have registered succesfully",
registerBody);
return ResponseEntity.status(HttpStatus.CREATED).body("User has been registered");
}
#PostMapping("/signin")
public ResponseEntity<LoginResponse> login(#Valid #RequestBody LoginRequest loginRequest, BindingResult bindingResult) {
if (bindingResult.hasErrors())
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getEmail(),
loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtProvider.generateToken(authentication);
LoginResponse token = new LoginResponse(jwt);
return new ResponseEntity<>(token, HttpStatus.OK);
}
}
I am trying to test my authentication API but I get a 404. I need to create a user so I can get a JWT token. But every time I try to access my API, I get a 404. It doesn't matter which API I sent a request; I always get a 404.
The only solution that I found was copying this in my main application, to evade the 401 error that
I used to get:
#SpringBootApplication (exclude = { SecurityAutoConfiguration.class })
I think it has to do something with spring security "reconfiguring" my Intellij because when I start an older version of this same project, I get the same error with my API's even though I didn't create any classes that implement spring security.
I am trying to get into Spring security with a Spring/Angular stack and found the awsome code of bezcoder which can be looked up here
https://github.com/bezkoder/angular-10-jwt-authentication
and
https://github.com/bezkoder/spring-boot-spring-security-jwt-authentication
Signin and signup works, however, I have trouble with the authorisation for certain access points. For instance, I cannot enter the url localhost:8080/api/test/user - if I try I get "Error:Unauthorized"
I think I narrowed the problem down to the handling of roles by the #PreAuthorize annotation. In the following "TestController", the #PreAuthorize("permitAll()"), as set on the public String allAccess() function works,
however, all other functions with #PreAuthorize which refer to a certain role do not. The controller:
package com.savetravel.SaveTravel.Controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.savetravel.SaveTravel.Repositories.UserRepository;
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
#RequestMapping("/api/test")
public class TestController {
#Autowired
UserRepository userRepositoy;
#PreAuthorize("permitAll()")
#GetMapping("/all")
public String allAccess() {
return "Public Content.";
}
#GetMapping("/user")
#PreAuthorize("hasRole('USER') or hasRole('MODERATOR') or hasRole('ADMIN')")
public String userAccess() {
return "User Content.";
}
#GetMapping("/mod")
#PreAuthorize("hasRole('MODERATOR') or hasRole('ADMIN')")
public String moderatorAccess() {
return "Moderator Board.";
}
#GetMapping("/admin")
#PreAuthorize("hasRole('ROLE_ADMIN')")
public String adminAccess() {
return "Admin Board.";
}
}
and my WebSecurityConfig
package com.savetravel.SaveTravel;
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.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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.savetravel.SaveTravel.Security.Services.UserDetailsServiceImpl;
import com.savetravel.SaveTravel.Security.jwt.AuthEntryPointJwt;
import com.savetravel.SaveTravel.Security.jwt.AuthTokenFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
// securedEnabled = true,
// jsr250Enabled = true,
proxyTargetClass = true,
prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsServiceImpl userDetailsService;
#Autowired
public AuthEntryPointJwt unauthorizedHandler;
#Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
#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()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
If I remove the #PreAuthorize annotations for the roles from the functions in the controller everything works (falling back to the WebSecurityConfig, which is not how its meant to be)
I am quite puzzled, as removing the #PreAuthorize annotations and altering the configure() function in the WebSecurityConfig with .authorizeRequests().antMatchers("/api/test/user").hasRole("USER")does not have an effect either say:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/api/test/user").hasRole("USER")
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
It seems that the backend doesn't consider roles at all. The only thing I changed is that I use Hibernate H2 instead of MySQL, as it is used in the original code. Consequently, my application.properties looks like that (the original configuration is commented out):
spring.datasource.url=jdbc:h2:mem:savetravel;DATABASE_TO_UPPER=false
spring.h2.console.enabled=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
spring.jpa.hibernate.hbm2ddl.auto=create
spring.datasource.username=myusername
spring.datasource.password=mypassword
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.platform=h2
spring.datasource.initialize=true
#Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/?user=root&password=rootpassword");
#PreparedStatement ps = connection.prepareStatement("CREATE DATABASE databasename");
#int result = ps.executeUpdate();
#spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
#spring.jpa.hibernate.ddl-auto= update
# SQL GENERATE CONFIGURATION
#datasource.schema= the schema sql script to load. By default it is schema-${platform}.sql then schema.sql;
#datasource.data= the data sql script. By default, it is data-${platform}.sql then data.sql;
#spring.h2.console.enabled=true
#spring.jpa.hibernate.ddl-auto=none
app.jwt.header=Authorization
app.jwtSecret= loginSecretKey
app.jwtExpirationMs= 86400000
with a data.sql:
INSERT INTO roles(name) VALUES('ROLE_USER');
INSERT INTO roles(name) VALUES('ROLE_MODERATOR');
INSERT INTO roles(name) VALUES('ROLE_ADMIN');
INSERT INTO users(id, username, email, password) VALUES(777, 'testuser', 'testuser#test.de', '$2a$10$tmPQGqC7XxNmFKwfufGybOxb7HIDA.0lEOtb3ejAiiBn4EfoxI9TK');
INSERT INTO user_roles(user_id, role_id) VALUES(777, 1);
INSERT INTO user_roles(user_id, role_id) VALUES(777, 2);
But I can't imagine that H2 is the problem, because the following tests don't fail:
#Test
public void simpleConstructorTestUser() {
User testUser = new User("testUser", "test#test.de", "testpassword");
assertNotNull(testUser.getUsername());
}
#Test
#PostMapping("/user")
public void userAccess() {
String userName = testUser.getUsername();
System.out.println(userName);
Optional<User> userFromDB = userRepository.findByUsername(userName);
Set<Role> roles = userFromDB.get().getRoles();
for (Role role : roles) {
String roleType = role.getName().name();
assertArrayEquals(roleType, "ROLE_USER");
}
}
But maybe I am wrong and it has to do something with H2 instead of MySql?
For the sake of comprehensiveness: My pom.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.savetravel</groupId>
<artifactId>SaveTravel</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SaveTravel</name>
<description>TravelApp</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Many questions, and the embarassing thing is: I have really no idea WHERE TO SEARCH to solve this problem, especially as the code is supposed to work and a collegue of mine seems to have been able to run it without changes. I would be happy if someone could give me a hint where to start my journey, as I think the Spring security application is terrific and I would love to gain a better understanding of security procedures.
So if anyone has an idea, such as:
tests I could write in Spring or Angular to check certain things
configurations I could look up (I use Linux, maybe that is an Issue?)
anything else...
Thanks in advance!
Tom
I have been working on a springboot 2.3.4 application with spring security. It's working with embedded tomcat. We want to make it work with external application servers like tomcat and jboss. I have tried to deploy the war file in external tomcat server. when hitting the endpoints I receive 404 error code. Here is my pom file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.teradata</groupId>
<artifactId>modelstudio</artifactId>
<version>1</version>
<name>modelstudio</name>
<packaging>war</packaging>
<description>ModelStudio Application</description>
<properties>
<java.version>13</java.version>
<start-class>
com.teradata.modelstudio.ModelStudioApplication
</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<exclusion>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.teradata.jdbc</groupId>
<artifactId>terajdbc4</artifactId>
<version>17</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20200518</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<exclusions>
<exclusion>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>modelstudio</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>static/**</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>ModelStudioUI/**</exclude>
<exclude>static/**</exclude>
</excludes>
</resource>
</resources>
</build>
</project>
My JWT Entry point is:
package com.teradata.modelstudio.filter;
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.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.teradata.modelstudio.service.CustomAuthenticationProviderService;
import com.teradata.modelstudio.utils.JwtUtil;
import com.teradata.modelstudio.utils.Logger;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;
#Component
public class JwtFilter extends OncePerRequestFilter {
#Autowired
private JwtUtil jwtUtil;
#Autowired
private CustomAuthenticationProviderService service;
#Autowired JwtUserDetailsService jwtUserDetailsService;
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
String requestURI = httpServletRequest.getRequestURI();
Logger.info("==================="+requestURI);
Pattern mega = Pattern.compile(
"\\/*.css|\\/*.js|\\/*.png|\\/*.jpg|\\/assets\\/*.*|\\/*.woff2|\\/*.woff|\\/*.ttf|\\/swagger-resources\\/*|/servicemanagement/configuration/*|/servicemanagement/etlframework/*|/servicemanagement/refreshCache/*");
// System.out.println(requestURI);
if (httpServletRequest.getMethod().equals("OPTIONS")// || requestURI.equalsIgnoreCase("/index.html")
|| requestURI.equalsIgnoreCase("/favicon.ico") || mega.matcher(requestURI).find() || requestURI.equalsIgnoreCase("/")) {
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
// TODO Auto-generated method stub
String url = httpServletRequest.getRequestURL().toString();
// System.out.println("+++URL in jwt request filter:"+url);
if (url.contains("auth") || url.contains("dbcontent") || url.contains("favico")) {
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
String requestTokenHeader = httpServletRequest.getHeader("Authorization");
String username = null;
String password = null;
String serverUrl = null;
String dbName = null;
String authType = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtUtil.getUsernameFromJWT(jwtToken);
password = jwtUtil.getPasswordFromJWT(jwtToken);
serverUrl = jwtUtil.getServerUrlFromJWT(jwtToken);
dbName = jwtUtil.getDbNameFromJWT(jwtToken);
authType = jwtUtil.getAuthTypeFromJWT(jwtToken);
jwtUtil.validateToken(jwtToken, username);
} catch (Exception e) {
throw e;
}
} else {
throw new IOException("Invalid Authorization");
}
SecurityContextHolder.getContext().setAuthentication(null);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwtToken, username)) {
CustomUserPrincipal customUserPrincipal = new CustomUserPrincipal(username, password, serverUrl, dbName, authType);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(customUserPrincipal, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
My Security config file:
package com.teradata.modelstudio.config;
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.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
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;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.teradata.modelstudio.filter.JwtFilter;
import com.teradata.modelstudio.payload.JwtAuthenticationResponse;
import com.teradata.modelstudio.security.JwtAuthenticationEntryPoint;
import com.teradata.modelstudio.service.CustomAuthenticationProviderService;
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProviderService authenticationProviderService;
#Autowired
private JwtFilter jwtFilter;
#Autowired
JwtAuthenticationEntryPoint unauthorizedHandler;
#Autowired
private com.teradata.modelstudio.filter.SimpleCORSFilter simpleCORSFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/*.svg",
"/*.png",
"/*.woff",
"/*.woff2",
"/*.svg",
"/*.jpg",
"/*.json",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/**/*.svg",
"/**/*.png",
"/**/*.jpg",
"/**/*.ico",
"/**/*.icons",
"/resources/**",
"/assets/",
"/static/**",
"/h2-console/**"
).permitAll()
.antMatchers("/auth/**", "/dbcontent/**")
.permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(simpleCORSFilter, UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProviderService);
}
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
One of my controller classes are:
package com.teradata.modelstudio.controllers;
import java.io.File;
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 com.teradata.modelstudio.exception.ModelStudioException;
import com.teradata.modelstudio.utils.Logger;
import org.apache.commons.io.FileUtils;
import org.json.JSONObject;
#RestController
#RequestMapping("dbcontent")
public class DBContentController {
#GetMapping(path="servers", produces = "application/json")
public ResponseEntity<?> getServers() {
try {
String dbConFilePath = System.getProperty("user.dir")+File.separator+"db-con";
File file = new File(dbConFilePath);
String content = FileUtils.readFileToString(file, "utf-8");
// Convert JSON string to JSONObject
JSONObject fileContents = new JSONObject(content);
return ResponseEntity.ok(fileContents.toString());
} catch(Exception e) {
Logger.error("Unable to get servers: "+e.getMessage());
throw new ModelStudioException(e.getMessage());
}
}
}
Here is my main class
package com.teradata.modelstudio;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
#SpringBootApplication(
exclude = { DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
})
public class ModelstudioApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(ModelstudioApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(ModelstudioApplication.class);
}
}
With embedded tomcat serever, I hit:
localhost:8080/dbcontent/servers
and I get the results while on external I do the following:
localhost:8080/modelstudio/dbcontent/servers
and I get 404.
Can anyone please help and advise me how to resolve this issue with external server like tomcat.
When I run the application, it displays this error (error 401).
How fix this problem and thank's :
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing
this as a fallback. There was an unexpected error (type=Unauthorized,
status=401). Unauthorized
pom.xml :
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>app-back</artifactId>
<name>app-back</name>
<description>module app backend </description>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<properties>
<start-class>app.AppApplication</start-class>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<hibernate.core.version>5.4.2.Final</hibernate.core.version>
<maven.war.plugin.version>3.2.0</maven.war.plugin.version>
<jjwt.version>0.9.1</jjwt.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.core.version}</version>
</dependency>
<!-- Spring data JPA, default tomcat pool, exclude it -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
</dependencies>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven.war.plugin.version}</version>
<configuration>
<packagingExcludes>WEB-INF/lib/tomcat-*.jar</packagingExcludes>
<warName>app</warName>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals><goal>copy-resources</goal></goals>
<configuration>
<outputDirectory>${basedir}/target/classes/static/</outputDirectory >
<resources>
<resource>
<directory>../app-front/dist/app-front</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
WebSecurityConfig.java :
package app.auth;
import javax.servlet.http.HttpServletResponse;
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.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.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;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String[] ACCEPTED_FILES = {"/*.html", "/*.css", "/*.js", "/*.jpg", "/*.png", "/*.ico", "/*.txt", "/*.svg", "/*.eot", "/*.woff2", "/*.ttf", "/*.woff"};
#Autowired
public UserDetailsService userDetailsService;
#Autowired
JwtTokenProvider jwtTokenProvider;
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
};
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean("authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public AuthenticationEntryPoint unauthorizedEntryPoint() {
return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/assets/**","/home/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.csrf().disable().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests().antMatchers("/auth/sign-in").permitAll()
.and().authorizeRequests().antMatchers(ACCEPTED_FILES).permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/auth/admin/**").hasRole("ADMIN")
.antMatchers("/object/admin/**").hasRole("ADMIN")
.and().authorizeRequests().anyRequest().authenticated()
.and().exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint())
.and().apply(new JwtConfigurer(jwtTokenProvider))
.and().httpBasic().disable();
}
}
Appl.java :
package myApp.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#Configuration
#ComponentScan("app")
#EnableJpaRepositories("app.repositories")
#EntityScan( basePackages = {"app.entities"} )
#SpringBootApplication
#EnableAutoConfiguration
public class RefMetierApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(RefMetierApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(RefMetierApplication.class);
}
}
and this method in userServiceImpl.java :
#Override
public Map<String, String> login(appUser requestUser) {
UsernamePasswordAuthenticationToken authenticationTokenRequest = new UsernamePasswordAuthenticationToken(
requestUser.getUsername(), requestUser.getPassword());
try {
Authentication authentication = this.authenticationManager.authenticate(authenticationTokenRequest);
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
appUser user = (appUser) authentication.getPrincipal();
String token = jwtTokenProvider.createToken(requestUser.getUsername(), user.getAuthorities());
Map<String, String> model = new HashMap<>();
model.put("username", requestUser.getUsername());
model.put("token", token);
if(user.hasRule(ParamsEnum.ROLE_ADMIN.getValue())) {
model.put("rule", "ADMIN");
}
else {
model.put("rule", "USER");
}
return model;
} catch (Exception e) {
e.printStackTrace();
throw new BadCredentialsException(ParamsEnum.BAD_CREDENTIALS.getValue());
}
}
You must not have setup ADMIN ROLE, for the User attempting request.
I am trying to build a simple Spring Boot CRUD application that also has login and signup options with spring boot security. I'm already working with a MySQL database and its working fine to persist the data for my application.
The problem is that, in trying to create my jdbcAuthentication, in my securityConfig class, it says that I cannot autowire Datasource, and that there are no beans of 'DataSource' type found (again, I have used my MySQL database successfully for this project, for a while now). It also automatically imports the javax.sql.DataSource import when I type it in, so it does recognize it.
I tried to search through similar questions, but just could not get it to work.
Here is my code:
Test2Application.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Test2Application {
public static void main(String[] args) {
SpringApplication.run(Test2Application.class, args);
}
}
SecurityConfig.java
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.sql.DataSource;
#EnableWebSecurity
#RequestMapping("cheese")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select email as principal, password as credentials, true from user where email=?");
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
.antMatchers(
"/cheese/index",
"/cheese/",
"/**/webjars/**",
"/cheese/signup",
"/cheese/login",
"/cheese/account",
"/cheese/add",
"/cheese/remove",
"/cheese/success").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/cheese/login")
.permitAll();
http.csrf().disable();
}
}
UserController.java
package com.example.demo.controllers;
import com.example.demo.models.Customer;
import com.example.demo.models.data.CustomerDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping("cheese")
public class UserController {
#Autowired
private CustomerDao customerDao;
#RequestMapping(value = "login")
public String loginPage(Model model) {
model.addAttribute("title", "Login Page");
return "cheese/login";
}
#RequestMapping(value = "account")
public String accountInfo(Model model) {
model.addAttribute("title", "Account Page");
return "cheese/account";
}
#GetMapping("signup")
public String displaySignUpForm(Model model) {
model.addAttribute("title", "Sign Up");
model.addAttribute("customer", new Customer());
return "cheese/signup";
}
#PostMapping(value = "signup")
public String processSignUp(Model model, #ModelAttribute Customer customer, Errors errors) {
if (errors.hasErrors()) {
return "cheese/signup";
}
customerDao.save(customer);
return "cheese/success";
}
}
Application.Properties
spring.datasource.url=jdbc:mysql://localhost:8889/******?useSSL=false
spring.datasource.username=****
spring.datasource.password=******
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>test2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test2</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
The Spring Security configuration should applied with the Configuration annotation.
Remove #RequestMapping("cheese") from SecurityConfig
The correct configuration:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
Had the same issue, I created a separate config class where I defined a DataSource bean
#Bean
DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("database_url");
dataSource.setUsername("username");
dataSource.setPassword("password");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
return dataSource;
}
and in the main config file (in your case Security config) left DataSource #Autowired.
#Autowired
DataSource dataSource;
#Autowired
protected void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}
And it worked. In case it is useful, I used these Gradle dependencies -
implementation 'mysql:mysql-connector-java:8.0.18'
implementation group: 'org.springframework', name: 'spring-jdbc', version: '5.3.21'
Apart from the #Configuration annotation, add #EnableAutoConfiguration which would attempt and configure code.
#Configuration
#EnableAutoConfiguration
public class SecurityConfig extends WebSecurityConfigurerAdapter
Also, rebuild your sources afterwards.