Implement Custom FormsAuthenticationModule and replace the default - c#

I cannot find any information on how to implement custom FormsAuthenticationModule.
Specifically, I want to implement a MyFormsAuthentication that mirrors most features of FormsAuthenticationModule, or child of FormsAuthenticationModule
<httpModules>
...
<add name="FormsAuthentication"
type="System.Web.Security.FormsAuthenticationModule" />
...
</httpModules>
MyFormsAuthentication can be used by the element in web.config, instead of the default FormsAuthenticationModule:
<authentication mode="Forms" />
The reason is that I want to support the domains format below:
Set A
a.domain.com
a.x.domain.com
a.y.domain.com
Can share cookie within set A.
Set B
b.domain.com
b.x.domain.com
b.y.domain.com
Can share cookie within set B.
Cookies (including Forms Authentication cookie) cannot be shared between domains of set A and set B, but use the same code base.
Current implemention
FormsAuthenticationTicket is used to generate forms auth cookie.
Any idea, or better solution?
https://msdn.microsoft.com/en-us/library/aa480476.aspx

Related

Web.config IIS rewrite rule to ignore specific file

I have a site txt map sitemaphttp.txt on my site. I redirect all my traffic to HTTPS. I still want Google to be able to read this sitemap, so it won't read it from https://example.com/sitemaphttp.txt but from http://example.com/sitemaphttp.txt. What rewrite rule I need to add to web.config so it will ignore all the other rules and just let that specific file through.
To link to a custom site-map provider from a parent site map
From the parent site map, create a SiteMapNode in the location in
the navigation structure where you want the child site map to be
displayed.
For example, if you are using the default XmlSiteMapProvider class,
open the Web.sitemap file and add the following SiteMapNode in the
appropriate location in the hierarchy:
<siteMapNode provider="SimpleTextSiteMapProvider" />
Note
The provider attribute corresponds to the provider's name attribute in the Web.config file.
Add the custom site-map provider to the Web.config file by using an add element. The following code adds the custom provider named SimpleTextSiteMapProvider, but maintains XmlSiteMapProvider as the default site-map provider.
<configuration>
<!-- other configuration sections -->
<system.web>
<!-- other configuration sections -->
<siteMap defaultProvider="XmlSiteMapProvider">
<providers>
<add
name="SimpleTextSiteMapProvider"
type="Samples.AspNet.SimpleTextSiteMapProvider,Samples.AspNet"
siteMapFile = "siteMap.txt" />
</providers>
</siteMap>
</system.web>
</configuration>

Custom config elements collection in Web.config - Using a key to choose

Intro
I'm developing a WebApp built on C# ASP.NET.
I've been researching creating a "Custom Configuration" section with child elements in the Web.config file, and I've hit a bit of a snag when it comes to consuming the keys/values in the data.
I seem to be going round in circles and I don't know how to tackle the issue I'm having.
Situation
I have a few different Connection Strings defined in the Web.Config file, in the <connectionStrings> section. They are for dev, test, and live databases.
<connectionStrings>
<add name="connectionOne" connectionString="..." providerName="..." />
<add name="connectionTwo" connectionString="..." providerName="..." />
<add name="connectionThree" connectionString="..." providerName="..." />
</connectionStrings>
The WebApp is currently hard-coded to use one of these connection strings - if I need to change which one to use, I need to re-compile.
Desired Functionality
I'd like to define a section in the Web.config, let's say DbSettings.
In that, I'd then like to be able to define some child elements for, let's say DbSettings, in which I could define dbConnectionName, foo, bar etc. as attributes.
For example:
<dbSettings>
<dbSetting key="DbSetting1"
dbConnectionName="connectionOne"
foo="fooOne"
bar="barOne" />
... and so on
</dbSettings>
Then, perhaps in the <appSettings> section, define which of these DbSettings elements I want to use to get the settings from:
<appSettings>
<add name="dbSettingsKey" value="DbSetting1" />
</appSettings>
Desired Web.config section
Here is a fuller example of what I'd imagine my Web.config file to look like:
Connection Strings
<connectionStrings>
<add name="connectionOne" connectionString="..." providerName="..." />
<add name="connectionTwo" connectionString="..." providerName="..." />
<add name="connectionThree" connectionString="..." providerName="..." />
</connectionStrings>
App Settings
<add key="dbSettingsKey" value="DbSetting1" /> // or 2, or 3 etc.
DbSettings (custom section)
<dbSettings>
<dbSetting key="DbSetting1"
dbConnectionName="connectionOne"
foo="fooOne"
bar="barOne" />
<dbSetting key="DbSetting2"
dbConnectionName="connectionTwo"
foo="fooTwo"
bar="barTwo" />
<dbSetting key="DbSetting3"
dbConnectionName="connectionThree"
foo="fooThree"
bar="barThree" />
</dbSettings>
My question...
How the devil am I going to get this desired functionality in the C# code?
I've read loads on "creating your own custom section", and similarly "creating a custom config collection". But, I just can't seem to glue it all together to apply for my situation.
I'd like to be able to have a class (like the one I'm using at the moment with the hard-coded strings), which I can reference necessary properties (as I am doing, at the moment) - and then the code can dynamically load the correct settings at run-time from the sections I've described above.
As always, thank you in advance for your suggestions and help.
I agree with the comments. The way this is usually done is you deploy a different web.config to each environment. When your deployment group (or you) deploys, you deploy everything EXCEPT the web.config unless you have changes to push.
In answer to your other question, adding a custom section is not trivial. It's quite a bit of work. Custom section handler which requires a whole bunch of configuration element classes and a bunch of configuration element collection classes... and then, if you want it to "work" correctly, you also need to create a schema and register that with the IDE, etc.
For your particular case, I'd just do it the "normal" way :).

