How to use https in c#? - c#

I'm developping a webapplication. For the security of the users information i need a https connection. I'm developping this local at the moment. I have followed the tutorial on: http://weblogs.asp.net/dwahlin/archive/2009/08/25/requiring-ssl-for-asp-net-mvc-controllers.aspx
When I build my project the page loads but the url is: http://...
In my code i have placed:
[RequiresSSL]
public ActionResult Index()
{
//var model = Adapter.EuserRepository.GetAll();
return View(db.Eusers.ToList());
}
code from site:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace extranet.Helpers
{
public class RequiresSSL: ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpRequestBase req = filterContext.HttpContext.Request;
HttpResponseBase res = filterContext.HttpContext.Response;
//Check if we're secure or not and if we're on the local box
if (!req.IsSecureConnection && !req.IsLocal)
{
var builder = new UriBuilder(req.Url)
{
Scheme = Uri.UriSchemeHttps,
Port = 443
};
res.Redirect(builder.Uri.ToString());
}
base.OnActionExecuting(filterContext);
}
}
}
What am i missing that the url isn't https based? Is this because I'm working local?
Thanks in advance

Your filter checks to see if the request is local with this statement: && !req.IsLocal. If it is, then it doesn't redirect. If you remove that statement then you'll be required to access the action via HTTPS regardless if you're local or not.

when i remove that piece of code then i get a 401 - can't make
connection with the server localhost, but the link is https now
Removing that part of the code is only part of the solution to your problem. Going back to your original question of "how you can use https" then you need to enable it using this guide.

Related

Blazor Server: Force file download

In the context of the development of my website MySpector.com developed with Blazor Server,
I want to give the user the possibility to download files which are stored on the disk of the machine.
To do this I want to create a Blazor Component / Page ( I do not know what) which will:
take as input a database ID,
fetch the database to locate the file in disk
dynamically transfer the data to be downloaded to the webbrowser
I am having problem to understand how I can program the http response headers and content with Blazor.
I have seen a potential solution on Blazor download on microsoft but I do not like the idea to create a RAZOR page inside a BLAZOR solution, as this introduce a component organized in a different way than the other ( 2 files: .cshtml + .cshtml.cs, instead of 1 .razor file)
see below Downloader.cshtml in the file hierarchy which looks like different than the other pages.
I am also aware of the 'different layers' of blazor server where a page is only a subpart of a bigger html context so I see the problem, but I woudl like to find a easy way only to override http GET via a .razor single file... if this is possible.
Regards.
You can get control of the http response with headers by using a Asp net core Controller. This is compatible with Blazor server technology.
To do so, you can folow up the 2 links below:
Mvc controller added to blazor server
Return file from Mvc Controller
I added a controller directory with the downloader controller:
I patch the code of startup with this diff:
Then I add the code for the downloader controller:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Net.Mime;
using System.Web;
using NLog;
using MySpector.Core;
using MySpector.Objects;
//https://chanmingman.wordpress.com/2020/07/12/add-web-api-controller-to-blazor-project-asp-net/
//https://stackoverflow.com/questions/5826649/returning-a-file-to-view-download-in-asp-net-mvc
namespace FrontEnd.Pages
{
[Route("api/[controller]")]
[ApiController]
public class DownloadController : Controller
{
private static Logger _log = LogManager.GetCurrentClassLogger();
private ResultStorage _resultStorage;
// GET /api/Download/3
[HttpGet("{resultDbId:int}")]
public ActionResult Get(int resultDbId)
{
bool isConnected = ServiceLocator.Instance.Repo.Connect();
if (!isConnected)
{
_log.Error("Cannot connect");
_log.Error("Returning Http 404");
return NotFound();
}
else
{
_log.Debug("Connected to db");
_log.Debug("Input: ResultDbId=" + resultDbId);
_resultStorage = ServiceLocator.Instance.Repo.GetSingleResult(resultDbId);
}
if(_resultStorage==null)
{
_log.Error("Returning Http 404");
return NotFound();
}
string filename = _resultStorage.File.FilePath;
var cd = new ContentDisposition
{
FileName = filename,
Inline = true,
};
Response.Headers.Add("Content-Disposition", cd.ToString());
byte[] filedata = System.IO.File.ReadAllBytes(filename);
string contentType = "application/octet-stream";
return File(filedata, contentType);
}
}
}
You can then call this module with:
string downloadUri = "api/Download/" + #_report.Result.DbId;
<NavLink href="#downloadUri">Download raw file</NavLink><br />

