IIS 6, Wildcard Application Mapping, and FrontPage - asp.net

While I'd love to get rid of requiring FrontPage Extensions on a heavy traffic site I host, the client requires it to administrate the site. Having just implemented Wildcard Application Mapping in IIS 6 on this site in order to provide integrated Forms Authentication security between ASP and ASP.NET resources, this breaks FrontPage extensions. Everything works like a charm, including encrypting and caching roles that are now available even to ASP, except for the loss of FrontPage. Specifically, you cannot even login to FrontPage administration (incorrect credentials).
Has anyone gotten FrontPage to work with Wildcard Application Mapping routing through the ASP.NET 2.0 aspnet_isapi.dll?
UPDATE: I've marked #Chris Hynes answer even though I have not had the time to test (and the current configuration is working for the client). It makes sense and goes along with what I thought was occurring and possibly how to deal with, but did not know where to route the request at that point (fpadmdll.dll). Much thanks!

The issue here sounds like the wildcard mapping is taking precedence over the frontpage extensions ISAPI handler and/or messing up the request/response for that. I'd try creating a handler that does nothing and mapping it to fpadmdll.dll.
Something like this:
namespace YourNamespace
{
public IgnoreRequestHandler : IHttpHandler
{
public IsReusable { get { return true; } }
public void ProcessRequest(HttpContext context)
{ }
}
}
Then map it up in the web.config:
<httpHandlers>
<add verb="*" path="fpadmdll.dll" type="YourNamespace.IgnoreRequestHandler, YourDll" />
</httpHandlers>

Related

Letsencrypt acme-challenge on wordpress or asp.net mvc

I have been trying without success to generate security certificates for my company using Let's Encrypt. My company uses WordPress 3.9.7 for its main website and I am not allow to upgrade to a newer version since that is handled by a third party company.
The website is running on top of Internet Information Services 7.5 on Windows Server 2008 R2.
My question is: How can I make wordpress handle http://www.company.com/.well-known/acme-challenge/mftvrU2brecAXB76BsLEqW_SL_srdG3oqTQTzR5KHeA
?
I have already created a new empty page and a new template that returns exactly what let's encrypt is expecting but wordpress keeps returning a 404 for that page. My guess is that the problem arise with the dot(.) at the beginning of the route (".well-known") but I don't know how to solve that on wordpress.
I am also able to use an asp.net mvc website and make IIS point to that website for a while. Not a good idea though since clients may not be able to reach our website for a few minutes, but still an option. Then the question is: How can I create a controller or a route with a dot(".") at the beginning of the name?
Help will be really appreciated.
For ASP.Net MVC or Web Forms, with certain Routing configs, you'll end up treating this URL as something for the Routing Engine to hand off to the MVC/Forms Handler, not a static file return. The result will be a 404 or a 503. The solution is surprisingly very simple:
If you haven't already, place the Challenge file:
Create the necessary dirs - .well-known is tricky mostly because Microsoft is lazy, but you can either do it from cmdline or create the folder as .well-known. and Windows Explorer will notice the workaround and remove the trailing period for you.
Inside \.well-known\acme-challenge place the challenge file with the proper name and contents. You can go about this part any way you like; I happen to use Git Bash like echo "oo0acontents" > abcdefilename
Then make a Web.Config file in the acme-challenge dir with these contents:
<?xml version = "1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<clear />
<mimeMap fileExtension = ".*" mimeType="text/json" />
</staticContent>
<handlers>
<clear />
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule"
resourceType="Either" requireAccess="Read" />
</handlers>
</system.webServer>
</configuration>
Source: https://github.com/Lone-Coder/letsencrypt-win-simple/issues/37
Done. The file will start returning instead of 404/503 allowing the Challenge to complete - you can now Submit and get your domain validated.
Aside: The above code snippet sets the content-type to json, a historical requirement that is no longer relevant to letsencrypt. The current requirement is there is no requirement - you can send a content-type of pantsless/elephants and it'll still work.
More for Asp.Net
I like to redirect all HTTP requests back to HTTPS to ensure users end up on a secure connection even if they didn't know to ask. There are a lot of easy ways to do that, until you're using LetsEncrypt - because you're going to break requests for .well-known. You can setup a static method in a class, like this:
public static class HttpsHelper
{
public static bool AppLevelUseHttps =
#if DEBUG
false;
#else
true;
#endif
public static bool Application_BeginRequest(HttpRequest Request, HttpResponse Response)
{
if (!AppLevelUseHttps)
return false;
switch (Request.Url.Scheme)
{
case "https":
return false;
#if !DEBUG
case "http":
var reqUrl = Request.Url;
var pathAndQuery = reqUrl.PathAndQuery;
// Let's Encrypt exception
if (pathAndQuery.StartsWith("/.well-known"))
return false;
// http://stackoverflow.com/a/21226409/176877
var url = "https://" + reqUrl.Host + pathAndQuery;
Response.Redirect(url, true);
return true;
#endif
}
return false;
}
}
Now that can do a great job of redirecting to HTTPS except when LetsEncrypt comes knocking. Tie it in, in Global.asax.cs:
protected void Application_BeginRequest(object sender, EventArgs ev)
{
HttpsHelper.Application_BeginRequest(Request, Response);
}
Notice that the bool returned is discarded here. You can use it if you like to decide whether to end the request/response immediately, true meaning, end it.
Finally, if you like, you can use the AppLevelUseHttps variable to turn off this behavior if need-be, for example to test if things are working without HTTPS. For example, you can have it set to the value of a Web.Config variable.

