Spring Security 4 : Request method 'POST' not supported - spring

The issue is that when I click on submit I get
Etat HTTP 405 - Request method 'POST' not supported
Here is the controller :
#RequestMapping(value = "/admin/login", method = RequestMethod.GET)
public ModelAndView login(
#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout) {
LOGGER.debug("admin login page");
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("/admin/index");
LOGGER.debug("returning admin login page");
return model;
}
And the form :
<form class="m-t" role="form" th:action="#{/admin/login}" method="POST" autocomplete="off">
<div th:if="${param.error}" class="alert alert-danger">Invalid username and password.</div>
<div th:if="${param.logout}" class="alert alert-success">You have been logged out.</div>
<div class="form-group">
<input type="text" class="form-control" id="username" name="username" placeholder="Username" required="" />
</div>
<div class="form-group">
<input type="password" class="form-control" id="username" name="username" placeholder="Username" required="" />
</div>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<button type="submit" class="btn btn-primary block full-width m-b">Login</button>
<small>Forgot password?</small>
<p class="text-muted text-center">
<small>Do not have an account?</small>
</p>
<a class="btn btn-sm btn-white btn-block" href="register.html">Create an account</a>
</form>
It seems like csrf field not working.
I explain, I have normal users website which I refer here by and admin part which is /admin
The login form is correctly displayed. But I when I click submit I get Etat HTTP 405 - Request method 'POST' not supported
Any idea please ?
Here is my security configuration class :
package com.mintad.spring.security;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
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.security.core.userdetails.UserDetailsService;
/**
* #author Sofiane HAMMAMI
*/
#Configuration
#EnableWebSecurity
#ComponentScan
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
#Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/**").permitAll()
// .antMatchers("/admin/**").access("hasRole('ADMIN')")
.and().formLogin().loginPage("/login")
.defaultSuccessUrl("/welcome").usernameParameter("username").passwordParameter("password")
.and().exceptionHandling().accessDeniedPage("/404");
}
}

In controller , you defined the form as GET:
#RequestMapping(value = "/admin/login", method = RequestMethod.GET)
and in the form, you are calling it as POST:
form class="m-t" role="form" th:action="#{/admin/login}" method="POST"
change one of these, either at controller or in the form.
If you want to change at controller, replace existing line with:
#RequestMapping(value = "/admin/login", method = RequestMethod.POST)
or you can do it by modifying call from form like
form class="m-t" role="form" th:action="#{/admin/login}" method="GET"

Change your security config to use /admin/login as your login page:
...
.formLogin().loginPage("/admin/login")

Reason you get 405 is, you are trying to submit your form with http post method and defined the end point with http get method.
You need to change your request mapping to method as POST like:
#RequestMapping(value = "/admin/login", method = RequestMethod.POST)
OR you could do vice versa (which is not recommend by security reasons) in your form like:
<form class="m-t" role="form" th:action="#{/admin/login}" method="GET" autocomplete="off">

Related

Request method 'POST' not supported in spring MVC web app

i am using .html in mvc app. it's showing app perfectly.inside login.html i have used form with method POST for submission but when i submit form showing error that POST is not supported.but when i change everything with .jsp then it let submit form.
here's the controller
#Controller
public class mainController {
#RequestMapping("/login")
public ModelAndView login(Locale locale , Model m) {
System.out.println("modal");
return new ModelAndView ("login");
}
#RequestMapping(path = "/user" , method=RequestMethod.POST)
public String user(#ModelAttribute("user") User user) {
System.out.println(user);
return "user";
}
}
this is login form
<form action="user" method="post" name="user">
<input type="text" name="username" placeholder="uname"/> <br>
<input type="password" name="password" placeholder="password"/> <br>
<input type="date" name="date" placeholder="date"/> <br>
<button type="submit">Submit</button>
</form>
what can I do to submit form using POST method from .html file.

How to POST data using API in Postman