How to filter UrlReferrer from a whitelist in ASP.NET?

I need to create a single page that is going to be a part of an existing ASP.NET MVC website that is only open or accessible if came from allowed websites (Referrer). Our partners are planning
to load this page using an iFrame. This page allows any user to quickly enter the details and save into
our database.
example: www.mysecuredwebsite.com/publicpage
Since this is going to be public single page only and no logins, the only security is
only allow if the referrer is in the list of allowed sites.
Example:
www.abc.com
www.randomwebsite.com
www.amazingsite.com
Any request from any other sites will be redirected to an error page.
What is the best approach to this problem? I'm thinking of creating a custom attribute that will be used
to decorate the controller which then reads
a list of allowed sites from the app.config orany type of config.
Or maybe from the SQLDB since the site is using SQLDB? The list I think will be frequently change
depending on the growing number of clients. It should be easily configurable and does not require
redeployment.
Any thoughts? Thanks!
You can use two methods
Method 1: Use ActionFilterAttribute.
Method 2: Use the Application_BeginRequest method in the Global.asax file.
Note: It is better to put the allowed urls in the database so that it can be easily changed.
I will explain the first method
The following filter checks whether UrlReferrer is allowed. If it
is not allowed, it will be referred to the error page.
add UrlReferrerFilterAttribute
using System.Web.Mvc;
using System.Web.Routing;
namespace yournamespace
{
public class UrlReferrerFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string urlReferrer = string.Empty;
if (filterContext.HttpContext.Request.UrlReferrer != null)
{
urlReferrer = filterContext.HttpContext.Request.UrlReferrer.AbsoluteUri;
if(!db.UrlReferrerTable.Any(a => a.Url == urlReferrer))
{
var values = new RouteValueDictionary(new
{
action = "ErrorPage",
controller = "Home"
});
filterContext.Result = new RedirectToRouteResult(values);
}
}
base.OnActionExecuting(filterContext);
}
}
}
now use
[UrlReferrerFilter]
public ActionResult YourAction()
{
//..................
//..................
}

Returning an HttpResponseMessage contents from a pass through API in ASP.NET Core [duplicate]

