Images from http site on https site: mixed mode - c#

My https-based site (site A) uses images from http-based site B. I causes mixed-content error. To fix this, I found solution to swap each external link like http://www.siteB.com/imageX.png with my controller method which do forward to external image. The new link format is:
The code of method /api/misc/forward is following:
[HttpGet]
public async Task<HttpResponseMessage> Forward(string url)
{
HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
try
{
var response = Request.CreateResponse(HttpStatusCode.Found);
response.Headers.Location = new Uri(HttpUtility.UrlDecode(url));
return response;
}
catch (Exception ex)
{
httpResponseMessage.StatusCode = HttpStatusCode.NotFound;
_loggerService.LogException(ex, url);
}
return httpResponseMessage;
}
but the browser still is able to recognize it as mixed mode.... Why?
The original image links sent to browser origins from https-based site.
Any quick tip for it? I dont want to cache all images from site B:).

Because your code sends back a redirect to another location, so, eventually, the browser still go to the HTTP image.
What happens is that your browser calls the controller in HTTPS, then controller action sends back a redirect command to the browser, the browser retrieves the image from the new location that you set in the response.Headers.Location.
If you want to avoid the mixed mode, then you need to retrieve the image from the controller and return a FileResult from the action, this way, the browser will not have to access the HTTP site.
Another approach, would be to just copy the images to you site.

Related

Web API redirect to web page

I have a Web API that I need to convert to API Core 2. I have one issue I cannot seem to resolve. There is a redirect in the controller that uses Request.CreateResponse which does not appear to be available in .Net Core?
public HttpResponseMessage Get() {
var response = Request.CreateResponse(HttpStatusCode.Redirect);
response.Headers.Location = new Uri("https://xxx.xxxx.com");
return response;
}
Any idea how I can modify this to work? Basically if a user does not pass any parameters, we just send them to a web page.
The syntax has changed in ASP.Net-Core. HttpResponseMessage is no longer used in action results. They will serialized like any other model returned object.
Use instead, the Controller.Redirect method which returns a RedirectResult
public IActionResult Get() {
return Redirect("https://xxx.xxxx.com");
}
RedirectResult
RedirectResult will redirect us to the provided URL, it doesn’t matter if the URL is relative or absolute, it just redirect, very simple. Other thing to note is that it can redirect us temporarily which we’ll get 302 status code or redirect us permanently which we’ll get 301 status code. If we call the Redirect method, it redirect us temporarily...
Reference Asp.Net Core Action Results Explained
That's what the Redirect() method exactly does:
return Redirect("https://xxx.xxx.com");
But if you want more control, you can return a ContentResult:
response.Headers.Location = new Uri("https://xxx.xxx.com");
return new ContentResult {
StatusCode = (int)HttpStatusCode.Redirect,
Content = "Check this URL"
};
I don't see any benefit for doing this, though. Well, unless if you use some client that will not follow the redirect and you want to provide some instructions or content in the Content property, which the client will see as the body of the returned page.
You can use HttpResponseMessage instead, something like:
var response = new HttpResponseMessage(HttpStatusCode.Redirect);
response.Headers.Location = new Uri("https://insight.xxx.com");

RedirectToAction is changing the URL

