Request.ServerVariables["LOGON_USER"] blank when using ASP.NET wildcard application mapping - asp.net

When I set up wildcard application maps so that asp.net handles requests (setting executable path to C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll) LOGON_USER is blank when I access a page via site.com/directory/ - site.com/directory/default.aspx returns the correct LOGON_USER value.
How can I fix this without needing to take off application maps?
Simple test:
<%# Request.ServerVariables["LOGON_USER"] %>
Results in DOMAIN\UserName when application maps not set up, but a blank string when they are.
Edit:
The site uses Forms authentication for administration, but I need to do LDAP queries based on the currently logged in user (and to search Active Directory) - anonymous access is turned off and Windows Integrated Authentication turned on.

I've never seen that before, and I almost always wildcard map, but is there any reason you're not using Request.User (or the Page's User helper property) instead of the string-based variable? I'm not sure if that'll help, but it is at least more safe from typoes.

Related

Windows authentication without a backend?

We have a web application that runs on ASP.Net. I don't know much on authentication for ASP.Net, but the application never asks me for a username and password (when on a Windows machine) and that's really great. The app has this in the web.config file: <authentication mode="Windows" />.
I've been assigned the task to re-create this application. I noticed that the only use for the backend is to get the user's AD account username. After that, it makes some HTTP requests that require the username. Besides that, the back-end is useless. If that's the case, then is there a way for be to get the user's credentials without needing a back-end (ASP.Net server)?
Really, a "backend" is anything on the server. You can't have a website without a web server, and that server is the "backend". It's always doing some kind of processing, even if it's not using ASP.NET.
But if I understand your requirements, you just want a way to inject the username into an otherwise static HTML file.
IIS handles the Windows Authentication, so you don't need ASP.NET to have Windows Authentication. But technically, static means static, so you can't modify an plain HTML file before it's served (unless you change stuff in IIS that would slow down actually static files).
But, the next best thing is to use a feature in IIS called Server-Side Include Directives (SSI). By default, IIS is setup to send files with extensions of .stm, .stm, and .shtml through its SSI engine, which processes the file and looks for specific "directives".
One of the features is the #echo directive, which lets you inject any IIS server variable into the content. If Windows Authentication is enabled and working, IIS stores the DOMAIN\username in the LOGON_USER server variable.
You can inject that into your page, and use JavaScript to split the domain and username into separate pieces. But you can't inject LOGON_USER directly into the JavaScript because of the slash, which JavaScript interprets as an escape character. So you have to put it in an HTML element, and use JS to pull it from there.
Here's an example of a simple page that stores the domain and username into JavaScript variables and displays them on the page. You'd have to save this file as .stm, .stm, or .shtml.
<html>
<body>
<span id="domainUsername" style="display:none"><!-- #echo var = "LOGON_USER" --></span>
Domain: <span id="domain"></span><br>
Username: <span id="username"></span>
<script>
var domainUsername = document.getElementById("domainUsername").innerText.split("\\");
var domain = domainUsername[0];
var username = domainUsername[1];
document.getElementById("domain").innerText = domain;
document.getElementById("username").innerText = username;
</script>
</body>
</html>
And remember you still need <authentication mode="Windows" /> in your web.config.
Then you can also set that file as the Default Document for your website (since IIS won't, by default, use a file with those extensions as the default doc).

ASP.NET Webforms User Authorization with Routing

I have a route
routes.MapPageRoute("clientOrder", "Contract/{contractId}/Orders",
"~/ContractOrders.aspx");
The idea is to authorize user to allow access to a certain set of contracts.
For instance user1 has access to pages Contract/001/Orders and Contract/002/Orders
user2 has access only to Contract/003/Orders, etc.
I'm using Forms Authentication and trying restrict access with
CheckUrlAccessForPrinсipal but it checks only physical access to the page not logical.
I tried to check access in Global.asax in Application_AuthorizeRequest but
Request.RequestContext.RouteData there is allways empty so I don't know the requested contractId. I can parse it manually from HttpRequest object. But it is a very dummy and unraliable solution.
Please advice
I believe that the only way is to add some code to check the contractId at the ContractOrders.aspx page level and if the Id doesn't pass the autorization, you manually redirect somewhere to indicate that the access is not granted.
The built-in mechanism always works at the physical level with route maps, so no matter how your route looks like, the engine always checks the access to the resource the route is mapped to, not the route itself.

WIF cross-domain on one IIS site, dynamically setting of realm

We have a lot of domains running on one IIS WebSite/AppPool.
Right now we are in the process of implementing SSO with Windows Identity Foundation.
in web.config the realm has to be set with
<wsFederation passiveRedirectEnabled="true" issuer="http://issuer.com" realm="http://realm.com" requireHttps="false" />
My problem is that the realm is dependent on which domain the user accessed the website on
so what I did is that I set it in an global action filter like this
var module = context.HttpContext.ApplicationInstance.Modules["WSFederationAuthenticationModule"] as WSFederationAuthenticationModule;
module.Realm = "http://" + siteInfo.DomainName;
My question is. When I set the realm like this, is it set per user instance
or application instance.
Scenario.
User A loads the page and the realm get set to domain.a.com.
User B is already logged in on domain.b.com and presses login.
Since user A loaded the page before User B pressed login, user A will hit the STS
with the wrong realm set.
What will happen here?
If this is not the way to set the realm per user instance, is there another way to do it?
I have already solved the problem.
I set PassiveRedirectEnabled to false in web.config
I set up the mvc project to use forms authentication, eventhough I dont.
I do that so that I will get redirected to my login controller with a return url everytime a controller with [Authorize] is run.
In my login controller I do
var module = HttpContext.ApplicationInstance.Modules["WSFederationAuthenticationModule"] as WSFederationAuthenticationModule;
module.PassiveRedirectEnabled = true;
SignInRequestMessage mess = module.CreateSignInRequest("passive", returnUrl, false);
mess.Realm = "http://" + Request.Url.Host.ToLower();
HttpContext.Response.Redirect(mess.WriteQueryString());
This is definitely not really how it should be, for me it feels like Windows Identity Foundation is lagging behind, both in documentation and microsoft technology wise, no examples for MVC.
For other MVC people i recommend them to not use the fedutil wizard, and instead write the code and configuration themself

How do I get the host domain name in ASP .NET without using HttpContext.Current.Request?

I've got an ASP .Net application running on IIS7. I'm using the current url that the site is running under to set some static properties on a class in my application. To do this, I'm getting the domain name using this (insde the class's static constructor):
var host = HttpContext.Current.Request.Url.Host;
And it works fine on my dev machine (windows XP / Cassini). However, when I deploy to IIS7, I get an exception: "Request is not available in this context".
I'm guessing this is because I'm using this code in the static constructor of an object, which is getting executed in IIS before any requests come in; and Cassini doesn't trigger the static constructor until a request happens. Now, I didn't originally like the idea of pulling the domain name from the Request for this very reason, but it was the only place I found it =)
So, does anyone know of another place that I can get the host domain name? I'm assuming that ASP .Net has got to be aware of it at some level independent of HttpRequests, I just don't know how to access it.
The reason that the domain is in the request is...that's what's being asked for. For example these are a few stackexchange sites from http://www.stackexchangesites.com/:
http://community.ecoanswers.com
http://www.appqanda.com
http://www.irosetta.com/
If you ping them, you'll see they all point to the same IP/Web Server and be served by the same app (or multiple apps in this case, but the example holds if it was one big one)...but the application doesn't know which one until a host header comes in with the request asking the server for that site. Each request may be to a different domain...so the application doesn't know it.
If however it doesn't change, you could store it as an appSetting in the web.config.
Use global.asax or write a HttpModule and subscribe to start request events. You will have the request passed into your event handler.
Use this instead:
HttpRuntime.AppDomainAppVirtualPath
Or if you want the physical path:
HttpRuntime.AppDomainAppPath
For further reading:
http://weblogs.asp.net/reganschroder/archive/2008/07/25/iis7-integrated-mode-request-is-not-available-in-this-context-exception-in-application-start.aspx

Use the ASP.NET request user for Log4net log entries

My ASP.NET site is using Integrated Authentication with impersonation turned off. I have added a "%username" to my "conversionPattern" in the web.config to add the user name to each logging entry. However this will use the application pool identity's user name, and not the current visiting user's name.
Any ideas on how best to do this? Do I have to write a custom appender? I don't mind any minor performance penalties as this is a small intranet site. Thanks!
There's built in ASP.NET pattern converters in recent versions of log4net:
%aspnet-request{REMOTE_ADDR} and %aspnet-request{AUTH_USER}
https://stackoverflow.com/a/7788792/74585
You can also access the contents of
aspnet-cache
aspnet-context
aspnet-session
https://logging.apache.org/log4net/log4net-1.2.13/release/sdk/log4net.Layout.PatternLayout.html
An alternative (and easier) solution you may want to take a look at is to use the ThreadContext class (formerly implemented as the MDC and NDC classes). You could have something like this inside an HttpModule (before the request arrives at your page) or anywhere else before you log your first message:
ThreadContext.Properties["user"] = username;
And then include the following in your conversionPattern:
%property{user}

Resources