var displayUrl = UriHelper.GetDisplayUrl(Request);
var urlBuilder = new UriBuilder(displayUrl) { Query = null, Fragment = null };
string _activation_url = urlBuilder.ToString().Substring(0, urlBuilder.ToString().LastIndexOf("/")) +"/this_is_my_link.html";
I expect to get correct uri production path, but I still get
http://localhost:5000/api/mdc/this_is_my_link.html
I deployed this on centos 7
please help me..
Thanks
Don
If you are using a reverse proxy, you should read this guide from Microsoft.
Essentially, your reverse proxy should provide these headers to your ASP.NET Core Application:
X-Forwarded-For - The client IP
X-Forwarded-Host - The Host header from the client (e.g. www.example.com:80)
X-Forwarded-Proto - The protocl (e.g. HTTPS)
Then you need to configure your ASP.NET Core application to accept them. You can do so by calling the app.UseForwardedHeaders() method in your Startup's Configure method.
By default (if I'm reading the docs correctly) UseForwardedHeaders (called as above) will accept X-Forwarded-For and X-Forwarded-Proto from a localhost reverse proxy.
If your situation is more complicated than that, you must configure the headers you want/the trusted reverse proxies:
var forwardedOptions = new ForwardedHeadersOptions()
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedProto // allow for, host, and proto (ForwardedHeaders.All also works here)
};
// if it's a single IP or a set of IPs but not a whole subnet
forwardedOptions.KnownProxies.Add(IPAddress.Parse("192.168.0.5"));
// if it's a whole subnet
forwardedOptions.KnownNetworks.Add(new IPNetwork("192.168.0.1", 24)); // 192.168.0.1 - 192.168.0.254
app.UseForwardedHeaders(forwardedOptions);
Also note that, depending on the reverse proxy you use, you might need to configure this on the reverse proxy
on asp core use
absoluteUri = string.Concat(
request.Scheme,
"://",
request.Host.ToUriComponent(),
request.PathBase.ToUriComponent(),
request.Path.ToUriComponent(),
request.QueryString.ToUriComponent());
or you may choose either
Getting absolute URLs using ASP.NET Core
Related
I'm trying to establish a setup which uses Asp.Net Identity together with a Google Login.
My Asp.Net Core endpoint is behind an Nginx Proxy which forwards the proper host to my server. This is required for local debugging, as I'm running in a docker-compose environment, with my server behind the Nginx proxy.
Nginx config:
location / {
proxy_buffers 8 16k;
proxy_buffer_size 16k;
proxy_pass https://dockerweb;
proxy_redirect dockerweb localhost:1253;
proxy_set_header X-Forwarded-For localhost:1253;
}
Login code:
[HttpGet]
[Route("ExternalLogin")]
public IActionResult ExternalLogin([FromQuery] string provider, [FromQuery] bool rememberMe)
{
var forwardedHeader = Request.Headers["X-Forwarded-For"].FirstOrDefault();
var redirectUrl = Url.Action("SocialLoginCallback", "SocialLogin", new
{
rememberMe
}, HttpContext.Request.Scheme, host: forwardedHeader ?? Request.Host.Value);
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
However, when calling my login and doing the redirect, the internal code redirecting to the signin-google does not refer to the correct host (Note that this is different to the redirecturi in the above code)
I'm getting a 302 with the following header:
Location: https://accounts.google.com/o/oauth2/v2/auth?response_type=code...&redirect_uri=https%3A%2F%2Fdockerweb%2Fsignin-google&scope=openid...
As you can see, my forwarded header is effectively ignored, and replaced by the internal Request.Host once more, to which the client can't redirect since that domain name is unknown outside of my docker network.
There is even a bit of help here. I already implemented this: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-6.0#forward-request-information-with-a-proxy-or-load-balancer
I also found Asp.Net Core Google authentication - and implemented it in my Startup as well.
However, things still do not work as expected.
Where did I miss something to properly overwrite the redirect?
We have a simple api that is hosted in azure vm, we have included an application gateway. And the application works fine, until we require to log the clients ip because we have to determine the location of our clients via ipstack.
I have added this code in our HomeController
var ip = string.Empty;
if (HttpContext.Request.Headers.ContainsKey("X-Forwarded-For"))
{
ip = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
}
This works fine, until I decided to use Postman to call the api and added the X-Forwarded-For in the request.
I have included the header as a result in our api just to check and...
"X-Forwarded-For": "<script>alert('test');</script>,192.168.0.1", //masked my real Ip
"X-Forwarded-For": "0.0.0.0,192.168.0.1" //fake ip (0.0.0.0)
Is there anyway to prevent this?
I have included the below code in startup.cs but still no luck.
services.Configure<ForwardedHeadersOptions>(c =>
{
//c.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
//c.ForwardLimit = 1;
//c.KnownProxies.Add(IPAddress.Parse("127.0.0.0"));
c.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});
I'm working on ASP.Net Core 2.1 with Angular Template provided by Microsoft Visual Studio 2017. My Client App is working fine. After competition of User Authentication, I want to start User Session Management in which I store client user IP Address. I've already searched for this on the internet but so far not found any solution.
Below are some ref links which I already visited:
How do I get client IP address in ASP.NET CORE?
Get Client IP Address in ASP.NET Core 2.0
Get a user remote IP Address in ASP.Net Core
In my ValuesController.cs I also tried below code:
private IHttpContextAccessor _accessor;
public ValuesController(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public IEnumerable<string> Get()
{
var ip = Request.HttpContext.Connection.RemoteIpAddress.ToString();
return new string[] { ip, "value2" };
}
wherein ip variable I get null value and getting this error
Request.HttpContext.Connection.RemoteIpAddress.Address threw an exception of Type 'System.Net.Sockets.SocketException'
Can you please let me know how to get client IP address in ASP.NET Core 2.1.
In your Startup.cs, make sure you have a method to ConfigureServices, passing in the IServiceCollection, then register IHttpContextAccessor as a singleton as follows:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
After registering the IHttpContextAccessor in your Startup.cs file, you can inject the IHttpContextAccessor in your controller class and use it like so:
private IHttpContextAccessor _accessor;
public ValuesController(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public IEnumerable<string> Get()
{
var ip = _accessor.HttpContext?.Connection?.RemoteIpAddress?.ToString();
return new string[] { ip, "value2" };
}
It's possible to use the following code:
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
string remoteIpAddress = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
if (Request.Headers.ContainsKey("X-Forwarded-For"))
remoteIpAddress = Request.Headers["X-Forwarded-For"];
If your Kestrel sits behind a reverse proxy like IIS make sure to forward the headers containing the client IP.
This goes into startup:
app.UseForwardedHeaders(new ForwardedHeadersOptions{ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto});
If I use the Binding Address Localhost:5000 then the IP is returned as "::1" (Localhost IPv6 address).
If I bind my Webapi on the IP Address and try to reach it from another client computer, I get Client's IP Address in API Response.
There is no need for HTTPAccessor i believe. As per the documentation https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1, the HttpContext.Connection.RemoteIpAddress is set by XForwardedFor header.
If your application (WEBAPI) is behind a NGINX/Apache Reverse Proxy, you should enable those REV Proxies to send X-Forwarded-For Header address which contains the real IP address of the Client, if you don't setup or process X-Forwarded-For Header, then you would always get either Nulls or Reverse-Proxy Server's IP Address.
The GetHostEntry above has no relation to the HTTP Request directly. GetHostEntry is just a NSLookup tool for API programming and it just tells you the IP Addresses reachable for a particular name, but doesn't tell you from which IP address the Request came to WebApi.
Hope that helps
Try this code,
var ipAddress = HttpContext.Connection.RemoteIpAddress;
And if you have another computer in same LAN, try to connect with this pc but use user ip instead of localhost. Otherwise you will get always ::1 result.
After spending some time on searching I found my own question answer. Here I'm also sharing the source link from where I can get my answer and detail explanation for how to query a server to obtain the family addresses and the IP addresses it supports.
Code:
IPHostEntry heserver = Dns.GetHostEntry(Dns.GetHostName());
var ip = heserver.AddressList[2].ToString();
Source
Here is my another Question: How to access server variables in ASP.Net Core 2.x Hope this helps for you all.
This works for me on .Net Core 2.2:
IPHostEntry heserver = Dns.GetHostEntry(Dns.GetHostName());
var ipAddress = heserver.AddressList.ToList().Where(p => p.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).FirstOrDefault().ToString();
I'm trying to configure IdentityServer4 with docker but I cannot make it work. To get started, I took the Client Credential example of the identity server documentation: Protecting an API using Client Credentials
IdentityServer
Hosted on port 5000
WebApi
Hosted on port 5001
In the Configure method of the Startup.cs file of my WebApi I did the following (the problem is probably here):
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "http://web:5000",
RequireHttpsMetadata = false,
ApiName = "api1"
});
Client
And the client
// Everything is fine here...
var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret");
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api");
// This does not work
var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);
var response = await client.GetAsync("http://localhost:5001/identity");
The problem is probably in my WebApi:
1) If I set the authority to localhost:5000, I get an internal server error: "Unable to obtain configuration from: 'http://localhost:5000/.well-known/openid-configuration'" which makes sense since localhost:5000 is unknown in this container
2) If I set the authority to http://web:5000 I get an authorization error: "Issuer validation failed. Issuer: 'http://localhost:5000'. Did not match: validationParameters.ValidIssuer: 'http://web:5000' or validationParameters.ValidIssuers" which also makes sense but I don't know if it's possible to change the authority name? I also tried to set the IssuerUri in the IdentityServer project but it didn't help
Network
Let's suppose you have two physical machines: C1 and C2. Each machine is a docker host.
C1 runs Auth container.
C2 runs WebApi container.
As you expose port 5000 in Auth dockerfile, the address C1:5000 should be accessible from C2 and from WebApi container itself. You could prefer IPs to DNS, it doesn't matter. Moreover you should be able to make a successfull GET request to http://C1:5000/.well-known/openid-configuration to be sure.
There are a lot of network issues you could face to achieve that. For example:
What would prevent code running in a Docker container from connecting to a database on a separate server?
Issuer validation
Issuer validation failed
Your client's authority URL differs from Auth hostname. By default, authority URL should be equal to issuer property value (this property is in Identity Server autodiscovery document response).
issuer property value depends on your client's web request:
GET http://127.0.0.1:6000/.well-known/openid-configuration -> "issuer": "http://127.0.0.1:6000"
GET http://localhost:6000/.well-known/openid-configuration -> "issuer": "localhost:6000"
Try to set IssuerUri to a constant for a dev environment:
services.AddIdentityServer(x =>
{
x.IssuerUri = "foo";
})
to achieve a constant issuer value. This allowes to call Identity Server by any valid URL (using IP, machine name or DNS):
GET http://anything/.well-known/openid-configuration -> "issuer": "foo"
DiscoveryClient also validates issuer value. It's a simple equality comparison:
public bool ValidateIssuerName(string issuer, string authority)
{
return string.Equals(issuer, authority, StringComparison.Ordinal);
}
You could disable it by:
DiscoveryClient.Policy.ValidateIssuerName = false;
FYI, IssuerUri setting is not recommended for a production environment:
IssuerUri Set the issuer name that will appear in the discovery
document and the issued JWT tokens. It is recommended to not set this
property, which infers the issuer name from the host name that is used
by the clients.
I am writing a test web service, and noticed a strange corner case. If you include two slashes after the port, the method will be called anyway for localhost, localhost:80, 127.0.0.1, and 127.0.0.1:80. But if I try it on the web server I'm developing on (port 55731), it fails.
localhost.Service1 s = new localhost.Service1();
string uri = "http://localhost//testService.asmx";
s.Url = uri;
double result = s.multiply(5,5);
Here's the specific cases:
uri = "http://localhost//testService.asmx"; // works
uri = "http://localhost:80//testService.asmx"; // works
uri = "http://127.0.0.1//testService.asmx"; // works
uri = "http://127.0.0.1:80//testService.asmx"; // works
uri = "http://localhost:55731//testService.asmx"; // fails - HTTP status 400 - bad request
Any idea why this is the case? I know I should have just one slash after the port, just curious.
It's an implementation detail specific to a web server. One server may consolidate the slashes into a single slash, another may look for a directory with an empty string as the name, or does a pattern check on it.
I'm assuming your webserver on port 80 is differnt from the one on 55731, IIS has many differences from the devserver.