Upload a file MVC 4 Web API .NET 4 - .net-4.0

I'm using the version of MVC that shipped with Visual Studio 2012 express. (Microsoft.AspNet.Mvc.4.0.20710.0)
I assume this is RTM version.
I've found plenty of examples online which all use this code:
public Task<HttpResponseMessage> PostFormData()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
// Read the form data and return an async task.
var task = Request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
}
// This illustrates how to get the file names.
foreach (MultipartFileData file in provider.FileData)
{
Trace.WriteLine(file.Headers.ContentDisposition.FileName);
Trace.WriteLine("Server file path: " + file.LocalFileName);
}
return Request.CreateResponse(HttpStatusCode.OK);
});
return task;
}
But this code always ends up in continueWith where t.IsFaulted == true. The exception reads:
Unexpected end of MIME multipart stream. MIME multipart message is not
complete.
Here is my client form. NOthing fancy, I want to do jquery form pluging for ajax upload, but I can't even get this way to work.
<form name="uploadForm" method="post" enctype="multipart/form-data" action="api/upload" >
<input type="file" />
<input type="submit" value="Upload" />
</form>
I've read that it is caused by the parser expecting /CR /LF at the end of each message, and that bug has been fixed in June.
What I cannot figure out is, if it was really fixed, why isn't it included this version of MVC 4? Why do so many examples on the internet tout that this code works when it does not in this version of MVC 4?

You are missing a name attribute on your file input.
<form name="uploadForm" method="post" enctype="multipart/form-data" action="api/upload" >
<input name="myFile" type="file" />
<input type="submit" value="Upload" />
</form>
Inputs without it will not get submitted by the browser. So your formdata is empty resulting in IsFaulted being asserted.

Related

Blazor Server auth with jwt

I have been trying for a few days to do client-side persistence token authorization. The problem is that we essentially cannot use IJSRunrime when a user request comes in to check his authentication, because ServerRendering does not run before initialization on the client. I also tried to use cookies in order to save them in the request, but we cannot do this either due to the fact that the request has already been started, for example, in the same MVC, we can do this without problems.
Detailed errors:
IJSRunrime - "JavaScript interop calls cannot be issued at this time"
Cookie - "headers are read-only, response has already started"
I create this code for example and my question - How save token on the client side?
UPD: I don't want to reload SPA application, some examples do it and I can't use HttpContext.SignIn because have Cookie error.
#page "/SignIn"
<EditForm EditContext="#editContext" OnValidSubmit="SendRequestSubmit" class="auth__form">
<DataAnnotationsValidator />
<div class="auth__item">
<h4 class="auth__actions-title actions-title">Email<span>*</span></h4>
<InputText #bind-Value="signInRequest.Email" class="input-actions" />
</div>
<div class="auth__item">
<h4 class="auth__actions-title actions-title">Password<span>*</span></h4>
<InputText #bind-Value="signInRequest.Password" type="password" class="input-actions" />
</div>
<button class="auth__confirm actions-btn btn" disabled="#sendRequestLoading">
Sign In
</button>
</EditForm>
#code {
// it is code for example
private async void SendRequestSubmit()
{
var auth = accountSerrvice.auth(Email, Password);
if(auth == true && auth.Token != null)
{
// Save auth.Token in the client side
}
else
{
throw new Exception("Test error");
}
}
}

.NET CORE and ADFS no Claims Available

Migrating to .NET Core 3 from a 4.6 project and I'm not 100% sure I am implementing things properly.
I followed the steps in this article, making sure to configure startup.cs following the code sample under the "Use WS-Federation without ASP.NET Core Identity" section.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/ws-federation?view=aspnetcore-3.0
Login seems to be working in that I'm redirected to MS login and sent back to my app with the expected cookies, for example MSISAuthenticated. But, user.identity.isauthenticated is always false and I have no claims available. Is this expected behavior? Perhaps I'm not configuring things properly? Ideally I'd like to be able to check if a user is authenticated and access the claims.
I've come across a number of articles about adding policies based on groups, but how would [Authorize (Policy="SomeGroup")] even work if no claims are available?
ConfigureServices Code:
enter image description here
Configure Code:
enter image description here
Controller Action:
public IActionResult Index()
{
var identity = (ClaimsIdentity)User.Identity;
ViewBag.Claims = identity.Claims;
return View();
}
View Code:
#using System.Security.Claims;
#{
ViewBag.Title = "Home Page";
IEnumerable<Claim> claims = (IEnumerable<Claim>)ViewBag.Claims;
}
#if (User.Identity.IsAuthenticated)
{
<div class="jumbotron">
<h1>Successful Sign On!</h1>
</div>
<div class="row">
<div class="col-md-12">
<h2>WS Federation Services Claims</h2>
#foreach (Claim claim in claims)
{
<p>
<b>#(claim.Type.ToString())</b>
<br />
#(claim.Value.ToString()) (type: #(claim.ValueType.ToString()))
<hr />
</p>
}
</div>
</div>
}
else
{
<div class="jumbotron">
<h1>SSO Test</h1>
<p class="lead">To sign in using Microsoft's single sign-on service, click the button below.</p>
<p>Sign in ยป</p>
</div>
}
perhaps the fact is that you are not send the desired ResourceUrl to ADFS. Then ADFS considers the default resource and issues a token without claims.
See more info on 3 step in "High level AD FS authentication flow"
enter link description here
AD FS identifies the resource which the client wants to access through
the resource parameter passed in the auth request. If using MSAL
client library, then resource parameter is not sent. Instead the
resource url is sent as a part of the scope parameter: scope =
[resource url]//[scope values e.g., openid].

