How to post Antiforgery token from IdentityServer 3 - asp.net-core-mvc

I am using IdentityServer 3 for authentication. When user is authenticated then IdentityServer makes a 'POST' request to client's application url. For example http://localhost/home so far so good everything is working fine.
My Client application is developed in ASP.NET Core. In client application i want to validate every POST request. So instead of adding ValidateAntiForgeryToken attribute on each action method, i have created a middleware that validates every POST request.
public class ValidateAntiForgeryTokenMiddleware
{
private readonly RequestDelegate _next;
private readonly IAntiforgery _antiforgery;
public ValidateAntiForgeryTokenMiddleware(RequestDelegate next, IAntiforgery antiforgery)
{
_next = next;
_antiforgery = antiforgery;
}
public async Task Invoke(HttpContext httpContext)
{
if (httpContext.Request.Method.ToUpper() == "POST")
{
await _antiforgery.ValidateRequestAsync(httpContext);
}
await _next(httpContext);
}
}
The problem here is since identityserver is also making POST, the middleware tries to validate that request but the POST request fails with the following error
"The required antiforgery cookie
\".AspNetCore.Antiforgery.AXelvXewLHI\" is not present."
In Identity Server i have custom login page. and i have configured anti-forgery-token in login page.
<div ng-show="model.loginUrl">
<div class="cr-login-dialog col-md-6 col-md-offset-3">
<form name="form" method="post" action="{{model.loginUrl}}" class="form-horizontal" role="form">
<anti-forgery-token token="model.antiForgery"></anti-forgery-token>
<div class="form-group">
//user name controls goes here
</div>
<div class="form-group">
//password controls goes here
</div>
<div class="form-group" ng-show="model.allowRememberMe">
// remember me controls goes here
</div>
</form>
</div>
</div>

You should separate out your anti-xsrf middleware to only run on your requests, not the requests to IdentityServer. IdentityServer does its own anti-xsrf token unrelated to MVC's implementation (as IdentityServer has no dependencies on MVC).

Related

I can't send a POST request using my browser?

I am working on an application using Spring Boot MVC and I have a login page and whenever I input data on the forms using chrome my browser doesn't redirect me to the page I've specified in my Controler class but instead It sends a GET request where it should be sending a POST request. This is my controller class
#Controller
#RequestMapping("/login")
public class loginController {
private final AuthService authService;
public loginController(AuthService authService) {
this.authService = authService;
}
#GetMapping
public String returnLogIn() {
return "login";
}
#PostMapping
public String login(#RequestParam String username, #RequestParam String password, Model model) {
User user = null;
try {
user = this.authService.login(username, password);
model.addAttribute("User", user);
return "redirect:/home";
} catch (InvalidArgumentsException exception) {
model.addAttribute("hasError", true);
model.addAttribute("error", exception.getMessage());
return "login";
}
}
}
As you see if the login is successful then I should be redirected to the home page but It doesn't happen I get redirected to the login page again and all that changes is the URL in it the parameters I've given are appended. But when I use POSTMAN everything works just fine a POST request is sent and I get redirected to the /home page just like I've specified it in my Controller class. But I don't know why this wont happen when I use chrome. Having to use POSTMAN everytime I do a small change is really time-consuming. Also this is the HTML form
<form id="form-id" th:action="#{/login}" th:method="post">
<div class="mb-3">
<input type="text" class="form-control" name="username" id="username" aria-describedby="emailHelp"
placeholder="User Name">
</div>
<div class="mb-3">
<input type="password" class="form-control" name="password" id="password" placeholder="Password">
</div>
<!-- TODO use hasError set it in the model -->
<div th:if="${hasError}">
<span class="error text-danger" th:text="${error}"></span>
</div>
<div class="text-center"><button type="submit" class="btn btn-color px-5 mb-5 w-100 btn btn-dark" >Login</button></div>
</form>
I don't think there is something wrong with my code since everything works fine when I use POSTMAN but I really don't know why It wont work when I use my browser. Javascript is enabled in my browser I really don't know what seems to be the issue. I also tried mapping the POST request to a different URL but still I get the same issue.
I also believe that your code sample has no problem because if there is a problem it should not respond correctly from POSTMAN,Unless you have configured the application server and restricted requests from the browsers.
The suggestion I can give you is to monitor requests when sending a request using tools like Fiddler (Fiddler is a powerful web debugging proxy),etc.. ,to see if both requests send the same parameters to server .