I am creating an API by using spring boot. Basically, this API does CRUD operations. And also I created a client that consumes my own API. At first I use Postman to POST data, it successfully insert data to the database and gives me 200 OK code. Then I created web page and I use my API as form action. Then I tried to insert data using the API. But, couldn't. Then I removed #RequestBody from the method and after that I was able to insert data. But the thing is now I can't insert data using Postman. When I try to insert data using Postman, it gives me 200 OK, but nothing insert to the database.
How can I Fix this ??
package com.kisalka.pacrestapi.controller;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.kisalka.pacrestapi.repository.ImRepository;
import com.kisalka.pacrestapi.model.ImModel;
#RestController
#RequestMapping("/api")
public class ImController {
#Autowired
private ImRepository TaskRepository;
#RequestMapping(method=RequestMethod.POST, value="/tasks")
public ImModel createNote(ImModel note) {
return TaskRepository.save(note);
}
}
My web page.
<form class="form-horizontal" method="POST" action="">
<div class="form-group">
<label class="control-label col-md-3">Project Name</label>
<div class="col-md-7">
<input type="text" class="form-control" name="pname" id="txtPname"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Developer Name</label>
<div class="col-md-7">
<input type="text" class="form-control" name="devname" id="txtDevname"/>
</div>
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Save" id="btnRegister"/>
</div>
</form>
In one of your #Configuration classes or #EnableAutoConfiguration class create a bean of CommonsRequestLoggingFilter, paste the code. This will log every incoming request
#Bean
public CommonsRequestLoggingFilter logFilter() {
CommonsRequestLoggingFilter filter
= new CommonsRequestLoggingFilter();
filter.setIncludeQueryString(true);
filter.setIncludePayload(true);
filter.setMaxPayloadLength(10000);
filter.setIncludeHeaders(false);
filter.setAfterMessagePrefix("REQUEST DATA : ");
return filter;
}
And in your application.properties file set logging level to DEBUG using logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=
DEBUG
All set! now call your endpoint from the WEB/Postman and check if you find the missing piece.
You need to use #RequestBody :
#RequestMapping(method=RequestMethod.POST, value="/tasks")
public ImModel createNote(#RequestBody ImModel note) {
return TaskRepository.save(note);
}
use the code written below.You need to add #RequestBody before ImModel note
#RequestMapping(method=RequestMethod.POST, value="/tasks")
public ImModel createNote(#RequestBody ImModel note) {
return TaskRepository.save(note);
}

Spring Boot ModelAndView - cannot update value to Model

I am trying to create a form with 3 fields within the class LoginForm: usuario, senha, msgLogin.
I receive the fields usuário and senha from the input boxes and then I try to redirect to the same page with the same fields plus the field MsgLogin. But I've not been able to update the msgLogin field and I don't understand why.
These are the code:
HTML:
<form id="frmLogin" class="form col-md-12" action="#" th:action="#{/login}" th:object="${loginForm}" method="post">
<div class="form-group">
<label for="usuario" class="col-md-1">Usuário: </label>
<input type="text" id="usuario" placeholder="Email" th:field="*{usuario}"/>
</div>
<div class="form-group">
<label for="senha" class="col-md-1">Senha: </label>
<input type="password" id="senha" placeholder="senha" th:field="*{senha}"/>
</div>
<div class="row">
<button id="entrar">Entrar</button>
</div>
<div class="row">
<div id="msgLogin"></div>
<p th:text="${loginForm.msgLogin}" />
</div>
</form>
The Controller:
#RequestMapping("/")
public String init(#ModelAttribute LoginForm loginForm) {
Logger.getAnonymousLogger().info("Tela Inicial.");
return "home";
}
#PostMapping("/login")
public ModelAndView entrar(LoginForm loginForm) throws IOException {
Logger.getAnonymousLogger().info("Entrando no Internet Banking.");
service.login(usuario, senha);
ModelMap model = new ModelMap();
loginForm.setMsgLogin("I want to update that value!");
model.addAttribute("loginForm", loginForm);
return new ModelAndView("redirect:/", model);
}
Class using Lombok:
#Getter
#Setter
public class LoginForm {
private String usuario;
private String senha;
private String msgLogin;
}
A redirect send a 302 HTTP status back to the browser to resubmit using a new url, so it resubmits the same two fields to the new url. There's no expectation of payload data in the 302 response.
In your Controller, change the last line in your entrar method to: return new ModelAndView("/login", model);

