I am getting the following error whenever I try to do a simple form post in my MVC website.
Either BinaryRead, Form, Files, or InputStream was accessed before the internal storage was filled by the caller of HttpRequest.GetBufferedInputStream.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Either BinaryRead, Form, Files, or InputStream was accessed before the internal storage was filled by the caller of HttpRequest.GetBufferedInputStream.
My sample form and actions are pretty basic...
#using (Html.BeginForm("Create", "Form"))
{
<div class="row action">
<div class="row">
First name: <input type="text" name="fname"><br>
Last name: <input type="text" name="lname"><br>
</div>
<input type="submit" id="save" class="btn" value="Save"/>
<input type="button" id="cancel" class="btn" value="Cancel"/>
</div>
}
And my Controller action is even more basic...
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
// TODO: Add insert logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Please share your route.config file that might help solving this problem.
Just in case also try removing the perimeters from Html.BeginForm() remove the name of the action and controller. As MVC has strong naming systems because of which we don't need to add that info.
if above doesn't solve your issue Share your route file.
Related
I know this is a common question but I'm getting desesperated here, Im pretty newbie and have been stuck with this for a long time now... I know this is not a DispatcherServlet or Servlet Mapping error as I'm working on a really big project that has everything working already.
What I need to do is add a form on an already existing jsp page, here is what I have
CONTROLLER:
#Controller
#RequestMapping("/messaging")
public class MessagingController {
#GetMapping
public String messagingView(Principal principal, Model model) throws ServiceException {
model.addAttribute("messagingInformation", new MessagingInformation());
return foo; -> this returns me to the main jsp where I'm creating the form
}
#PostMapping(value = "/submitInformation") -> I've also tried with #RequestMapping(value = "/submitInformation", method = RequestMethod.POST)
public String submitInformation(#ModelAttribute(value = "messagingInformation") #Valid MessagingInformation messagingInformation) {
return "redirect:/messaging"; -> shouldn't this redirect me to the main jsp?
}
}
JSP:
<form:form action="messaging/submitInformation" modelAttribute="messagingInformation" method="POST">
<div class="row col-sm-12 margin-top-container">
<div class="col-sm-4">
<span class="titles-select-box uppercase-text">RECEIVER</span>
<input name="receiver" type="email" id="receiverId" name="receiverName"
placeholder="Receiver" multiple>
</div>
</div>
<div class="col-sm-12 no-padding-left">
<div class="button-container pull-right">
<input type="submit" value="Send" class="btn btn-default"
id="sendButton" />
</div>
</div>
</form:form>
I'm mainly getting --No mapping found for HTTP request with URI [/foo/messaging/submitInformation] in DispatcherServlet -- I've asked around and I shouldn't add nothing to any cofiguration file or anything, clearly it's something wrong on my side but I can't see it
Leaving this in case anyone finds out... I was requiered to do a manual build so the java changes would show up. This is done through Projects -> Build All
I tried to authenticate user from MySQL database with BCrypt using this
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().usersByUsernameQuery(USER_LOGIN_QUERY).authoritiesByUsernameQuery(GET_USER_ROLE_QUERY)
.dataSource(dataSource).passwordEncoder(bCryptPasswordEncoder);
}
on those requests here
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login").permitAll()
.antMatchers("/reg").permitAll().anyRequest().hasAuthority("ADMIN").anyRequest()
.authenticated().and().csrf().disable().formLogin().loginPage("/login").failureUrl("/login?error=true")
.defaultSuccessUrl("/").usernameParameter("username").passwordParameter("password").and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/").and()
.exceptionHandling().accessDeniedPage("/403");
}
on Login page
<div class="login-page">
<div class="form">
<form class="login-form" th:action="#{/login}" method="post">
<input type="text" placeholder="Username" id="username"
name="username" />
<input type="password" placeholder="Password" id="password"
name="password" />
<button type="submit">login</button>
<p class="message">
Not registered?
<a th:href="#{/reg}">Create an account</a>
</p>
</form>
<label th:if="${param.error}"
class="message text-danger text-capitalize">Login
credentials invalid</label>
</div>
</div>
Both overridden 'configure' methods do invoke when Web bootup. As I did put syserr to print out a random line to console from both.
I setup the datasource in application.properties and confirm it's correct since I can sign-up new user successfully. It's autowired
The USER_LOGIN_QUERY and GET_USER_ROLE_QUERY is normal too, it worked on MySQL query.
bCryptPasswordEncoder works since registering new user does encode password into hashed string. It's autowired
With jpa.show-sql = true, registering user(save to database) and other query do show SQL in the console. However, the two queries for authentication DON'T show up in the console log. So I assume login with post method never invoke authentication, hence, datasource, queries and passwordEncoder are not related
As a result, login always redirect me to failureUrl.
Where did I do wrong? How can I properly do authentication?
PS: On the other note,I follow the tutorial here https://github.com/gustavoponce7/SpringSecurityLoginTutorial , I build and run this tutorial source with no problem like above.
UPDATE: I tried new Spring Boot project, repeated the procedure to make a plain simple Spring Web with Security. jdbcAuthentication does authenticate for sometimes but giving me SQL query error. After correcting query error, BOOMM, nothing works again, even reverting edit won't do anything.
I'd like to create the form for editing some Entity (for example a post) in the database using the Entity Framework Core.
I want to protect the value PostId in the hidden field before rewriting to another value from the browser. I'm wondering about checking the user permissions before updating but I want to create some encryption/signing or something like that.
How can I encrypt or sign the PostId and in the controller decrypt or validate it?
I've created the example form for editing the post like this:
Entity - Post:
public class Post
{
[Key]
public int PostId { get; set; }
[Required]
[StringLength(40)]
public string Title { get; set; }
}
Controller - PostsController with Edit method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("PostId,Title")] Post post)
{
if (ModelState.IsValid)
{
//Update method
}
return View(post);
}
Form for editing:
#model EFGetStarted.AspNetCore.NewDb.Models.Post
#{
ViewBag.Title = "Edit Post";
}
<h2>#ViewData["Title"]</h2>
<form asp-controller="Posts" asp-action="Edit" method="post" asp-antiforgery="true" class="form-horizontal" role="form">
<div class="form-horizontal">
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="PostId" type="hidden" />
<div class="form-group">
<label asp-for="Title" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Edit" class="btn btn-default" />
</div>
</div>
</div>
</form>
By encrypting it you don't get any real business value and if the intent is so prevent one user to edit/modify posts he has no access to, you should do it in the backend by following the "Never trust the client" principle and always validate input on the server.
Easiest way to do is to use only the post ID from the model posted in and validate if the user has permissions to modify it. For this the new policy based systems offers resource based permissions which are well documented and can be used to validate the permissions.
Once done, passed take over the values and save the changes.
Also you shouldn't use persistence models inside the views, they easily break your API or your forms when the you change the database layout and navigation properties may cause issues (circular references etc.); especially later on, when lazy loading is implemented (lazy loading can't happen async as its inside a property, so the db call will block the thread).
Take a look at Sergey Akopov's blog post where he proposes a mechanism to deal with this scenario within ASP.NET MVC. His solution is to write a Html Helper that can be called within your view to generate a hidden input to accompany each input that you wish to make "tamper proof". This hidden input contains an encrypted copy of the value that you want to be tamper proof. When the form is posted, the server checks that the posted value and accompanying encrypted value still match - he writes a filter attribute which is applied to the corresponding controller action to perform this check. This adds an extra layer of "never trust the client" security.
Another example here has an interesting discussion (in the comments) around the potential security flaws inherent in this approach - The main one being that a determined attacker could "farm" valid combinations of secure field and encrypted value from their editing sessions, and subsequently use these farmed values to post tampered data with future edits.
In a system where I am using the Identity framework, I have the following form in a view that is bound to the model AppUser:
<div class="form-group">
<label>Name</label>
<p class="form-control-static">#Model.Id</p>
</div>
#using (Html.BeginForm("Edit", "Admin", new { returnUrl = Request.Url.AbsoluteUri }, FormMethod.Post, new { #id = "edituserform" }))
{
#Html.HiddenFor(x => x.Id)
<div class="form-group">
<label>Email</label>
#Html.TextBoxFor(x => x.Email, new { #class = "form-control" })
</div>
<div class="form-group">
<label>Password</label>
<input name="password" type="password" class="form-control" />
</div>
<input type="checkbox" name="userLockout" value="Account Locked" #(Html.Raw(Model.LockedOut ? "checked=\"checked\"" : "")) /> #:Account Locked <br>
<button type="submit" class="btn btn-primary">Save</button>
<button class="btn btn-default"
id="canceleditbutton">
Cancel
</button>
}
The model definition for AppUser:
public class AppUser : IdentityUser
{
public bool LockedOut { get; set; }
/*Other fields not shown for brevity*/
}
My specific question is regarding the checkbox for the LockedOut flag, which is a custom property I added. For a test user, I manually set the flag in the database to True and as expected, on the view the checkbox was checked when it was loaded. Now my goal is to be able to access this in the POST edit method of the AdminController that this form calls on submit. The skeleton for that method is as follows:
[HttpPost]
public async Task<ActionResult> Edit(string id, string email, string password, string userLockout)
{
//Code here to change the LockedOut value in the database based on the input received
}
The issue is that the userLockout parameter comes in as null when I click Save on the submit on the edit screen. The other two values are populated correctly. How can I access the userLockout value, so that I can continue with saving the change into the database if needed?
And lastly, my ultimate goal here is to implement a system where an admin can lock or unlock a user account via the LockedOut flag (which gets checked each time someone logs in). I know the Identity framework has support for lockouts, but this seems to be time restricted lockouts only. Is there a way that exists in the Identity framework to have permanent (unless manually changed) lockouts? I am trying to use as little custom code and design as possible, so that's why I am interested in knowing this as well. Particularly, I am interested in using the way the framework keeps track of unsuccessful login attempt counts, because I want to try to avoid implementing that manually as well.
Thank you.
Change userLockout type to bool in the Edit method and post should work.
To lock the user for a very long duration (a sub for permanent lock) after n failed attempts, one option is to set the DefaultLockoutTimeSpan to some x years in the future.
To check if a user is locked out, try UserManager.IsLockedOutAsync(userId)
I'm using Spring (3.1), Spring MVC (3.1) and Spring Security (3.0) in combination and I've put together a single JSP page that has two forms on it; One is a form to login and the other is a form to register (i.e. create a new user).
For the register form, I use the Spring form tags, backed up by a controller to handle the request but for the login form I don't bother with the Spring form tags as I don't believe they're needed. There is also no controller that I need to write to handle the form submission as Spring Security takes care of authenticating so long as the request is submitted to j_spring_security_check.
The register form is working fine but the login form is a problem. It seems that when I click the submit button on the login form, the registration form is also submitted, or at least Spring thinks I'm trying to submit that form. Here is the JSP:
<form id="loginform" method="POST" action="<c:url value='j_spring_security_check'/>">
<label for="existing_email">Email:</label>
<input name="j_username" id="existing_email" type="text" value="${SPRING_SECURITY_LAST_USERNAME}" />
<label for="existing_password">Password:</label>
<input name="j_password" id="existing_password" type="password" />
<input id="login-form-submit" type="submit" value="Sign in" />
</form>
<form:form id="registrationform" modelAttribute="user" method="POST" action="register">
<form:label path="username" for="email">Email:</form:label>
<form:input path="username" name="username" id="email" type="text" />
<form:errors path="username" cssClass="formError" />
<form:label path="password" for="password">Password:</form:label>
<form:input path="password" name="password" id="password" type="password" />
<form:errors path="password" cssClass="formError" />
<input id="registration-form-submit" type="submit" value="Sign up" />
</form:form>
Notice that form tags for the input of type submit are not present and this seems to be a normal thing to do in the examples I've seen. Adding form tags to the submit button I guess doesn't make sense as it doesn't map to anything on the target object (user in this case).
When I click the "Sign in" button I get the following exception:
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/project1] threw exception [An exception occurred processing JSP page /WEB-INF/views/registration.jsp at line 29
28: <form:form id="registrationform" modelAttribute="user" method="POST" action="register">
29: <form:label path="username" for="username">Username:</form:label>
30: <form:input path="username" name="username" id="username" type="text" />
31: <form:errors path="username" cssClass="formError" />
32:
Stacktrace:] with root cause
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'user' available as request attribute
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:141)
This I recognise from cases where you forget to include the modelAttribute attribute in form:form, but of course I don't want to submit this form to my controller.
I have a feeling there is a mistake I'm making or a simple solution. Can anyone recommend a way around this or perhaps a different approach?
Here is the controller method that handles requests to register in case that's needed:
#RequestMapping(value = "**/register", method = RequestMethod.POST)
public String registerUser(#ModelAttribute("user") #Validated User user, BindingResult errors, ModelMap model) {
if (errors.hasErrors()) {
return "registration";
}
// Other stuff then...
return "profile"
}
If you are using "user" modelAttribute in form tag then a non-null request attribute must be present with name "user".
One way to add that in request attribute is what you did in your answer above. Other ways are:
(1) Add in ModelMap:
#RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model) {
model.addAttribute("user", new User());
model.addAttribute("error", "true");
return "registration";
}
(2) Add in request scope (Using WebRequest or HttpServletRequest):
#RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model, WebRequest webRequest) {
webRequest.setAttribute("user", new User(), WebRequest.SCOPE_REQUEST);
model.addAttribute("error", "true");
return "registration";
}
(3) Use #ModelAttribute on method:
#ModelAttribute("user")
public User user() {
return new User();
}
Please also see Using #ModelAttribute on a method and Using #ModelAttribute on a method argument
Also note that you don't have to use type attribute. See form:input and form:password.
I think the problem is specifically when a login fails and the same page is served up, albeit on a different URL path and so through a different controller method. Therefore my original suspicion that the issue is that both forms are submitted may be something of a red herring, though I still don't fully understand what's going on and that may yet have something to do with it. In any case, this is what corrected the problem for me:
I had a controller method that originally looked like this:
#RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model) {
model.addAttribute("error", "true");
return "registration";
}
In the Spring Security context I specify /loginfailed as the path to go to by default if a login attempt fails. This is where it seems the user object is needed so if I alter the signature as follows it all works:
#RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(#ModelAttribute("user") User user, BindingResult errors, ModelMap model) {
model.addAttribute("error", "true");
return "registration";
}
Any comments/clarification welcome from others.