IIS8 MVC asp.NET Session not working. Getting null object reference error

Can't get session variables working, I've tried all the solutions I could find online.
On page 1, I call the following in the c# model
HttpContext.Current.Session["lol1"] = "123";
Later on I use an ajax call to return this session variable to me in the c# model,
return HttpContext.Current.Session["lol1"].ToString();
In javascript, I pick it up in the ajax success function and put it in an alert box with alert(e);
I get an null object reference error. Seems like my variable didn't save into the session. This all works fine on localhost via debug, including the alert.
Things I have tried (currently set):
-DefaultAppPool setting Maximum Worker Processes: 1
-IIS manager->ASP->Services->Session Properties->Enable Session State:true
-IIS manager->Session State->In process
-In my solution web.config:
<system.web>
<sessionState mode="InProc" timeout="25"></sessionState>
</system.web>
<system.webServer>
<modules>
<remove name="Session" />
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
</modules>
</system.webServer>
Try setting the SessionStateBehavior in your controller. For example:
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
It is recommended to use ReadOnly if you only need to read from Session and not write to it to prevent blocking.
Link to Microsoft's SessionStateBehavior enumeration.
(for more info on ASP.NET's blocking when controllers use writable sessions see this link: Does Session State read/write everything when you access with DynamoDB)
Hope this helps!
Regards,
Ross

Configuring custom authorization with ELMAH

How can I configure ELMAH to display only for certain people without default ASP.NET authorization roles manager?
I (as well as many others, I think) use my own authorization logic and build my projects from zero without using provided templates. I want to log errors but it seems that it is impossible to configure ELMAH (somehow override functionality) to make it work with some other authorization or even to make it work only for particular IP addresses.
Since I will have access to web.config I tried to change these values in order to NOT display elmah by default.
<add key="elmah.mvc.disableHandler" value="false" />
<add key="elmah.mvc.disableHandleErrorFilter" value="false" />
<add key="elmah.mvc.requiresAuthentication" value="false" />
And when I want to view errors switch them from true to false and see errors, then switch back. But it seems that when I change these values all logs are erased.
What can I do?
I think the easiest approach would be to make some minor alterations to your custom authorization so the ELMAH authorization will work.
Option 1: Set the FormsAuthentication cookie on login. This way, in the web.config the allow users="username" should work. On successful login you can set the cookie with
FormsAuthentication.SetAuthCookie(theUsername, true).
The ELMAH authorization would look something like:
<location path="elmah.axd" inheritInChildApplications="false">
<system.web>
<authorization>
<allow users="theUserName" />
<deny users="*" />
</authorization>
</system.web>
...other config settings
</location>
Option 2: If you are using putting users into roles, you can override the default role provider to use the function you made to get roles. This way is a little more involved but then lets you harness role-basing authentication in the web.config, which is really nice for securing things like static file (.pdf etc) delivery. I can add code for this if interested.
I was using the ASP.NET Identity Framework, so this answer is regarding that setup. I also used the Elmah.MVC package in NuGet. I edited the following lines in web.config. (you need to supply your own user name in the allowedUser setting)
<add key="elmah.mvc.requiresAuthentication" value="true" />
<add key="elmah.mvc.allowedRoles" value="*" />
<add key="elmah.mvc.allowedUsers" value="your_user_name" />
It appears that ELMAH does get the authentication information from the current thread principal, which the ASP.NET Identity Framework will establish on your behalf upon login.
It doesn't matter how the system gets the username or roles in this case. Whether it be from the built-in providers, a provider you implement yourself, or if during your custom authentication you populate this information yourself. All it takes is to manually set the principal during something like the Application_PostAuthenticationRequest event. This should give you the jist of it.
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
//Obtain username and roles from application datastore and use them in the next line
Thread.CurrentPrincipal = new GenericPrincipal(
new GenericIdentity("userNameHere"),
new string[] { "Admin", "CanDeleteStuff", "CanEditStuff", "OtherRole" }
);
}
This will let you use something like this in your web.config
<location path="elmah.axd" inheritInChildApplications="false">
<system.web>
<authorization>
<allow roles="Elmah"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
Not to mention being able to use User.IsInRole("CanEditStuff") in your code.

