Spring Security for Rest #PreAuthorize 500 error - java

I want basic security for rest ,this is my config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private PacijentUserDetailsService pacijent;
#Autowired
private FizioterapeutUserDetailsService fizioterapeut;
#Autowired
private FizijatarUserDetailsService fizijatar;
#Override
protected void configure(AuthenticationManagerBuilder
auth) throws Exception {
auth.userDetailsService(pacijent)
.passwordEncoder(new
BCryptPasswordEncoder());
auth.userDetailsService(fizioterapeut).passwordEncoder(new
BCryptPasswordEncoder());
auth.userDetailsService(fizijatar).passwordEncoder(new
BCryptPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/pacijent/", "/fizijatar/","/fizioterapeut/").permitAll()
.antMatchers("/pacijent/**","/fizijatar/**","/fizioterapeut/**").authenticated()
.and()
.httpBasic()
.realmName("Ordinacija")
.and()
.csrf()
.disable();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
I have 3 implements of userdetailservice this is one example:
#Component
public class PacijentUserDetailsService implements UserDetailsService {
#Autowired
private PacijentService pacijentService;
#Override
public UserDetails loadUserByUsername(String jmbg) throws UsernameNotFoundException {
Pacijent pacijent = pacijentService.vratiPacijenta(jmbg);
if (pacijent == null) {
throw new UsernameNotFoundException(String.format("Pacijent nije pronadjen", jmbg));
}
List<GrantedAuthority> authorities = new ArrayList<>();
if (pacijentService.postojiPacijentPoJmbgu(jmbg)) {
authorities = AuthorityUtils.createAuthorityList("ROLE_USER");
}
UserDetails userDetails = new org.springframework.security.core.userdetails.User(pacijent.getJmbg(),
pacijent.getSifra(), authorities);
return userDetails;
}
}
And my web xml file:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</context-param>
org.springframework.web.context.ContextLoaderListener
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet- class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
When i start my app and go to rest method which have #PreAuthorize method i have error 500:
Request processing failed; nested exception is org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContex.

i write the answer to help others.
If you have a Filter like OncePerRequestFilter where you check authentication, so when you check for authentication and it fails you can set this:
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
Otherwise if you let manage authentication to spring you can use the exception handler:
#ControllerAdvice
#RestController
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler({AccessDeniedException.class})
public final
ResponseEntity<Object> handleUserNotFoundException(EntityNotFoundException ex, WebRequest request){
return new ResponseEntity<>("Unauthorized", HttpStatus.UNAUTHORIZED);
}
}

Try to change your configuration something like this.
.authorizeRequests()
.antMatchers(permitAllEndpointList.toArray(new String[permitAllEndpointList.size()]))
.permitAll()
.and()
.authorizeRequests()
.antMatchers(API_ROOT_URL).authenticated()
I hope this solves your issue.

Related

session timeout in spring boot + React

I am able to configure session timeout in web.xml, but after session timeout getting errors from react side.
using spring security and jwt token.
WebSecurity.java
#Configuration
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailServiceImpl userDetails;
#Autowired
JWTAuthenticationFilter jwtRequestFilter;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetails).passwordEncoder(getPasswordEncoder());
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.GET, "/index*", "/static/**", "/*.js", "/*.json", "/*.ico", "/*.png")
.permitAll().antMatchers("/resources/**", "/login", "/", "/actuator").permitAll()
.antMatchers("/authenticate/**", "/identity/**").permitAll().anyRequest().authenticated().and().cors().and()
.exceptionHandling().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
web.xml
<session-config>
<session-timeout>1</session-timeout>
</session-config>
I tried sessionManagement().InvalidSessionURL("url") but on login it always redirect to invalid url only.
There is no api for login, we are loading from React directly.
Please let me know how to redirect to login page on session timeout ? and how to handle errors from react side ?

How to fix BasicAuth for Spring Boot?