My call to RedirectToAction is acting like RedirectToActionPermanent. That is, the URL is being changed, rather than simply displaying a different view.
Edit: Now that I think about it, RedirectToAction typically acts as a permanent redirect. As in, this is probably the correct behavior. In the below code, if the ModelState is valid, the user is given a 302 redirect back to the index. But then, what's the point of RedirectToActionPermanent?
The redirects are for HTTP errors. I have my Web.config set to point errors to certain action methods in HttpErrorsController. This works perfectly, including showing a temporary redirect, as expected. (https://localhost/ThisPageDoesntExist shows error page but the URL remains the same)
Returning an HttpStatusCodeResult or throwing an HttpException both work as expected.
However, if I try to do a temporary redirect to an error action method by using RedirectToAction, the view is still displayed properly, but the URL changes, e.g. https://localhost/HttpErrors/404.
HttpErrorsController.cs
private ViewResult ErrorView(HttpStatusCode httpStatusCode, string shortDesc, string longDesc)
{
Response.StatusCode = (int)httpStatusCode;
return View("HttpError", new HttpErrorViewModel(httpStatusCode, shortDesc, longDesc));
}
[ActionName("404")]
public ActionResult Error404()
{
return ErrorView(HttpStatusCode.NotFound, "Not Found",
"The requested resource could not be found.");
}
// Other identical methods for each error
ItemController.cs
public ActionResult HttpError(HttpStatusCode status)
{
return RedirectToAction(((int)status).ToString(), "HttpErrors");
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ItemViewModel viewModel)
{
if (!Request.IsAjaxRequest())
{
return HttpError(HttpStatusCode.NotAcceptable);
}
if (ModelState.IsValid)
{
db.Items.Add(pm);
db.SaveChanges();
return RedirectToAction("Index");
}
return PartialView("_Create", viewModel);
}
Since writing the above, I've realized I'm probably better off just throwing an HttpException, so that it also gets caught by ELMAH, but I'm still quite confused by the behavior described above.
RedirectToAction method sends a 302 response back to the browser with the location header value which the new url and the browser will make a totally new http GET request to this new url. So what you see is the expected behavior.
If you want not do the redirect, but want to keep the url as it is, do not do return a RedirectResult, return a view result as needed.
RedirectToActionPermanent method sends a 301 Moved Permanently response back to the client. This is usually useful when you are moving one page to another (killing an old page and creating a new one with different url) of your site and wants the client to know it so that they can the calling code to use the new url in future. Think about google search engine changing the links to your new page and showing that in the search result.

Web Security in IE VS Chrome & Firefox (bug)

Why is the Web Security is working differently on different browser:
Details:
I have two applications
One is a simple HTML application and another one is an ASP.NET MVC4 WebApi application and the projects are inside of same solution and i have set multiple start-up project for run the application for same time .
Working version:
I have Used Web Security in the Web API project. I did full implementation of web security...
Login Action Code
// GET api/company
[System.Web.Http.AcceptVerbs("Post")]
[System.Web.Http.HttpPost]
public HttpResponseMessage Login(LoginRequest loginRequest)
{
try
{
if (WebSecurity.Login(loginRequest.EmailAddress, loginRequest.Password, true))
{
var userDetails = new string[2];
userDetails[0] = loginRequest.EmailAddress;
var currentUSerRole = Roles.GetRolesForUser(loginRequest.EmailAddress);
userDetails[1] = currentUSerRole[0].ToString();
HttpResponseMessage response =
Request.CreateResponse(HttpStatusCode.Accepted, userDetails);
return response;
}
else
{
HttpResponseMessage response
= Request.CreateResponse(HttpStatusCode.Unauthorized);
return response;
}
}
catch (Exception e)
{
HttpResponseMessage response
= Request.CreateResponse(HttpStatusCode.Unauthorized);
return response;
}
}
*WebSecurity.Login* is working on all browsers when i call the login method using Ajax.
But I have another method in another controller, That named as CurrentDateAndUser
Code:
[AllowAnonymous]
[System.Web.Http.AcceptVerbs("Get")]
[System.Web.Http.HttpGet]
public HttpResponseMessage CurrentDateAndUser()
{
if (WebSecurity.IsAuthenticated)
{
int userId = WebSecurity.CurrentUserId;
string[] currentDateAndUSerId = new string[2];
currentDateAndUSerId[0] = userId.ToString();
currentDateAndUSerId[1] = DateTime.UtcNow.ToString();
HttpResponseMessage response =
Request.CreateResponse(HttpStatusCode.Accepted, currentDateAndUSerId);
return response;
}
HttpResponseMessage responseNew =
Request.CreateResponse(HttpStatusCode.NotAcceptable);
return responseNew;
}
Issue:
If I call the CurrentDateAndUser method from Microsoft Internet Explorer Using an Ajax call, then everything works. The WebSecurity.IsAuthenticated returns true and is working well.
However,
If I call the CurrentDateAndUser method from Google Chrome Or Mozilla Firefox using an Ajax call, then nothing works. The WebSecurity.IsAuthenticated always returns false.
I don't know why. If you have any idea, then please let me know.
I also found a similar problem (not sure if it is a real issue):
When I run my application with Fiddler, I see a different result:
When i call the CurrentDateAndUser method from IE, the request is:
I can see the Cooke/Login values in above image
But When i call the CurrentDateAndUser method from Chrome And Firefox , the request is:
I can't see the cookie values, meaning that the Web Security.IsAuthenticated property is returning false.
Is it Bug in WebSecurity?????
Edit
My Ajax request code is
function GetCurrentUserId() {
return $.ajax({
method: 'GET',
url: rootUrl + '/api/Common/CurrentDateAndUser',
async: false
}).success(function (response) {
return response[0];
}).error(function () {
toastr.error('Somthing is wrong', 'Error');
})
}
This request does not send the Auth Cookie values to Web API method when I run the application in Chrome and Firefox, however, this request sends the cookie values to the API method, if it is run in IE
i have posted the Image , Please take a look at the above image
The issue is not with web security at all, it's with the way you implement your security. You should never be using a userid, email, or anything important in the cookies.
I would suggest you use the FormsAuthentication class to encrypt and decrypt your cookies, and even so, only store something such as the SessionID plus a custom hash of that session ID to verify your self when you decrypt the cookie
Here is a site that gives a pretty good example: http://www.c-sharpcorner.com/uploadfile/nipuntomar/update-formsauthenticationticket/
There are 3 things around it:
WebSecurity.IsAuthenticated actually returns the value of HttpRequest.IsAuthenticated, which is true if the Forms Authentication cookie has been set and is current. It's not available until the user makes the next request after successfully logging in, which is why you are seeing the behaviour that you describe.
I remember reading on MSDN or someplace, the WebSecurity.IsAuthenticated does not work until the page is fully loaded. Meaning if you login a user in a page and in the same flow of code you check IsAuthenticated, it will NOT return True. For IsAuthenticated to be True the page has to be reloaded or use the better practice; which is to redirect the user to another secured page as soon as the login is successful and in that page check IsAuthenticated.
We had the same issue with Chrome (version 21.0.1180). Despite that we see expiration date on Header, some Chrome in Windows XP ignored it. Then we removed the Expiration Date and Chrome accepted keep the session cookie without problems.
So what to do is:
After login try to check this on new page not on same page.
Also try to set cookie explicitly
System.Web.Security.FormsAuthentication.SetAuthCookie(user.Username, false);
I don't know if this will help or not.
But I remember I was learning jQuery ajax
So I setup a simple project on my laptop. When I tested it, it worked fine on IE, but failed in Chrome. After searching for hours, I found that Chrome will not allow AJAX requests from the local machine. When I tested it using an actual web server it worked fine for IE and Chrome.
So my question and advice is: are you testing on the same machine?
Try to deploy it to a machine running a web server with a unique domain name and test your application!

File download via Webapi controller - handling errors

I am working on an application that provides some links for users to download files.
The page itself is served up by an MVC controller but the links are pointing to a WebAPI controller running on a separate domain.
(I would have preferred same domain but for various reasons it has to be a separate project and it will run on a separate domain. I don't think CORS is part of the issue anyway as this is not using XHR, but I mention it just in case).
So in development, the main MVC project is http://localhost:56626/Reports/
And the links on the page might look like this:
Report 12345
where port 51288 is hosting the Web API.
The WebAPI controller uses ReportID to locate a file, and write its contents into the response stream, setting the disposition as an attachment:
//security.permission checks and scaffolding/database interaction
//left out for clarity
try
{
string filename = #"C:\ReportFiles\TestReport.csv";
var stream = new FileStream(path, FileMode.Open);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/csv");
var disp = new ContentDispositionHeaderValue("attachment");
disp.FileName = "TestReport.csv";
result.Content.Headers.ContentDisposition = disp;
return result;
}
catch(Exception ex)
{
//how to return a response that won't redirect on error?
}
By doing this the user can then click on the link and without any redirection, the user gets prompted to save or open the file, which is what I want; they stay on the original page with the links and just get an Open/Save dialog from the browser.
The problem arises when something goes wrong in the Web API controller - either an exception or some internal logic condition that means the file cannot be downloaded.
In this case when clicking the link, the download doesn't happen (obviously) and they get taken to the target URL instead i.e http://localhost:51288/api/ReportDownload?ReportID=12345 which is not desirable for my requirements.
I would much rather be able to catch the error somehow on the client-side by returning for e.g. HTTP 500 in the response, and just display a message to the user that the download failed.
Now to be honest, I don't even understand how the browser can do the "in place" File/Save dialog in the first place:
I always thought if you click a link that has no explicit target attribute,the browser would just open the new request in your current tab i.e it's just another GET request to the target URL, but it seems this is not the case
The browser seems to be doing a hidden background fetch of the target URL in this case (same behaviour in FF,Chrome and IE) which I cannot even see in the F12 tools.
The F12 Network log shows no activity at all except in the specific case where the response has NOT been setup as Content-Disposition: attachment i.e an error -only in this case do I see the (failed) HTTP GET being logged in the Network request list.
I suppose I could just catch any exception in the controller and send back a dummy file called "Error.csv" with contents "Ha Ha Nope!" or something similar, but that would be a last resort...any ideas welcome!
If the user clicks on the link, the browser will follow it - then depending on the response headers and browser configuration, it'll either show the file dialog or render directly - you can't really change that behavior (apart from using preventDefault when the link is clicked, which kind of defeats the purpose).
I'd suggest taking a closer look at http://jqueryfiledownload.apphb.com/ which lets you do something like this:
$.fileDownload('some/file/url')
.done(function () { alert('File download a success!'); })
.fail(function () { alert('File download failed!'); });
Then you could bind the download action using jQuery.

I can't get redirecttoaction to work in asp.net mvc after receiving data from flash

I'm building an action that basically handles receiving post data from a flash app,
I have no problem receiving the data.
after that, it should redirect to another controller/action
I tried Redirect, RedirectToRoute, none of them worked.
here is my code
[AcceptVerbs(HttpVerbs.Post)]
public RedirectToRouteResult Draw(FormCollection form)
{
string bitmapDataString = Request.Params["someimagedata"];
byte[] bitmapData = Convert.FromBase64String(bitmapDataString);
File.WriteAllBytes(Server.MapPath("~/Images/abc.jpg"),
return RedirectToAction("Register", "Participant");
}
Redirects are the job of the client (browser). You're simply telling the browser that you would like it to redirect. I don't know anything about flash but note that these redirects don't work with Ajax requests either. I know that's not a full answer but may send you in the right direction while you're waiting on someone with some flash experience.

Categories