How to add an element id to the url of the Thymeleaf template in the controller in Spring

I have a Spring Application and Server Side Rendering with Thymeleaf as Templating language.
A button sends a get or post request to the controller in Spring, which puts some message to the view, which is rendered into the HTML file and send back to the client. The message should be optional. Thats why the template must also be able to be called without the message.
Next i want the client browser to scroll down to the part of the page where this message is rendered into, which is normally very easy. You would just have to append the id of the element to the url like following example.
https://stackoverflow.com/#footer
In this example the browser scrolls down to the footer of the page.
Below is what i tried. Unfortunately it doesnt't work like that. Spring/Thymeleaf tries to find a index#messagebox template which can't be found. Hence a Whitelabel Error Page error is thrown/shown.
Page.html
<section>
<h2>Form to send request</h2>
<form action="showmessage" method="get">
<input type="submit" value="Click for message">
</form>
</section>
Controller.java
#GetMapping("showmessage")
public ModelAndView showMessage(){
return new ModelAndView("index#messagebox",Map.of("optionalmessage","Some message that is optioal"));
}
src/main/resources/templates/index.html
<body>
<h1>Index Page</h1>
<div id="messagebox" th:fragment="message" th:with="optionalmessage=${optionalmessage}">
<p th:if="${optionalmessage!=null}">[[${optionalmessage}]]</p>
</div>
</body>
The problem can be solved with Flashmessages and Redirects. The html basically keeps the same. If the message attribute is set, you render it.
src/main/resources/templates/index.html
<div th:if="${msg}">
<div class="message" >
<p>[[${msg}]]</p>
</div>
</div>
The most important changes had to be made in the controller. First a parameter of type RedirectAttributes is added to the Controller that handles the request.
If wanted the message is added with the RedirectAttributes.addFlashAttribute function as shown below. Finally a redirect is returned, which contains the needed tag. A second controller is also needed that handles the Get Request of the Redirect with a Model as input parameter and returns the needed Template. The #tag is simply passed throuhg to the client browser.
Controller.java
#GetMapping("showMessage")
public String postNotification(RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("optinalMessage", "Hello I am an optional message");
return "redirect:/index#footer";
}
#GetMapping("index")
public String getIndex(Model model) {
return "index";
}
You add id in URL by using ?id=value.
And in controller #RequestMapping("/path/{id}")
to access that variable #PathVariable

How to handle session to keep login information using Spring MVC