I'm writing an SpringBoot app. When I do requests with Postman - I get this error VERY OFTEN:
java.lang.NullPointerException: null
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.authenticationIsRequired(BasicAuthenticationFilter.java:222) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:166) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
Here is my SecurityConfig:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Autowired
private PasswordEncoder passwordEncoder;
#Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder(8);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/registration", "/restaurants").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.rememberMe()
.and()
.logout()
.permitAll();
//Set enable when frontend added
http.csrf().disable();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService)
.passwordEncoder(passwordEncoder);
}
}
How to fix it? I need to do request from Postman, so I can't change the login form.
Go to the Authorization tab in your Postman window ( it's under the request type ) and select 'Basic Auth' and fill in your credentials if you're doing any request other than "/", "/registration", "/restaurants".

Spring Boot 403 forbidden with POST request in Tomcat 9

I am new to the spring boot and I am creating a web application. I am bypassing "/auth/login" URL without JWT token authentication.
I have created a controller which handle the login request and give the response.
When I call my web service with URL in my local using URL
http://localhost:9505/auth/login with body param
{
"username":"abcd#g.l",
"password" : "newPassword"
}
It is working fine and does not check for the token but When I export it and create WAR file and deployed on the server then it is giving me 403 Forbidden error.
Below is URL which I use to call API after deploying on tomcat 9 server
http://localhost:9505/myapplicationame/auth/login
Can you please guide me what will be the problem?
Below is my security config method.
#Override
protected void configure(HttpSecurity http) throws Exception {
logger.info("SecurityConfig => configure : Configure in SecurityConfig");
logger.info("http Request Path : ");
logger.info("servletContext.getContextPath()) : " + servletContext.getContextPath());
http
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/auth/**")
.permitAll()
.antMatchers("/auth/login")
.permitAll()
.antMatchers("/permissions")
.permitAll()
.anyRequest()
.authenticated();
// Add our custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
Below is my filter class
#Configuration
#CrossOrigin
#EnableWebSecurity
#EnableMBeanExport(registration=RegistrationPolicy.IGNORE_EXISTING)
#EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
#Order(SecurityProperties.IGNORED_ORDER)
public class JwtAuthenticationFilter extends OncePerRequestFilter {
#Autowired
JwtTokenProvider tokenProvider;
#Autowired
CustomUserDetailsService customUserDetailsService;
#Autowired
AdminPermissionRepository adminPermissionRepository;
#Autowired
PermissionMasterRepository permissionMasterRepository;
#Autowired
private ServletContext servletContext;
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
FilterChain filterChain) throws IOException, ServletException {
if (StringUtils.hasText(jwt) && isValidToken) {
// Check user email and password
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
adminDetails, null, adminDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
logger.info("Before finish doFilterInternal");
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
/**
* To get JWT token from the request
*
* #param httpServletRequest
* #return String
*/
private String getJwtFromRequest(HttpServletRequest httpServletRequest) {
logger.info("JwtAuthenticationFilter => getJwtFromRequest");
String bearerToken = httpServletRequest.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
logger.info("Have token");
return bearerToken.substring(7, bearerToken.length());
}
logger.info("Does not have token");
return null;
}
}
Below is my controller
#RestController
#Transactional(rollbackFor=Exception.class)
public class AuthController {
#PostMapping("/auth/login")
ResponseEntity login(#Valid #RequestBody LoginRequest request)
throws DisabledException, InternalAuthenticationServiceException, BadCredentialsException {
// My logic
return ResponseEntity.ok();
}
}
The problem is with the CORS in my tomcat server.
I have commented below code and it works.
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>http://localhost:9505, http://localhost, www.mydomain.io, http://mydomain.io, mydomain.io</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Thanks
Try adding below mention annotations to your class.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ServletContext servletContext;
#Override
protected void configure(HttpSecurity http) throws Exception {
logger.info("SecurityConfig => configure : Configure in SecurityConfig");
logger.info("http Request Path : ");
logger.info("servletContext.getContextPath()) : " + servletContext.getContextPath());
http
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/auth/**")
.permitAll()
.antMatchers("/auth/login")
.permitAll()
.antMatchers("/permissions")
.permitAll()
.anyRequest()
.authenticated();
// Add our custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}

Right configuration of two separate login forms in one application via Spring Security

I have two different users in my web app: client and translator. I created two different HttpSecurity configuration for this. I have super class for both configurations:
#Configuration
#ComponentScan(basePackages = {"ua.translate"})
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
CustomSuccessHandler customSuccessHandler;
#Autowired
#Qualifier("customAccessDeniedHandler")
AccessDeniedHandler accessDeniedHandler;
#Autowired
DataSource dataSource;
#Autowired
PersistentTokenRepository tokenRepository;
#Override
public void configure(WebSecurity web){
web
.ignoring()
.antMatchers(new String[]{"/resources/**"});
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth,#Qualifier("detailsService") UserDetailsService uds) throws Exception{
auth.userDetailsService(uds)
.passwordEncoder(bcryptEncoder());
}
#Bean
public PasswordEncoder bcryptEncoder(){
return new BCryptPasswordEncoder();
}
#Autowired
#Bean
public PersistentTokenBasedRememberMeServices getPersistentTokenBasedRememberMeServices(#Qualifier("detailsService") UserDetailsService uds) {
PersistentTokenBasedRememberMeServices tokenBasedservice = new PersistentTokenBasedRememberMeServices(
"remember-me", uds, tokenRepository);
return tokenBasedservice;
}
#Bean
public SavedRequestAwareAuthenticationSuccessHandler
savedRequestAwareAuthenticationSuccessHandler() {
SavedRequestAwareAuthenticationSuccessHandler auth
= new SavedRequestAwareAuthenticationSuccessHandler();
auth.setTargetUrlParameter("targetUrl");
return auth;
}
}
There are two different configurations for different users:
#Configuration
#EnableWebSecurity
public class AppSecurityConfigGlobal{
#Configuration
#Order(1)
public static class AppSecurityConfigTranslator extends AppSecurityConfig{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/translator/**")
.authorizeRequests()
.antMatchers("/translator/registration*","/bulbular*").anonymous()
.antMatchers("/translator/index","/translator/login*").permitAll()
.antMatchers("/translator/**").hasRole("TRANSLATOR")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/translator/login")
.permitAll()
.successHandler(customSuccessHandler)
.failureUrl("/translator/login?error")
.usernameParameter("username")
.passwordParameter("password")
.loginProcessingUrl("/j_spring_security_check")
.and()
.logout().deleteCookies("JSESSIONID")
.logoutUrl("/translator/logout")
.logoutSuccessUrl("/translator/login?logout")
.and()
.rememberMe().tokenRepository(tokenRepository)
.tokenValiditySeconds(86400)
.and()
.csrf()
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler);
}
}
#Configuration
#Order(2)
public static class AppSecurityConfigClient extends AppSecurityConfig{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/client/registration*","/bulbular*").anonymous()
.antMatchers("/client/**").hasRole("CLIENT")
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/index","/translators","/orders","/client/login*").permitAll()
.and()
.formLogin()
.loginPage("/client/login")
.permitAll()
.successHandler(customSuccessHandler)
.failureUrl("/client/login?error")
.usernameParameter("username")
.passwordParameter("password")
.loginProcessingUrl("/j_spring_security_check")
.and()
.logout().deleteCookies("JSESSIONID")
.logoutUrl("/client/logout")
.logoutSuccessUrl("/client/login?logout")
.and()
.rememberMe().tokenRepository(tokenRepository)
.tokenValiditySeconds(86400)
.and()
.csrf()
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler);
}
}
}
My problem is when user with ROLE_CLIENT logged out, he is redirected to ../client/login and no message about successful logging out not displayed.
But when user with ROLE_TRANSLATOR logged out, he is redirected to ../translator/login?logout and message is showed, so there is no problem.
I don't understand cause of this problem, help me, please)
I found cause of this problem! In my configuration for client I has:
.antMatchers("/client/registration*","/bulbular*").anonymous()
.antMatchers("/client/**").hasRole("CLIENT")
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/index","/translators","/orders","/client/login*").permitAll()
but one rule for order of andMatchers(..) in configuration is: the most strict andMatchers must be last.
I changed order:
.antMatchers("/client/registration*","/bulbular*").anonymous()
.antMatchers("/index","/translators","/orders","/client/login*").permitAll()
.antMatchers("/client/**").hasRole("CLIENT")
.antMatchers("/admin/**").hasRole("ADMIN")
And problem is solved!)

Both isAnonymous() and isAuthenticated() are returning false

I have a simple page which is displays simple text depending on whether the user is logged in or not.
<sec:authorize access="isAnonymous()">
No, you failed!
</sec:authorize>
<sec:authorize access="isAuthenticated()">
yes, logged in. Well done!
</sec:authorize>
The above code displays nothing! which means both isAuthenticated() and isAnonymous() have returned false.
It is suggested here (Both isAnonymous() and isAuthenticated() return false on error page) that I must use this configuration for my filter mapping:
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<!-- apply Spring Security authentication to error-pages -->
<dispatcher>ERROR</dispatcher>
</filter-mapping>
I am not using XML, but my configuration is the same:
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
FilterRegistration.Dynamic security = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
security.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
Why else would this happen?
Edit:
This is my security context:
#Configuration
#EnableWebSecurity
public class SecurityContext extends WebSecurityConfigurerAdapter {
#Autowired
private UserRepository userRepository;
#Override
public void configure(WebSecurity web) throws Exception {
web
//Spring Security ignores request to static resources such as CSS or JS files.
.ignoring()
.antMatchers("/static/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
//Configures form login
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login/authenticate")
.failureUrl("/login?error=bad_credentials")
//Configures the logout function
.and()
.logout()
.deleteCookies("JSESSIONID")
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
//Configures url based authorization
.and()
.authorizeRequests()
//Anyone can access the urls
.antMatchers(
"/auth/**",
"/login",
"/signin/**",
"/signup/**",
"/user/register/**"
).permitAll()
//The rest of the our application is protected.
.antMatchers("/**").hasRole("USER")
//Adds the SocialAuthenticationFilter to Spring Security's filter chain.
.and()
.apply(new SpringSocialConfigurer());
}
/**
* Configures the authentication manager bean which processes authentication
* requests.
*/
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService())
.passwordEncoder(passwordEncoder());
}
/**
* This is used to hash the password of the user.
*/
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
}
/**
* This bean is used to load the user specific data when social sign in
* is used.
*/
#Bean
public SocialUserDetailsService socialUserDetailsService() {
return new SimpleSocialUserDetailsService(userDetailsService());
}
/**
* This bean is load the user specific data when form login is used.
*/
#Bean
public UserDetailsService userDetailsService() {
return new RepositoryUserDetailsService(userRepository);
}
}
This the page controller:
#Controller
public class LoginController {
private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class);
protected static final String VIEW_NAME_LOGIN_PAGE = "user/login";
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String showLoginPage() {
LOGGER.debug("Rendering login page.");
return VIEW_NAME_LOGIN_PAGE;
}
}
Make sure you are not bypassing security for that URL like as follows:
<http pattern="/xyz.xx" security="none" />
The ApplicationContext must contain
#ComponentScan(basePackages = {
"com.social.user.detail.service"
})
In this package I have the my user class containing the following:
public interface UserService {
public User registerNewUserAccount(RegistrationForm userAccountData) throws DuplicateEmailException;
}

Categories

Resources