I'm developing an ASP.Net Core web application where I need to create a kind of "authentication proxy" to another (external) web service.
What I mean by authentication proxy is that I will receive requests through a specific path of my web app and will have to check the headers of those requests for an authentication token that I'll have issued earlier, and then redirect all the requests with the same request string / content to an external web API which my app will authenticate with through HTTP Basic auth.
Here's the whole process in pseudo-code
Client requests a token by making a POST to a unique URL that I sent him earlier
My app sends him a unique token in response to this POST
Client makes a GET request to a specific URL of my app, say /extapi and adds the auth-token in the HTTP header
My app gets the request, checks that the auth-token is present and valid
My app does the same request to the external web API and authenticates the request using BASIC authentication
My app receives the result from the request and sends it back to the client
Here's what I have for now. It seems to be working fine, but I'm wondering if it's really the way this should be done or if there isn't a more elegant or better solution to this? Could that solution create issues in the long run for scaling the application?
[HttpGet]
public async Task GetStatement()
{
//TODO check for token presence and reject if issue
var queryString = Request.QueryString;
var response = await _httpClient.GetAsync(queryString.Value);
var content = await response.Content.ReadAsStringAsync();
Response.StatusCode = (int)response.StatusCode;
Response.ContentType = response.Content.Headers.ContentType.ToString();
Response.ContentLength = response.Content.Headers.ContentLength;
await Response.WriteAsync(content);
}
[HttpPost]
public async Task PostStatement()
{
using (var streamContent = new StreamContent(Request.Body))
{
//TODO check for token presence and reject if issue
var response = await _httpClient.PostAsync(string.Empty, streamContent);
var content = await response.Content.ReadAsStringAsync();
Response.StatusCode = (int)response.StatusCode;
Response.ContentType = response.Content.Headers.ContentType?.ToString();
Response.ContentLength = response.Content.Headers.ContentLength;
await Response.WriteAsync(content);
}
}
_httpClient being a HttpClient class instantiated somewhere else and being a singleton and with a BaseAddressof http://someexternalapp.com/api/
Also, is there a simpler approach for the token creation / token check than doing it manually?
If anyone is interested, I took the Microsoft.AspNetCore.Proxy code and made it a little better with middleware.
Check it out here: https://github.com/twitchax/AspNetCore.Proxy. NuGet here: https://www.nuget.org/packages/AspNetCore.Proxy/. Microsoft archived the other one mentioned in this post, and I plan on responding to any issues on this project.
Basically, it makes reverse proxying another web server a lot easier by allowing you to use attributes on methods that take a route with args and compute the proxied address.
[ProxyRoute("api/searchgoogle/{query}")]
public static Task<string> SearchGoogleProxy(string query)
{
// Get the proxied address.
return Task.FromResult($"https://www.google.com/search?q={query}");
}
I ended up implementing a proxy middleware inspired by a project in Asp.Net's GitHub.
It basically implements a middleware that reads the request received, creates a copy from it and sends it back to a configured service, reads the response from the service and sends it back to the caller.
This post talks about writing a simple HTTP proxy logic in C# or ASP.NET Core. And allowing your project to proxy the request to any other URL. It is not about deploying a proxy server for your ASP.NET Core project.
Add the following code anywhere of your project.
public static HttpRequestMessage CreateProxyHttpRequest(this HttpContext context, Uri uri)
{
var request = context.Request;
var requestMessage = new HttpRequestMessage();
var requestMethod = request.Method;
if (!HttpMethods.IsGet(requestMethod) &&
!HttpMethods.IsHead(requestMethod) &&
!HttpMethods.IsDelete(requestMethod) &&
!HttpMethods.IsTrace(requestMethod))
{
var streamContent = new StreamContent(request.Body);
requestMessage.Content = streamContent;
}
// Copy the request headers
foreach (var header in request.Headers)
{
if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
{
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
}
}
requestMessage.Headers.Host = uri.Authority;
requestMessage.RequestUri = uri;
requestMessage.Method = new HttpMethod(request.Method);
return requestMessage;
}
This method covert user sends HttpContext.Request to a reusable HttpRequestMessage. So you can send this message to the target server.
After your target server response, you need to copy the responded HttpResponseMessage to the HttpContext.Response so the user's browser just gets it.
public static async Task CopyProxyHttpResponse(this HttpContext context, HttpResponseMessage responseMessage)
{
if (responseMessage == null)
{
throw new ArgumentNullException(nameof(responseMessage));
}
var response = context.Response;
response.StatusCode = (int)responseMessage.StatusCode;
foreach (var header in responseMessage.Headers)
{
response.Headers[header.Key] = header.Value.ToArray();
}
foreach (var header in responseMessage.Content.Headers)
{
response.Headers[header.Key] = header.Value.ToArray();
}
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
response.Headers.Remove("transfer-encoding");
using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
{
await responseStream.CopyToAsync(response.Body, _streamCopyBufferSize, context.RequestAborted);
}
}
And now the preparation is complete. Back to our controller:
private readonly HttpClient _client;
public YourController()
{
_client = new HttpClient(new HttpClientHandler()
{
AllowAutoRedirect = false
});
}
public async Task<IActionResult> Rewrite()
{
var request = HttpContext.CreateProxyHttpRequest(new Uri("https://www.google.com"));
var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, HttpContext.RequestAborted);
await HttpContext.CopyProxyHttpResponse(response);
return new EmptyResult();
}
And try to access it. It will be proxied to google.com
A nice reverse proxy middleware implementation can also be found here: https://auth0.com/blog/building-a-reverse-proxy-in-dot-net-core/
Note that I replaced this line here
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
with
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToString());
Original headers (e.g. like an authorization header with a bearer token) would not be added without my modification in my case.
I had luck using twitchax's AspNetCore.Proxy NuGet package, but could not get it to work using the ProxyRoute method shown in twitchax's answer. (Could have easily been a mistake on my end.)
Instead I defined the mapping in Statup.cs Configure() method similar to the code below.
app.UseProxy("api/someexternalapp-proxy/{arg1}", async (args) =>
{
string url = "https://someexternalapp.com/" + args["arg1"];
return await Task.FromResult<string>(url);
});
Piggy-backing on James Lawruk's answer https://stackoverflow.com/a/54149906/6596451 to get the twitchax Proxy attribute to work, I was also getting a 404 error until I specified the full route in the ProxyRoute attribute. I had my static route in a separate controller and the relative path from Controller's route was not working.
This worked:
public class ProxyController : Controller
{
[ProxyRoute("api/Proxy/{name}")]
public static Task<string> Get(string name)
{
return Task.FromResult($"http://www.google.com/");
}
}
This does not:
[Route("api/[controller]")]
public class ProxyController : Controller
{
[ProxyRoute("{name}")]
public static Task<string> Get(string name)
{
return Task.FromResult($"http://www.google.com/");
}
}
Hope this helps someone!
Twitchax's answer seems to be the best solution at the moment. In researching this, I found that Microsoft is developing a more robust solution that fits the exact problem the OP was trying to solve.
Repo: https://github.com/microsoft/reverse-proxy
Article for Preview 1 (they actually just released prev 2): https://devblogs.microsoft.com/dotnet/introducing-yarp-preview-1/
From the Article...
YARP is a project to create a reverse proxy server. It started when we noticed a pattern of questions from internal teams at Microsoft who were either building a reverse proxy for their service or had been asking about APIs and technology for building one, so we decided to get them all together to work on a common solution, which has become YARP.
YARP is a reverse proxy toolkit for building fast proxy servers in .NET using the infrastructure from ASP.NET and .NET. The key differentiator for YARP is that it is being designed to be easily customized and tweaked to match the specific needs of each deployment scenario. YARP plugs into the ASP.NET pipeline for handling incoming requests, and then has its own sub-pipeline for performing the steps to proxy the requests to backend servers. Customers can add additional modules, or replace stock modules as needed.
...
YARP works with either .NET Core 3.1 or .NET 5 preview 4 (or later). Download the preview 4 (or greater) of .NET 5 SDK from https://dotnet.microsoft.com/download/dotnet/5.0
More specifically, one of their sample apps implements authentication (as for the OP's original intent)
https://github.com/microsoft/reverse-proxy/blob/master/samples/ReverseProxy.Auth.Sample/Startup.cs
Here is a basic implementation of Proxy library for ASP.NET Core:
This does not implement the authorization but could be useful to someone looking for a simple reverse proxy with ASP.NET Core. We only use this for development stages.
using System;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
namespace Sample.Proxy
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(options =>
{
options.AddDebug();
options.AddConsole(console =>
{
console.IncludeScopes = true;
});
});
services.AddProxy(options =>
{
options.MessageHandler = new HttpClientHandler
{
AllowAutoRedirect = false,
UseCookies = true
};
options.PrepareRequest = (originalRequest, message) =>
{
var host = GetHeaderValue(originalRequest, "X-Forwarded-Host") ?? originalRequest.Host.Host;
var port = GetHeaderValue(originalRequest, "X-Forwarded-Port") ?? originalRequest.Host.Port.Value.ToString(CultureInfo.InvariantCulture);
var prefix = GetHeaderValue(originalRequest, "X-Forwarded-Prefix") ?? originalRequest.PathBase;
message.Headers.Add("X-Forwarded-Host", host);
if (!string.IsNullOrWhiteSpace(port)) message.Headers.Add("X-Forwarded-Port", port);
if (!string.IsNullOrWhiteSpace(prefix)) message.Headers.Add("X-Forwarded-Prefix", prefix);
return Task.FromResult(0);
};
});
}
private static string GetHeaderValue(HttpRequest request, string headerName)
{
return request.Headers.TryGetValue(headerName, out StringValues list) ? list.FirstOrDefault() : null;
}
public void Configure(IApplicationBuilder app)
{
app.UseWebSockets()
.Map("/api", api => api.RunProxy(new Uri("http://localhost:8833")))
.Map("/image", api => api.RunProxy(new Uri("http://localhost:8844")))
.Map("/admin", api => api.RunProxy(new Uri("http://localhost:8822")))
.RunProxy(new Uri("http://localhost:8811"));
}
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}