ASP.net Identity can't login

I'm using Asp.net Identity and I've deployed my web role to Azure, and changed my connection string in Web.config so it looks like this:
<connectionStrings>
<add name="DefaultConnection" connectionString="Server=SERVERNAME,1433;Database=DATABASE;User ID=USER;Password=PASSWORD;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;MultipleActiveResultSets=True;" providerName="System.Data.SqlClient" />
</connectionStrings>
I haven't changed default Account controller, but when I try to Login nothing nothing happens except that URL changes to "/Account/Login?ReturnUrl=%2FRoutines" which should happen if user successfully logged in (no errors are shown)
Why is this happening ? (and how can I fix it)
EDIT
Here is code which configures ASP.net Identity
public class DatabaseContext : IdentityDbContext<User>
{
public DatabaseContext()
: base("DefaultConnection")
{
Configuration.LazyLoadingEnabled = true;
}
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>()
.ToTable("Users");
modelBuilder.Entity<User>()
.ToTable("Users");
var usermapping = new UserMapping();
usermapping.MapUser(modelBuilder);
}
I've noticed that now even when I'm using LocalDb I can't Log in, and I don't know why is this because, I haven't changed my code, only changes that I made to the project is Added Azure web service, and Asp.net web Api 2 project (and when I've tested locally I didn't run my web api project), before this everything worked fine.
Are you sure your connection is really used when you deploy (in Web.config.release)?
In case you are, try testing the website locally (with the Azure SQL connection string) and stepping through the code for POST version of Login. There you should be able to see, what exactly is going on. You will probably need to enable access to SQL from your IP address, which is easy to do - just go to Azure Portal, click on your SQL database and down below select Manage, which will automatically ask you for your IP address access permission.
I don't know what I exactly happened, but I've fetched older version of solution from TFS and that helped (eve though code was same)

Thread.CurrentPrincipal is not set in WCF service called using WebGet

