Get requested URL in Startup.cs - asp.net-mvc

I have multiple hostname binding on my IIS web site.
And I want to do some base setup during running Startup.cs, that should be dependent on what url has been called.
Lets say there is http://red.webapp.com and http://blue.webapp.com bindings to the same web site.
I tried to get url :
var request = HttpContext.Current.Request;
var url = request.Url.Scheme;
var auth = request.Url.Authority;
However as auth I have 127.0.0.1.
Is it possible to somehow get url that user tried to access?
Thank you.

Related

Get Customer Resource Id with Multi Tenant OAuth on Microsoft Dynamics

I want our my users who are using online Microsoft dynamics to give us access to their account through OAuth2. To be clear, my users live in their own tenants and NOT part of my tenant.
So I registered an Azure AD application and made it multi-tenant but the authorize URL required the resource id which is the exact customer URL on MS Dynamics. like
https://{orgid}.crm.dynamics.com
but I do not want the user to enter their URL manually. I want to automatically figure out their resource id during the OAuth process and complete the process.
how can I do so?
Btw, I am not using C# and I would appreciate it if the HTTP calls could be provided.
Recently I have been working/wrestling with some multi-tenant web apps that need to access D365 via OAuth2. While I do not claim to have mastered it, I have gotten a few such apps working.
Here are some thoughts for you:
I have not attempted to put the tenantId into the CRM url. To construct the CRM url I use the org "url name", which you can get using the below code.
This code assumes that you've put the base URL into the appSettings node of the web.config:
<add key="ida:OrganizationHostName" value="https://{0}.crm.dynamics.com" />
Then this code might should help you along:
private string getOrgName(string user)
{
var a = user.IndexOf('#');
var b = user.IndexOf('.');
return user.Substring(a + 1, b - (a + 1));
}
var signedInUserID = ClaimsPrincipal.Current.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier).Value;
var tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
var userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
var OrganizationHostName = ConfigurationManager.AppSettings["ida:OrganizationHostName"];
var organizationName = getOrgName(User.Identity.Name);
var resource = string.Format(OrganizationHostName, organizationName);
Where I have seen the tenant Id used is when establishing the auth context
var authContext = new AuthenticationContext($"https://login.windows.net/{tenantID}");
As shown above you can get it from the ClaimsPrincipal, but I think my apps are all now using https://login.windows.net/common rather than appending the tenantId.
If you want to get fancy you can query the Discovery service to see what orgs a user has access to. For me, Colin Vermander's article was the key to getting that working.

ASP.Net MVC application access to other servers

We have an ASP.Net MVC application (website), just a straight web app. The URL it needs to connect to is an ASP.Net WebAPI2 web service on port 14015. The MVC application is calling the Web service anonymously using a WebClient class; the web service is secured by limiting which IPs can connect to it. There is no authorization mode to access except by IP.
using (WebClient client = new WebClient())
{
//****************************
// We make the web service call like this:
//****************************
string url = #"http://secure.example.com:14015/lms/SSOKey/1158341";
string key = client.DownloadString(url);
//****************************
// Then we append the returned key to build the full URL. This URL is used
// in the View to build a link button.
//****************************
string login_url = #"http://192.168.1.1/tc/login.do?uid=" + key;
login_url = login_url.Replace("\"", string.Empty);
//****************************
// Pass the URL to the view to build the link button
//****************************
ViewBag.LoginURL = login_url;
}
I can access the URL from a browser on the server where the MVC application is published, however, the call is unsuccessful. Any ideas how I may find out why this won't connect??
If you are calling the code inside of a controller and the users have to logon to your web app, than this code should give you what you need:
string currentUser = User.Identity.Name;
If your users use your web app anonymously currentUser will be blank.
Adding this code solved the problem.
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
Since we limit access by IP Addresses, very low security risk.

Action to only allow request from same webserver