ASP.Net C# Routing; HttpHandler; and HttpModule not working

I am having quite a few problems with custom extensions and intercepting existing handlers.
What am I trying to do
Based upon persisted options, I would like all 'virtual' extensions to be handled by set handlers. All pages are dynamically built, and no actual files exist on the site. The site populates the content, forms the html output and returns it as the web result.
This is required as I am setting up a fat/thin relationship between 2 servers. The thin server will simply pass on the request to the fat server - where the request is processed and response issued back down the line.
The project is for a dynamic multi-domain content management system. The thin server may not be .net compatible (hence the external request), but will be .net optimised (hence the need for handlers).
The Problem
What I want is to re-route existing extensions - aspx; php; html.
I have achieved this in my local environment using a custom HttpModule which sets the appropriate handler. I have explored setting the tag in config, but the the extensions are re-routed using dynamic rules that are persisted.
As mentioned, this solution works on localhost.
When uploaded, the .Net extensions are handled by the module correctly but any custom extensions or non-.net extensions return a 404 error.
Seeking an alternative, I have experimented with routing within Global, but this dis not work either.
I have also attempted to use to register the custom extensions... but each are met with the same result - 404 not found.
Global Routing attempt:
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new Route("{action}.sqs", new SqlRequestHandler()));
}
.Config (for handler and module attempt)
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime requestValidationMode="2.0" />
<customErrors mode="Off"/>
<httpHandlers>
<add path="*.sqs" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" />
<add path="*.sql" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" />
</httpHandlers>
<httpModules>
<add name="SisBerCMS" type="CmsMapper.VirtualModule, CmsMapper" />
</httpModules>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<modules>
<add name="SisBerCMS" type="CmsMapper.VirtualModule, CmsMapper" />
</modules>
<handlers>
<add path="*.sqs" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" name="sqsHandler" />
<add path="*.sql" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" name="sqlHandler" />
</handlers>
</system.webServer>
Custom Module (CmsMapper.VirtualModule)
if (extentionMap != null)
{
// note that extentionMap.ExtentionType is a predetermined enum
switch (extentionMap.ExtentionType)
{
// If the extention is banned then pass back a generic message
case ExtentionType.Banned:
this.WriteTextResponce("Invalid extention detected:" + extentionMap.Extention);
break;
// Remap .Ajax requests to the ajax handler
case ExtentionType.Ajax:
this._app.Context.RemapHandler(new AjaxHandler());
break;
// Remap session query or sql requests to the sql handler
case ExtentionType.SessionQuery:
this._app.Context.RemapHandler(new SqlRequestHandler());
break;
// if the extention is not ignored, re map to the virtual page handler
default:
bool isManagementServer = this._app.Context.Request.Url.Authority != VirtualModule.RESPONSE_SERVER;
bool isPostRequest = !String.IsNullOrEmpty(this._app.Context.Request.Form[HtmlRequest.RequestOrigin]);
bool isGetRequest = !String.IsNullOrEmpty(this._app.Context.Request.QueryString[HtmlRequest.RequestOrigin]);
bool isIgnored = extentionMap.ExtentionType == ExtentionType.Ignore;
if ((isPostRequest || isGetRequest) && !isIgnored)
{
this._app.Context.RemapHandler(new VirtualHandler());
}
else
{
this._app.Context.RemapHandler(new ExternalRequestHandler());
}
break;
}
}
All the handlers are pretty standard implementing the following:
public class SqlRequestHandler : IHttpHandler, IRequiresSessionState, IRouteHandler
Again, the preferred method - HttpModule - works on my localhost machine. This could be a server config issue (in which case I'm looking for a work around), but the fact that the .net extensions are being handled is strange - as this would imply that issues with medium trust should not apply, however issues regarding extension handling on the server may take priority over the .net application.
The server is shared hosting (therefore I am unable to alter the machine.config files), is IIS6 using 4.0.
Thank you for any suggestions on how to resolve this issue.
Mike
You need to configure web site in IIS 6.0 to route all extensions (including extensionless paths known as wildcard extension mapping) to ASP.NET ISAPI dll (and disable the check for file exists).
You can of course do this mapping selectively only for those extensions that you want to route via ASP.NET code. But wildcard mapping will be more useful in case you don't have predefined set of extensions.
In the absence of such mappings, IIS will not forward requests for unknown extensions to ASP.NET (and routing code will not even come into picture) - rather IIS will pass the extension to default (static file) handler that will issue 404 if file is not present.
See this article that describes these steps (for ASP.NET MVC but the same applies to your case): http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx
Near the end of article, author has given how to add wildcard script map

Categories