I have a web site hosted in IIS that uses Windows Authentication and exposes WCF web services.
I configure this service with an endpoint behavior:
<serviceAuthorization principalPermissionMode ="UseAspNetRoles"
roleProviderName="MyRoleProvider"/>
and a binding:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" />
</security>
When the service is called, Thread.CurrentPrincipal is set to a RolePrincipal with the client's Windows identity and roles provided by by configured provider.
All is well with the world.
Now I've added some additional WCF services that are consumed by REST-ful Ajax calls: Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" in the svc file, WebGet attribute in the service contract, and the AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed) attribute on the service implementation.
I also add the following incantation to web.config as recommended in MSDN:
<system.serviceModel>
...
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
...
</system.serviceModel>
My Ajax service almost works the way I want it to. When it's called, HttpContext.Current.User is set to a RolePrincipal with the roles I expect. But Thread.CurrentPrincipal remains set to an unauthenticated GenericPrincipal.
So I need to add a line of code to each of my service methods:
Thread.CurrentPrincipal = HttpContext.Current.User
Is there any incantation in the configuration file I can use to get Thread.CurrentPrincipal to be set automagically, like it is for a normal SOAP service?
UPDATE
Here's a blog from someone who had the same problem, and solved it by implementing custom behaviors. Surely there's a way to do this out of the box?
UPDATE 2
Coming back to add a bounty to this as it's bugging me again in a new project, using a WCF WebGet-enabled service on .NET 3.5.
I've experimented with a number of options, including setting principalPermissionMode="None", but nothing works. Here's what happens:
I navigate to a WebGet URL that calls my service: http://myserver/MyService.svc/...
I've put a breakpoint in Global.asax "Application_AuthorizeRequest". When this breakpoint is hit, both "HttpContext.Current.User" and "Thread.CurrentPrincipal" have been set to a "RolePrincipal" that uses my configured ASP.NET RoleProvider. This is the behavior I want.
I have a second breakpoint when my service's OperationContract method is called. When this breakpoint is hit, HttpContext.Current.User still references my RolePrincipal, but Thread.CurrentPrincipal has been changed to a GenericPrincipal. Aaargh.
I've seen suggestions to implement a custom IAuthorizationPolicy, and will look into that if I don't find a better solution, but why should I need to implement a custom policy to make use of existing ASP.NET authorization functionality? If I have principalPermissionMode = "UseAspNetRoles", surely WCF should know what I want?
This is an interesting question. I don't have the same setup as you, so its difficult to test whether my recommendations will apply exactly to your use case, but I can share what has worked for us with similar projects.
How we keep Thread.CurrentPrincipal and HttpContext.Current.User in Sync
We wrote an HttpModule called "AuthenticationModule" which inherits from IHtppModule.
We then attached to the HttpApplication.AuthenticateRequest event which happens very early in request lifecycle.
In our AuthenticateRequest event handler, we implement our application specific requirements including setting Thread.CurrentPrincipal and if necessary also the current context user. In this way you only implement this code once for your entire application and if it changes (like if you implement a custom Principal IIDentity) you have only one place to change it. (Don't duplicate this code in every service method.)
public class AuthenticationModule : IHttpModule
{
public void Dispose() { return; }
public void Init(HttpApplication app)
{
app.AuthenticateRequest += new EventHandler(app_AuthenticateRequest);
}
void app_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
// This is what you were asking for, but hey you
// could change this behavior easily.
Thread.CurrentPrincipal = app.Context.User;
}
}
Ours is actually a bit more complex as we implement a custom IIdentity, create an instance of GenericPrincipal and then assign it to both app.Context.User and Thread.CurrentPrincipal; but, the above is what you were asking for.
Don't forget to register your new HttpModule in your web.config!
For integrated app pools:
<system.webServer>
<modules>
<add name="AuthenticationModule" type="YourNameSpace.AuthenticationModule" preCondition="integratedMode" />
</modules>
</system.webServer>
For old classic app pools you'd have to put it in <system.web><httpModules></httpModules></system.web>
You might need to play with what goes inside that AuthenticationRequest event handler and/or the order with which you register the handler. Because ours is totally custom it might be different than what you need. We actually grab the Forms Authentication cookie, decrypt it, etc... you might need to ping some built in methods for WindowsAuthentication.
I believe this is a more generic way to handle your application authentication stuff as it applies to all HttpRequests whether that be a page request, an IHttpHandler, some 3rd party component, etc... That will keep it consistent throughout your app.
I'm not sure. Maybe this will help
<configuration>
<system.web>
<identity impersonate="true" />
</system.web>
</configuration>
http://msdn.microsoft.com/en-us/library/134ec8tc(v=vs.80).aspx

WCF - Using ServiceRoutes instead of svc files -- My app states I need AspNetCompatability only when I first attempt to connect?

public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
private static void RegisterRoutes(ICollection<RouteBase> routes)
{
routes.Add(new ServiceRoute("Calculator", new WebServiceHostFactory(), typeof(CalculatorService)));
}
}
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true">
<serviceActivations>
<add factory="System.ServiceModel.Activation.ServiceHostFactory"
relativeAddress="Calculator.svc"
service="MyServer.CalculatorService"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
When I do this and go to http://localhost/MyApp/Calculator.svc I get an error saying I need AspNetCompatability. So I added [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] and it works, the only thing is I'm worried that I will want my service to use alternative means of transport (not just http) if I want to get into using alternative non-http bindings.
The strange thing is that if I don't set the attribute to Allowed or Required then when I rebuild my page I get that error. After I get that error I hit refresh and everything is fine. And it isn't just if I query the svc through a web browser, but if I have an app it crashes the first time it connects (if the server was restarted) and afterwards it works. What gives?
I think that your problem is messed configuration. You are adding a route and in the same time you are registering the service with configuration based activation. Use either one or second. Also you can use routes and only Http based protocols or non-http protocols but without routes.
Unfortunately, yes, you must enable ASP.NET compatibility to use ServiceRoutes. This is because the ASP.NET runtime is now responsible for routing the traffic instead of just IIS modules.

different web.config settings for http and https

Is it possible to configure your web.config file of your asp.net website to use different settings for users accessing the site via HTTPS?
(eg. I need to have validateRequest attribute for https access set to false, but for internal access (using http) set to true...)
thanks!
For security reasons, I would recommend deploying internal and extenal sites a different sites altogether. That means you could use windows authentication internally and forms authentication externally, and change whatever other config settings you desire. It also means you can limit the attack surface for external evil-doers by not providing access to methods intended for internal users only.
Disable request validation in the Web.config file:
<system.web>
<pages validateRequest="false"/>
</system.web>
And in the Global.asax file, add an event handler for BeginRequest along the lines of:
public class Global : HttpApplication
{
public override Init()
{
base.Init();
BeginRequest += ToggleValidation;
}
void ToggleValidation(object sender, EventArgs e)
{
if (Request.IsSecureConnection)
Request.ValidateInput();
}
}

Resources