I have a MVC Controller which exposes a Initialise Action. The other virtual web application hosted on same IIS will need to access this Action.
For security reason, only request coming from same web server (where MVC app is hosted) will need to be granted access to this Iniliase method.
Could someone please help how to achieve this? We can't use localhost to validate as this application will be hosted in Azure which doesn't support locahost requests.
My answer is regarding restricting server-side requests.
The website that calls Initialise would need to make a request to http://www.example.com/controller/Initialise rather than http://localhost/controller/Initialise (replacing www.example.com and controller with your domain and controller names of course).
HttpRequest.IsLocal should be checked in your controller action:
if (!Request.IsLocal)
{
throw new SecurityException();
}
This will reject any requests not coming from the local host. This approach assumes that both the calling site and the requested site share the same IP address - the documentation states that this should work:
The IsLocal property returns true if the IP address of the request originator is 127.0.0.1 or if the IP address of the request is the same as the server's IP address.
For restricting client-side requests Google "csrf mitigation".
If your server has multiple ip addresses, you'll need some extra code. The following handles multiple ip addresses, and handles CDN like cloudflare which will have the wrong ip address in the Request.UserHostAddress property.
Code:
private bool IsLocal()
{
if (Request.IsLocal)
{
return true;
}
string forwardIP = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
{
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
{
string ipString = addr.Address.ToString();
if (Request.UserHostAddress == ipString || forwardIP == ipString)
{
return true;
}
}
}
return false;
}
Access-Control-Allow-Origin tells the browser regarding its accessibility to domains. Try specifying:
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "yourdomain")
I have not tested this to find out if this works.
Use the AntiForgeryToken provided by ASP.NET MVC. Here is an article about that.
http://blog.stevensanderson.com/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/
I think Request.IsLocal is the way to go here. Since you're on using MVC, you could implement a custom attribute to do this for you. See my answer here for a working example

Breeze is not working with some project settings

I have a problem using breeze on a project based on John Papa's HotTowel. I configured breeze like:
var mgr = new breeze.EntityManager('breeze/Breeze');
everything is ok but in the case I change the Project properties Start Action from Current Page to Specific Page: HotTowel/Index and breeze doesn't work properly.
I've checked the requests using firebug. It seems in this case application sends a GET request like this:
http://localhost:53180/HotTowel/Index/breeze/Breeze/Metadata
instead of
http://localhost:53180/breeze/Breeze/Metadata
I've also checked this part of breeze.js which is going to send get request.
The url parameter is set to breeze/Breeze/Metadata in both cases which seems correct.
ctor.prototype.fetchMetadata = function (metadataStore, dataService) {
var serviceName = dataService.serviceName;
var url = dataService.makeUrl("Metadata");
var deferred = Q.defer();
var that = this;
ajaxImpl.ajax({
url: url,
dataType: 'json',...
I've also tried ~/breeze/Breeze but it didn't work as remote service name.
As I'm new to web, probably it's not related to breeze.
The question is why the ajax call (or breeze) depends on how the project activates?
Add a / character to your configuration to execute the request relative to the base directory:
var mgr = new breeze.EntityManager('/breeze/Breeze');
The reason why this happens is because you specified a relative path for the EntityManager and if your url is localhost:53180/HotTowel/Index then the relative url for the EntityManager is localhost:53180/HotTowel/Index + /breeze/Breeze.
To correct the issue, change your EntityManager path to the following:
var mgr = new breeze.EntityManager('breeze/Breeze');

Building a url to a STS in a passive scenario

I'm used to program with WIF and the pattern usually goes like this:
- Add a STS Ref
- Set the location of the web that needs to be autorized (or decorate actions in MVC with [Autorize]
- if the user access the "reserved" section, they are redirected to the STS
But let's say I need to actually build a web page that offer the user a choice of STS in order to logon. Not by accessing a page that triggers the redirection by configuration, but by actively loggin in on the page.
If I do this, what would be the form of the url to my STS ? What are the params I need to set to make the user login then redirect to let'S say the index page ?
WIF can help you with this.
Here's a code snippet of what it looks like:
WSFederationAuthenticationModule fam = FederatedAuthentication.WSFederationAuthenticationModule;
var signInRequest = new SignInRequestMessage(new Uri(fam.Issuer), fam.Realm)
{
AuthenticationType = fam.AuthenticationType,
Freshness = fam.Freshness,
Realm = "some realm",
Context = GetAReturnUrl(),
HomeRealm = "A Home Realm"
};
Then you can retrieve the URL with:
signInRequest.WriteQueryString()

Resources