how could I use csrf in spring security

My login page.
<form class="form-horizontal" ng-controller="loginCtrl" action="/login" method="post">
<div class="form-group input-login">
<div ng-if="message.error" class="alert alert-danger">
<p>Invalid username and password.</p>
</div>
<div ng-if="message.logout" class="alert alert-success">
<p>You have been logged out successfully.</p>
</div>
<label class="control-label sr-only">Email</label>
<div class="col-md-12">
<input type="text" class="form-control" ng-model="user.username" name="username" placeholder="NickName"/>
</div>
</div>
<div class="form-group input-login">
<label class="control-label sr-only">Password</label>
<div class="col-md-12">
<input type="password" class="form-control" ng-model="user.password" name="password" placeholder="Password"/>
</div>
</div>
<input name="_csrf" type="hidden" value="6829b1ae-0a14-4920-aac4-5abbd7eeb9ee" />
<div class="form-group sub-login">
<div class=" col-md-12">
<button name="submit" type="submit" class="btn btn-primary btn-login">Login</button>
</div>
</div>
</form>
But if I didn't disable the csrf,it alway be accessDenied.I don't know where is the problem.
My config code below.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDao userDao;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserService(userDao)).passwordEncoder(new MD5Util());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/index").access("hasRole('USER')")
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login#/signin?error=1")
.successHandler(new LoginSuccessHandler())
.usernameParameter("username").passwordParameter("password")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login#/signin?logout=1")
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied")
.and().csrf().disable(); // If I disable this csrf,it worked!
}
}
And does anyone knows how to ues thymeleaf in ng-route's partial page.Just see this question.
Your best bet would be to have a look at this link: https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii
Particularly, the relevant section is:
CSRF Protection
That’s good because it means that Spring Security’s built-in CSRF protection has kicked in to prevent us from shooting ourselves in the foot. All it wants is a token sent to it in a header called “X-CSRF”. The value of the CSRF token was available server side in the HttpRequest attributes from the initial request that loaded the home page. To get it to the client we could render it using a dynamic HTML page on the server, or expose it via a custom endpoint, or else we could send it as a cookie. The last choice is the best because Angular has built in support for CSRF (which it calls “XSRF”) based on cookies.
So all we need on the server is a custom filter that will send the cookie. Angular wants the cookie name to be “XSRF-TOKEN” and Spring Security provides it as a request attribute, so we just need to transfer the value from a request attribute to a cookie:
public class CsrfHeaderFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie==null || token!=null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
After a bit more work, the last sentence is:
With those changes in place we don’t need to do anything on the client side and the login form is now working.
You should include an input hidden to send the CSRF token in the POST method when the user submit the form.
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
You already included a input hidden _csrf in your template, but the value is wrong, just change it.
You can read more about CSRF here:
https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html

Spring Boot newbie - Request method 'POST' not supported

There are a lot of similar questions to this, I have looked at them but still couldn't figure out what my problem is. Would really appreciate help with this.
This is my controller:
#RestController
#RequestMapping(value = "/game")
public class YatzyController {
#Autowired
private Games games;
#RequestMapping(value = "/{DiceDTO}", method = RequestMethod.POST)
public GameState putGameState(#ModelAttribute("DiceDTO") DiceDTO diceDTO) {
return null;
}
And this is my HTML:
<form method="post" enctype='application/json' action="/game">
<button type="button" onclick="rollDice()">Roll dice</button>
<div>
<input type="text" id="dice1" disabled>
<input type="checkbox" id="keepdice1" value="Keep">
</div>
<div>
<input type="text" id="dice2" disabled>
<input type="checkbox" id="keepdice2" value="Keep">
</div>
<input type="submit">
</form>
Configuration class:
#Configuration
public class YatzyConfiguration {
#Bean
public Games games(){
return new Games();
}
}
Posting to /game
You don't need value = "/{DiceDTO}" in #RequestMapping annotation, because Spring considers it as path's part. So Spring actually maps POST request to /game/somenting path in your case.

Resources