I want to make login form with Spring MVC using Hibernate.
I found that I need to use 'session' to keep login information.
So, I use it in 'Controller.java', '.jsp'.
But It seems didn't work.
Below is my code. Controller.java:
#Controller
public class PassengerController {
#Autowired
private PassengerService passengerService;
public void setPassengerService(PassengerService passengerService) {
this.passengerService = passengerService;
}
#RequestMapping(value = "/login")
public String login(HttpSession session, HttpServletRequest request) {
String id = request.getParameter("idInput");
String pw = request.getParameter("pwInput");
// check DB
// if it is right, add session.
session.setAttribute("id", id);
session.setAttribute("pw", pw);
return "flightschedule";
}
#RequestMapping(value = "/logout")
public String logout(HttpSession session) {
session.invalidate();
return "flightschedule";
}
}
Below is part of flightschedule.jsp:
<c:if test="${sessionScope.loginId eq null}">
<!-- Not login: show login button -->
<div class="loginArea">
<form action="${loginAction}"> <!-- // URL '/login' -->
<input type="text" name="idInput" placeholder="ID" class="loginInput">
<input type="password" name="pwInput" placeholder="PASSWORD" class="loginInput">
<input id="loginButton" type="submit" value="login">
</form>
</div>
</c:if>
<c:if test="${sessionScope.loginId ne null}">
<!-- already login: show logout button -->
<div class="loginArea">
<form action="${logoutAction}"> <!-- // URL '/logout' -->
<input type="button" name="idInput" id="loginInfo" value="Welcome ${sessionScope.loginId}">
<input id="logoutButton" type="submit" value="LOGOUT">
</form>
</div>
</c:if>
I intended that when session.id exists, show log out button and when session.id doesn't exist, show login button.
I don't want to use interceptors or spring security etc..
I thought they're too complex to my little project.
And, I have login/logout form at all most of my pages. I don't use a separate page to login.
So I don't want to use interceptor. I just want to check whether session key exists in some jsp pages. Depending on its presence, I want to change page's view.
Above's code work partly. When login, it shows 'Welcome userId'.
But, when I click page's logo(then go to the first page), It still show 'login' button. It have to show 'log-out' button becuase session.loginId exists!
Do you have any solution?
In login method you put
// check DB
// if it is right, add session.
session.setAttribute("id", id);
session.setAttribute("pw", pw);
but on JSP check sessionScope.loginId , looks like you should check attribute with name id.

Why this Spring MVC controller method can't handle this POST Request (Content type 'application/x-www-form-urlencoded' not supported)

I am working on a Spring MVC application and I have the following problem.
Into a FreeMarker view (but is not so important that the view is made using FreeMarker) I have this form:
<form id="reg-form" name="reg-form" action="<#spring.url '/iscrizioneStep2' />" method="post">
<fieldset>
<div class="form-group">
<label for="cf">Codice fiscale:</label>
<input type="text" id="cf" name="codiceFiscale" class="form-control input-mm" placeholder="Inserisci il tuo codice fiscale" data-validation="[NOTEMPTY, NOSPACE, L==16, CF]" data-validation-label="codice fiscale" aria-required="true" tabindex="10">
</div>
<div class="form-group">
<div class="g-recaptcha" data-sitekey="6LcOfhcTAAAAAE3D2hsa3UcyTQ0PI4upcZ759FDa" tabindex="20"></div>
</div>
<button type="submit" class="btn btn-block submit-btn" aria-label="prosegui la registrazione" tabindex="30">Passaggio 2</button>
</fieldset>
</form>
As you can see the form is submittet to this action: action="<#spring.url '/iscrizioneStep2' />" performing a POST request.
This generate a POST request toward this URL (I see it using FireBug):
http://localhost:8080/iam-ssum-public/iscrizioneStep2?codiceFiscale=AAAAAAAAAAAAAAAA&g-recaptcha-response=
So I think that it should send the input field having name="codiceFiscale" into the POST request.
Then I have this controller method:
#RequestMapping(value = "/iscrizioneStep2", method = RequestMethod.POST)
public String iscrizioneStep2(#RequestBody(required = true) IscrizioneStep1Form iscrizioneStep1Form, Model model)
throws APIException {
/*
* Verifica se l'utenza รจ attivata per il codice fiscale
*/
String codiceFiscale = iscrizioneStep1Form.getCodiceFiscale();
..............................................................
..............................................................
..............................................................
return "myView";
}
So the data sended in the post request should be putted inside the IscrizioneStep1Form iscrizioneStep1Form parameter, that is:
public class IscrizioneStep1Form {
/**
* Codice fiscale
*/
private String codiceFiscale;
public String getCodiceFiscale() {
return codiceFiscale;
}
public void setCodiceFiscale(String codiceFiscale) {
this.codiceFiscale = codiceFiscale;
}
}
But the problem is that this HTTP POST request is not handled by the iscrizioneStep2() method. When I submit the form don't enter into this method and into the Eclipse console I obtain the following error message:
11:55:43,949 WARN [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver] (http-localhost/127.0.0.1:8080-6) Handler execution resulted in exception: Content type 'application/x-www-form-urlencoded' not supported
Why? What am I missing? How can I fix this issue?
Try to add heders param to your RequestMapping annotation:
#RequestMapping(value = "/iscrizioneStep2", method = RequestMethod.POST,
headers = "content-type=application/x-www-form-urlencoded")
Try to remove #RequestBody(required = true) from your request method.
Here Spring Mvc Rest Webservice jstl form submittion HTTP Status 415 Content type 'application/x-www-form-urlencoded' not supported has the same problem.
There is no built-in converter that knows how to convert content of the type 'application/x-www-form-urlencoded to IscrizioneStep1Form. Simply omit #RequestBody. Form data is automatically mapped to objects.
The problem is that when we use application/x-www-form-urlencoded, Spring doesn't understand it as a RequestBody. So, if we want to use this
we must remove the #RequestBody annotation.
Then try the following:
#RequestMapping(value = "/iscrizioneStep2", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String iscrizioneStep2(IscrizioneStep1Form iscrizioneStep1Form, Model model) throws APIException {
//method body where
}
Note that removed the annotation #RequestBody
answer: Http Post request with content type application/x-www-form-urlencoded not working in Spring