adding Response to user in mcv4 web-api

I need in MCV4 web-api to return a http status to user (after calling POST/GET methods).
(New project of MCV4, and choose: WEB-API).
I have VS 2010, and I looked at the sample on Returning http status code from Web Api controller, but it didn't work for me.
I am using ApiController to handle GET/POST methods.
For following code:
[ResponseType(typeof(User))]
public HttpResponseMessage GetUser(HttpRequestMessage request, int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
return new HttpResponseMessage(HttpStatusCode.NotModified);
}
return request.CreateResponse(HttpStatusCode.OK, user);
}
I put the above in class of type: apicontroller - ResponseType is unknown, and indeed, in code, I added:
using System.Web.Http;
But, still ResponseType is unknown.
I am using 32bit for my win-api.
How can I return status to user (whether it is error, or OK).
Thanks :)
As per MSDN document, the ResponseTypeAttribute is in the namespace "System.Web.Http.Description"
Refer: ResponseTypeAttribute

No OpenID endpoint found

I am trying to use the DotNetOpenId library to add OpenID support on a test website. For some reason it keeps giving me the following error when running on Firefox. Keep in mind that I am using localhost as I am testing it on my local machine.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
using DotNetOpenAuth.OpenId.RelyingParty;
namespace TableSorterDemo
{
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var openid = new OpenIdRelyingParty();
if (openid.GetResponse() != null)
{
switch (openid.GetResponse().Status)
{
case AuthenticationStatus.Authenticated:
var fetch = openid.GetResponse().GetExtension(typeof(ClaimsResponse)) as ClaimsResponse;
var nick = fetch.Nickname;
var email = fetch.Email;
break;
}
}
}
protected void OpenIdLogin1_LoggedIn(object sender, OpenIdEventArgs e)
{
var openid = new OpenIdRelyingParty();
if(openid.GetResponse() != null)
{
switch(openid.GetResponse().Status)
{
case AuthenticationStatus.Authenticated:
var fetch = openid.GetResponse().GetExtension(typeof (ClaimsResponse)) as ClaimsResponse;
var nick = fetch.Nickname;
var email = fetch.Email;
break;
}
}
}
protected void OpenIdLogin1_LoggingIn(object sender, OpenIdEventArgs e)
{
var openid = new OpenIdRelyingParty();
var req = openid.CreateRequest(OpenIdLogin1.Text);
var fetch = new ClaimsRequest();
fetch.Email = DemandLevel.Require;
fetch.Nickname = DemandLevel.Require;
req.AddExtension(fetch);
req.RedirectToProvider();
return;
}
}
}
Also, if I run the same page in Chrome then I get the following:
Login failed: This message has already been processed. This could indicate a replay attack in progress.
The replay attack detection results from you calling GetResponse() twice. You must not do that. Instead, assign the result of just one call to GetResponse() to a local variable, and then check it against null and use it otherwise.
Regarding you "No OpenID endpoint found" error, are you testing against a localhost OpenID as well or an OpenID hosted by an external party like Yahoo?
In my case as I was using a proxy to connect to the internet, I resolved by adding the following configuration to the web.config.
<system.net>
<defaultProxy useDefaultCredentials="true">
<proxy autoDetect="True" usesystemdefault="True" />
</defaultProxy>
</system.net>
Its worth noting that the 'No OpenID endpoint found' error message may not be a true description of what the issue is.
For myself it was because I was using my gmail email address but actually you need to create an OpenId account you will then get an id in the format .myopenid.com/
Enter that Id into the form and it should work correctly.
Check the web.config in your client app.
There is a section
<!-- Uncomment to enable communication with localhost (should generally not activate in production!) -->
<!--<add name="localhost" />-->
So as it says - uncomment to
<add name="localhost" />

Categories