IdentityServer4 Host with SPA front end

I'm trying to use identity server 4 as a SSO site with a front-end written as an SPA (framework not important)
The Example project uses MVC, which when the user logs in the page posts to a controller that redirects the browser to the return URL.
I'm having trouble modifying this flow to work in a more AJAX fashion. Firstly I want to be able to submit the username/password to an API controller so that I can get back validation errors etc without doing a page refresh. Given a successful login I then need to redirect the browser to the returnUrl, but I cannot get this to work and the callback url returns the user back to the login page again rather than redirecting to the client app logged in.
This is what my login endpoint looks like:
[HttpPost]
[Route("api/identity/login")]
public async Task<IActionResult> Login(LoginInputModel model)
{
// check credentials in model etc
await _eventsService.RaiseAsync(new UserLoginSuccessEvent(model.Email, subjectId, model.Email));
await HttpContext.SignInAsync(subjectId, model.Email, new AuthenticationProperties());
return Ok();
}
And simple form as a front-end, this is hosted on a static html page:
<form>
<label for="email">Email</label>
<input id="email" type="email" />
<label for="password">Password</label>
<input id="password" type="password" />
<button onclick="login()" type="submit">Log me in</button>
</form>
<script>
var email = document.querySelector('#email').value;
var password = document.querySelector('#password').value;
var returnUrl = unescape(window.location.search.replace('?returnUrl=', ''));
fetch('/api/identity/login', {
body: JSON.stringify({ email, password }),
headers: new Headers({
'Content-Type': 'application/json'
}),
method: 'POST'
}).then(() => {
var returnUrl = unescape(window.location.search.replace('?returnUrl=', ''));
window.location = window.location.origin + returnUrl;
})
</script>
On a 200 response I use javascript to redirect the browser to the returnUrl.
I'm not sure what I'm missing to get this to work. Do I need to sign the user in and redirect all in one call?
I am modifying an existing example app here which does work with the direct post/redirect method as expected, so both host and client config is unchanged: https://github.com/BenjaminAbt/Samples.AspNetCore-IdentityServer4
After investigating some logs and watching the requests a little more carefully I realised that the login response from the AJAX request was not setting the authentication cookie on the browser.
Setting the credentials option in the fetch request to 'same-origin' fixed the issue
thanks to this stackoverflow answer: https://stackoverflow.com/a/39233628

Primefaces fileupload mode="Simple" with commandbutton ajax="true" throws nullpointer exception

This is in reference to the following thread
[File upload doesn't work with AJAX in PrimeFaces 4.0/JSF 2.2.x - javax.servlet.ServletException: The request content-type is not a multipart/form-data
The problem I experience is Nullpointer on clicking the command button.
Starting from the web.xml
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>commons</param-value>
</context-param>
xhtml
<p:fileUpload id="file" value="#{userBean.uploadedFile}"
mode="simple" required="true" allowTypes="*.xls,*.xlsx"
requiredMessage="#{msg.vrUserUpload}"
invalidFileMessage="#{msg.vrUserUploadInvalidFile}"
multiple="false" fileUploadListener="userBean.fileUploadListener" />
<p:commandButton id="btnUpload" value="#{displayText.btUpload}"
styleClass="button_lite" actionListener="#{userBean.insert}"
ajax="true" update="userMassUploadForm"
process="userMassUploadForm">
</p:commandButton>
UserBean.java
public void fileUploadListener(FileUploadEvent event)
{
uploadedFile = event.getFile();
}
public void insert(){
if(uploadedFile!=null){
System.out.println(uploadedFile.getFileName());
}
else{
System.out.println("The file object is null.");
}
}
Console prints out "The file object is null." whenever ajax="true" and when set to false, works. I could not find a solution for this in the above referred thread.
Please advise.Also please let me know if you want any further information.
From PrimeFaces user guide:
Simple File Upload
Simple file upload mode works in legacy mode with a file input whose value should be an UploadedFile instance. Ajax uploads are not supported in simple upload.

How to validate file size and type in <p:fileUpload mode="simple">?

In PrimeFaces 3.4, the <p:fileUpload> attributes sizeLimit and allowTypes doesn't work in case of mode="simple". How can I validate the file size and allowable types?
The mode="simple" generates a plain HTML5 <input type="file"> instead of using jQuery/Ajax file upload, so the client side facilities are limited.
If the webbrowser supports the new HTML5 File API, then you could just make use of it. It adds support for the new accept attribute on <input type="file"> and enables JavaScript to have access to specific file properties such as File#size.
E.g.
<p:fileUpload mode="simple" styleClass="imagesOnlyMax10MB" />
with this JS (using jQuery from PrimeFaces):
$("input[type=file].imagesOnlyMax10MB").attr("accept", "image/*").on("change", function() {
var max = 10 * 1024 * 1024; // 10MB
if (this.files && this.files[0].size > max) {
alert("File too large."); // Do your thing to handle the error.
this.value = null; // Clears the field.
}
});
Otherwise, your best bet is really validating it in the server side. You could use ExternalContext#getMimeType() to get a mime type based on file extension (you can manage all mime types as <mime-mapping> in web.xml; the container's own one has a bunch of default ones).
if (!externalContext.getMimeType(filename).startsWith("image/")) {
// Not an image.
}