Two identical post-methods, first is executed, second one is not allowed 405 - spring

I just wonder what can go wrong
#PostMapping("/login")
public ResponseEntity<TokenDTO> login(#RequestBody LoginDTO loginDTO) {
return ResponseEntity.ok(loginService.login(loginDTO));
}
#PostMapping("/logout")
public ResponseEntity<?> logout(#RequestBody LoginDTO loginDTO) {
Guest guest = guestDao.getGuestByLogin(loginDTO.getLogin());
guest.getTokens().clear();
return ResponseEntity.ok("Logout successfully");
}
SecurityConfig:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(tokenAuthFilter, BasicAuthenticationFilter.class)
.authenticationProvider(tokenAuthProvider)
.authorizeRequests()
.antMatchers("/guests/**", "/rooms/**", "/maintenances/**")
.authenticated()
.and()
.authorizeRequests()
.antMatchers("/login/**", "/logout/**").permitAll();
enter image description here - /login executed
enter image description here - /logout 405 not allowed

Related

adding a login page before swagger-ui.html using thyme leaf and spring Boot

#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.authorizeRequests()
.antMatchers("/", "/favicon.ico", "/**/*.png", "/**/*.gif", "/**/*.svg", "/**/*.jpg",/**/*.html","/**/*.css", "/**/*.js")
.permitAll()
.antMatchers("/v2/api-docs", "/configuration/ui", "/configuration/security","/webjars/**")
.permitAll().antMatchers("/swagger-resources","/swagger-resources/configuration/ui","/swagger-ui.html").hasRole("SWAG").anyRequest().authenticated()
.antMatchers("/api/all/**").permitAll().antMatchers("/api/Service/**").permitAll()
.antMatchers("/api/Service/Package/**").permitAll()
.antMatchers("api/public/customer/**").hasRole("CUSTOMER1")
.antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated().and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.permitAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.addFilterBefore(authTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER")
.and()
.withUser("manager").password("{noop}password").roles("MANAGER");
}
#Controller
public class HomeController {
#GetMapping("/")
public String root() {
return "index";
}
#GetMapping("/user")
public String userIndex() {
return "swagger-ui.html";
}
#GetMapping("/login")
public String login() {
return "login";
}
#GetMapping("/access-denied")
public String accessDenied() {
return "/error/access-denied";
}
}
so iam trying to authenticate /swagger-ui.html like a simple popup login using inmemory in order to access the api by certain users
when i do with this code i got the following output of the attached image
when i login there is no redirection for authentication
>

Ajax call after session expired not redirecting to login page - spring boot

I want to redirect to the login page if while doing an ajax call the session is expired. I'm following the instructions on this link to do that, but every time I do an ajax call with the session expired it returns the login page as part of the response instead of redirecting to the login page, this never fails and response always goes to success piece of the ajax call with readyState: 4 and status: 200 and this is giving me a jquery error because I'm expecting a list and it's returning the html code for the login page.
My code is as below:
WebSecurityConfig.java
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(URL_LOGIN, "/css/**", "/img/**").permitAll()
.antMatchers("/admin/**").hasAnyAuthority(authorizedRolesAdmin)
.antMatchers("/**").hasAnyAuthority(ArrayUtils.addAll(authorizedRolesUser, authorizedRolesAdmin))
.and()
.formLogin()
.loginPage(URL_LOGIN)
.defaultSuccessUrl("/", true)
.failureUrl(URL_LOGIN_FAILED)
.permitAll()
.and()
.logout()
.logoutSuccessUrl(URL_LOGOUT)
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage(URL_LOGIN_UNAUTHORIZED)
.authenticationEntryPoint(new AjaxAwareAuthenticationEntryPoint(URL_LOGIN))
.and()
.sessionManagement()
.maximumSessions(1)
.expiredUrl(URL_LOGOUT)
.and()
.invalidSessionUrl(URL_LOGOUT);
}
AjaxAwareAuthenticationEntryPoint.java
public class AjaxAwareAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
public AjaxAwareAuthenticationEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
String ajaxHeader = request.getHeader("X-Requested-With");
if ("XMLHttpRequest".equals(ajaxHeader)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Ajax Request Denied (Session Expired)");
} else {
super.commence(request, response, authException);
}
}
}
While debugging after session expired, I noticed that it doesn't even enter to: AjaxAwareAuthenticationEntryPoint java class commence method.
What I'm missing here?
I know, that it is probably too late for the answer, but anyway the code you've attached helped me to resolve the absolutely same issue. To be honest, I don't see any issues in your code that makes it not to enter to the AjaxAwareAuthenticationEntryPoint, only may be you have some other configs behind the scene. But anyway, let my answer be an example for everyone, who struggles with the same issue, cause for me it works fine, and returns 403 if session is expired. I am using Spring Boot v2.3.5 and this is my code:
AjaxAwareAuthenticationEntryPoint.java
public class AjaxAwareAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
public AjaxAwareAuthenticationEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
String ajaxHeader = ((HttpServletRequest) request).getHeader("X-Requested-With");
if ("XMLHttpRequest".equals(ajaxHeader)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Ajax Request Denied (Session Expired)");
} else {
super.commence(request, response, authException);
}
}
}
WebSecurityConfig.java
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationFailureHandler authenticationFailureHandler;
#Autowired
private AccessDeniedHandler accessDeniedHandler;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/registration*").permitAll()
.antMatchers("/admin/**").hasAuthority("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error=true")
.defaultSuccessUrl("/admin", true)
.failureHandler(authenticationFailureHandler)
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login")
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.and()
.exceptionHandling()
.authenticationEntryPoint(new AjaxAwareAuthenticationEntryPoint("/login"));
}
}
and inside my main.js where I have some jquery ajax calls I have this:
$(document).ajaxError(function myErrorHandler(event, xhr, ajaxOptions, thrownError) {
if (xhr.status == 403) {
window.location.href ="/login";
}
});