Spring relationships between tables in view

Well, I started a new project using Spring MVC (I'm beginner in technology) and soon I had a basic question which I am unable to find on the internet, maybe the reason that I'm doing wrong or implementing the wrong question.
I have a form in which the data will be persisted are in two different tables.
What better way to do this?
I created two related tables, one called "Agency" and another called "Login". An "Agency" may contain one or more "Login" (# OneToMany), but the problem takes the view creation time, because data from both tables will compose a single form. With some research I noticed that I can not have two modelAttribute in my form.
I apologize for the mistakes in English.
Best regards!
if the mapping is correct and Agency contain one or many login, what you have to do is render the Agency in the model and view and in your form iterate the logins
<form:form id="foo"
method="post"
action="url"
modelAttribute="agency">
<form:input type="hidden" path="id"/>
<c:forEach var="login" items="${agency.logins}"
varStatus="login_index">
<form:input type="hidden" path="login.id" />
</c:foreach>
</form:form>
thanks for the reply.
But is not it :(
I have a form in which the data will be persisted are in two different tables.
<form class="form-signin" method="post" action="addAgency">
<div class="input-group">
<span class="input-group-addon entypo-user"></span>
//Table Agency
<spring:bind path="tenant.firstName"/>
<input class="form-control" placeholder="Nome"/>
//Table Login
<spring:bind path="login.email"/>
<input class="form-control" placeholder="Nome"/>
</div>
//Rest of my form...
</form>
In my view I have the annotation "bind" Spring, searching in the internet I found this way to make the connection between the controller and the view for persist two tables.
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(#ModelAttribute("tenant") Agency tenant, #ModelAttribute("login") Login login, ModelMap map) {
Agency agency = dashboardFacade.getAgency();
map.addAttribute("agency", agency);
if (tenantResolver.isMasterTenant()) {
//Here is the problem!!
// Add an attribute in my view of type login and agency, but i don't kwon if it is correct.
map.addAttribute("tenant", tenant);
map.addAttribute("login", login);
return "landing/index";
} else {
return "dashboard/home";
}
}
The method below to save an agency and login.
// Add a new agency
#RequestMapping(value = "/addAgency", method = RequestMethod.POST)
public String addAgency(#ModelAttribute("tenant") Agency agency, #ModelAttribute("login") Login login, Model model, final RedirectAttributes redirectAttributes) {
agency = dashboardFacade.addAgency(agency);
login = dashboardFacade.addLogin(login);
return "redirect:" + getAgencyFullUrl(agency);
}
What better way to do this?
Thank you

Resources