Spring security Basic Auth and Form login for the same API

I would like to access all my API's via two authentication mechanisms, Basic Auth & Form login. I know that there are existing questions, but, the answers did not work for me, and my use case is a little bit different.
My config:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {
#Configuration
#Order(1)
public static class SecurityConfigBasicAuth extends WebSecurityConfigurerAdapter {
final private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
#Autowired
public SecurityConfigBasicAuth(RestAuthenticationEntryPoint restAuthenticationEntryPoint,
#Qualifier("customUserDetailsService") UserDetailsService userDetailsService) {
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
this.userDetailsService = userDetailsService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
// #Bean authenticationProvider()
// #Bean passwordEncoder()
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.cors()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin().disable()
.logout().disable();
}
}
#Configuration
public static class SecurityConfigFormLogin extends WebSecurityConfigurerAdapter {
final private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
final private RestfulSavedRequestAwareAuthenticationSuccessHandler restfulSavedRequestAwareAuthenticationSuccessHandler;
final private CustomAuthenticationProvider customAuthenticationProvider;
#Autowired
public SecurityConfigFormLogin(RestAuthenticationEntryPoint restAuthenticationEntryPoint,
RestfulSavedRequestAwareAuthenticationSuccessHandler restfulSavedRequestAwareAuthenticationSuccessHandler,
CustomAuthenticationProvider hashAuthenticationProvider) {
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
this.restfulSavedRequestAwareAuthenticationSuccessHandler = restfulSavedRequestAwareAuthenticationSuccessHandler;
this.customAuthenticationProvider = customAuthenticationProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.cors()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.csrf().disable()
.httpBasic().disable()
.formLogin()
.usernameParameter("id1")
.passwordParameter("Id2")
.loginProcessingUrl("/test/login")
.successHandler(restfulSavedRequestAwareAuthenticationSuccessHandler)
.failureHandler(myFailureHandler())
.and()
.logout();
}
// #Bean myFailureHandler()
}
}
As you can see, I defined two 'WebSecurityConfigurerAdapters', one for Basic Auth, and one for Form login. The Form login is REST compatible (does not redirect, but gives HTTP responses).
The problem is as follows: The first 'WebSecurityConfigurerAdapter' that is loaded works and overrides the second. The above example, makes it possible to use basic auth, but I cannot login on POST '/test/login', I get a:
{
"timestamp": 1534164906450,
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/test/login"
}
Update fixed: the key was to use the 'requestMatchers()', see answer section for solution (as suggested by jzheaux)
Okay, this is how I fixed this:
I configured the Basic Auth configuration as:
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/api/**")
.and()
.cors()
.and()
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and();
}
If you do not want that the basic authentication returning new cookie with new JSESSIONID, add:
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.sessionFixation()
.migrateSession()
The Form login configuration as:
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers(HttpMethod.POST, "/test/login")
.and()
.cors()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin()
.usernameParameter("id1")
.passwordParameter("id2")
.loginProcessingUrl("/test/login")
.successHandler(authenticationSuccessHandler)
.failureHandler(myFailureHandler())
.and()
.logout();
}
Now, it is possible for me to authenticate via the Form login configuration, and use the cookie session id to call /api/** (configured in the Basic Auth configuration). I can also just use the Basic Auth authentication ofcourse.

Spring security only allowed oauth login

In my project, i just want to allow oauth login. my spring security config as follow:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login.html", "/oauth/**", "/sign**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().disable()
.httpBasic().disable()[enter image description here][1]
.exceptionHandling().accessDeniedPage("/login.html")
.and()
.apply(new SpringSocialConfigurer());
}
The problem is the access denied page not working. I want to get login.html content as follow:
login.html
in fact i got 403 page as follow:
403
How to solve this problem?
I solve this problem, the code as follow:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login.html", "/oauth/**", "/sign**").permitAll()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.defaultAuthenticationEntryPointFor(new HttpForbiddenEntryPoint(), AnyRequestMatcher.INSTANCE)
.and()
.logout()
.logoutUrl("/logout.html")
.clearAuthentication(true)
.logoutSuccessUrl("/login.html")
.and()
.apply(new SpringSocialConfigurer());
}
The entry point:
public class HttpForbiddenEntryPoint implements AuthenticationEntryPoint {
private String redirect_url = "/login.html";
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendRedirect(redirect_url);
}
public String getRedirect_url() {
return redirect_url;
}
public void setRedirect_url(String redirect_url) {
this.redirect_url = redirect_url;
}
}

Spring security: Redirect unauthorised url

#PreAuthorize("hasPermission(#id,'Integer','write')")
#RequestMapping(value="events/{id}/edit",method=RequestMethod.GET)
public String edit(Model model,#PathVariable("id") int id) {
model.addAttribute("event", eventService.getEvent(id));
return "events/edit";
}
Security config
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/", "/index", "/register", "/regitrationConfirm", "/forgotPassword", "/accountRecovery", "/passwordReset", "/public/**").permitAll()
.antMatchers(HttpMethod.POST, "/register", "/accountRecovery","/passwordReset").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginPage("/login?error")
.permitAll()
.failureHandler(authFailureHandler)
.and()
.rememberMe()
.tokenValiditySeconds(3600)
.key("rememberTracker")
.and()
.logout()
.permitAll()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.sessionManagement()
.maximumSessions(1)
.expiredUrl("/login?expired");
}
}
i want to redirect or show a custom page to the user if authorization fails. Is there a way to that?
updated with spring security code.
Thanks
I updated you SecurityConfig to add a failureUrl and successHandler
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/", "/index", "/register", "/regitrationConfirm", "/forgotPassword", "/accountRecovery", "/passwordReset", "/public/**").permitAll()
.antMatchers(HttpMethod.POST, "/register", "/accountRecovery","/passwordReset").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginPage("/login?error")
.permitAll()
.failureUrl("/your-unsuccessful-authentication-url-here")
.successHandler(yourSuccesshandler) //create your success handler to redirect the user to different places depending on his role
//.failureHandler(authFailureHandler) I deleted this line, we just need a redirect
.and()
.rememberMe()
.tokenValiditySeconds(3600)
.key("rememberTracker")
.and()
.logout()
.permitAll()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.sessionManagement()
.maximumSessions(1)
.expiredUrl("/login?expired");
}
}
The success Handler
public class SuccessAuthenticationHandler implements AuthenticationSuccessHandler{
public SuccessAuthenticationHandler(){
}
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication auth) throws IOException, ServletException {
HttpSession session = request.getSession();
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String redirect = "";
if(user != null){
session.setAttribute("username", user.getUsername());
if(user.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ADMIN"))
|| user.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN")))
redirect = "admin/";
else if(user.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_YOUR_ROLE")))
redirect = "yourrole/";
}
if(redirect.isEmpty())
redirect = "signin";
response.sendRedirect(redirect);
}
}

Resources