Dynamic use of cookies in Forms-Authentication - c#

Currently I have 2 ways:
when i set my web.config cookieless="UseCookies" my url looks that:
http://example.com/Stuff
<sessionState timeout="60" cookieless="UseCookies"/>
when i set cookieless="true" i have such urls
http://example.com/%28S%28uanyuxwgaviyonky0lxwq3vq%29%29/Stuff
<sessionState timeout="60" cookieless="true"/>
Is i possible to set cookieless property dynamic? Something like
if(/*condition*/)
{
sessionState .cookieless = "true";
}
else
{
sessionState .cookieless = "UseCookies";
}
This must be somewhere in SessionStart of Global.asax or something

The basic Idea here is you want to modify the WebConfig file at runtime. i didn't tried my-self , but as curiosity i searched over internet , and found This link
and according to this your code in Global.asax will be like
Note : this actually writes the new value the web.config
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
Configuration config;
config = WebConfigurationManager.OpenWebConfiguration("~");
SessionStateSection SessionState = config.GetSection("system.web/sessionState") as SessionStateSection;
if (SessionState != null)
{
SessionState.Mode = System.Web.SessionState.SessionStateMode.InProc;// changes
if (true/*condition*/)
{
SessionState.Cookieless = System.Web.HttpCookieMode.UseCookies;
}
else
{
SessionState.Cookieless = System.Web.HttpCookieMode.UseUri; // not sure about this one
}
config.Save();
}
}

This question is discussed regularly since 2003 (see for example Switch dynamically to cookieless session state asp.net?.
You cannot change cookieless false/true from the application because decision is made by IIS before begin_request fired.
Some available options are:
A.
<system.web>
<sessionState cookieless="AutoDetect"></sessionState>
</system.web>
B.
Set some folder inside your webroot as web application and set cookieless="true"

IIS manage it before application request start so you can not change it on application level.

Related

Programmatically edit the SslFlags in the web.config on an IIS site

On IIS, I have a site on which I wish to edit the SslFlags.
I want to have these flags being set in the web.config at the site level instead of applicationHost.config.
I managed to have the UI of IIS to behave as expected by declaring the access section in the web.config, and allowing the override of the access section by editing applicationHost.config with the following element:
<section name="access" overrideModeDefault="Allow" />
Editing the SslFlags through the UI will edit the web.config file as expected. The section is not locked and the overridden value is considered.
However, when using the Microsoft.Web.Administration assembly to read and edit these flags by using the following code, the values which are considered are the ones of applicationHost.config, both when reading and editing.
In that first example, I used GetWebConfiguration to get the Configuration.
var serverManager = ServerManager.OpenRemote(serverName);
// Try with GetWebConfiguration
Configuration config = serverManager.GetWebConfiguration(sitename);
ConfigurationSection accessSection = config.GetSection(
"system.webServer/security/access",
sitename);
also, same applies if I retrieve the configuration with GetApplicationHostConfiguration:
config = serverManager.GetApplicationHostConfiguration();
accessSection = config.GetSection(
"system.webServer/security/access",
sitename);
I feel like I'm missing something obvious here, but I can't seem to access the values of the SslFlags in Web.config, how can I achieve that?
The first thing I would recommend is to only unlock sections for the specific web site or application that you want to allow overriding the values. For that you can do it quite easily using AppCmd.exe, for example:
C:\Windows\System32\inetsrv\appcmd.exe unlock config "Default Web Site/" /section:system.webServer/security/access -commit:apphost
Once you do that, then you can use the following code:
using(ServerManager serverManager = new ServerManager()) {
Configuration config = serverManager.GetWebConfiguration("Default Web Site");
ConfigurationSection accessSection = config.GetSection("system.webServer/security/access");
accessSection["sslFlags"] = #"SslRequireCert";
serverManager.CommitChanges();
}

How to remove X-AspNetMvc-Version from header response without touching source code file (Global.asax.cs)?

I need to disable the X-AspNetMvc-Version from the response header of a large number of applications. The server where the applications are hosted has just the content and config files Global.asax, web.config, app.config for the application and source code files (*.cs) reside with some other team.
I could only find the solution as adding
MvcHandler.DisableMvcResponseHeader = true;
to Global.asax.cs.
Any alternative solution(s) that involves working with any config file(s)?
Set enableVersionHeader to false in your web.config is an alternate, I would prefer the web.config change to a handler solution like you have, obviously, since you will not need to access global.asax.cs to make the change:
just copy this line into the web.config’s <system.web> section:
<httpRuntime enableVersionHeader="false" />
http://msdn.microsoft.com/en-us/library/system.web.configuration.httpruntimesection.enableversionheader(v=vs.110).aspx
http://madskristensen.net/post/Remove-the-X-AspNet-Version-header
Unfortunately the only way is to use the following code in your Global.asax:
MvcHandler.DisableMvcResponseHeader = true;
This is an old post but no marked answer. I was able to achieve this using the code below. In your global.asax.cs we can remove any header.
protected void Application_PreSendRequestHeaders()
{
if (HttpContext.Current != null)
{
HttpContext.Current.Response.Headers.Remove("x-aspnet-version");
}
}

How to create an HTTP redirect from a virtual directory using C#

I can create an http redirect in my IIS by using the following code. However, it only creates a redirect for the main site "MySite" itself. How do I programatically add a redirect to a virtual directory? Is there some setting I need to set when I create the VD? Thanks!
ServerManager iisManager = new ServerManager();
Configuration config = iisManager.GetWebConfiguration("MySite");
ConfigurationSection httpRedirectSection = config.GetSection("system.webServer/httpRedirect");
httpRedirectSection["enabled"] = true;
httpRedirectSection["destination"] = #"http://www.google.com";
httpRedirectSection["exactDestination"] = false;
httpRedirectSection["httpResponseStatus"] = #"Found";
iisManager.CommitChanges();
Sean,
What your code is doing is essentially modifying the web.config file for your site. The virtual directory is likely configured as an application so it would have its own web.config file. Did you try doing the same thing but simply changing:
Configuration config = iisManager.GetWebConfiguration("MySite/VirtDirName");
Also, the virtual directory, since it is a child application may already be inheriting the httpRedirect setting from the parent site, I'd check first that this is not the case.
http://www.iis.net/ConfigReference/system.webServer/httpRedirect
http://msdn.microsoft.com/en-us/library/ms178685.aspx
If your hosting it in IIS 7+ then you could use web.config.
Place a web.config in the directory and then add
<?xml version="1.0"?>
<configuration>
<system.webServer>
<httpRedirect enabled="true" destination="/[PathFromRoot]/" childOnly="true" httpResponseStatus="Temporary" />
</system.webServer>
</configuration>
You can read up on the properties here

How to override authentication for certain web pages....?

Well I am having following code written in master page: -
<authentication mode="Forms">
<forms loginUrl="Loginpage.aspx" />
</authentication>
Now it will redirect to "Loginpage.aspx" if authentication fails.
Now what If I would like to override this authentication for few pages. Also note that the number of pages and page names are not available at design time, so cannot include the aspx page names in configuration file.
Is there anyway to override authentication for few aspx pages?
-Anil
Henrik's answer is a good one and should work if properly implemented. However, this is another option which tackles the problem more from a configuration standpoint. I know that you mentioned that you won't know the page names ahead of time so you can't include an entry in web.config for each page BUT web.config allows you to secure folders too. You could have all pages that require authentication placed in a folder called "AuthRequired" and all pages that don't require authentication placed in a folder called "Anonymous", for example. Then in your web config you could have the following entries:
<location path="AuthRequired">
<system.web>
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
</system.web>
</location>
<location path="Anonymous">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
You can listen to the AuthorizeRequest event and act accordingly. Create your own Http Module to do this.
Three options:
use the configuration settings above together with generating folders with web.config entries. This is a pretty shoddy way of doing it.
listen to the event AuthenticateRequest, the code looks something like this:
public class UserAuthenticationModule : IHttpModule
{
private HttpApplication _Context;
private RoleManagerModule _RoleManager;
public void Init(HttpApplication context)
{
_Context = context;
context.AuthenticateRequest += AuthenticateUser;
_RoleManager = (RoleManagerModule)context.Modules["RoleManager"];
_RoleManager.GetRoles += roleManager_GetRoles;
}
// http://stackoverflow.com/questions/1727960/how-to-keep-roleprovider-from-overriding-custom-roles
private void roleManager_GetRoles(object sender, RoleManagerEventArgs e)
{
if (_Context.User is UserPrincipal)
e.RolesPopulated = true; // allows roles set in AuthenticateUser to stick.
}
private static void AuthenticateUser(object sender, EventArgs e)
{
var app = (HttpApplication) sender;
if (app.Context == null) return;
var user = app.Context.User;
// not signed in, forms authentication module takes care of redirecting etc.
if (user == null) return;
// we're done then.
if (user is IUser) return;
var userEntity = IoC.Resolve<IUserRepository>().FindByUserName(user.Identity.Name);
// we can't find the user in the database.
if (userEntity == null)
throw new ApplicationException(string.Format("User \"{0}\" deleted from, or renamed in, database while logged into application.",
user.Identity.Name));
// signed in, assigning user, which should assign Thread.CurrentPrincipal as well (it wouldn't do this on PostAuthenticateRequest).
app.Context.User = new UserPrincipal(userEntity);
userEntity.SetAuthenticated();
}
//Implement IDisposable.
public void Dispose()
{
}
}
If your UserPrincipal implements IPrincipal, then IsInRole is used to give role-based access to your pages.
The service-oriented way; set up a small transparent proxy server. List your endpoints/uri-s in a dynamic store, like what you are describing. Set up an authorization service such as Rhino Security; expose its service interfaces as a REST-API or a request/reply interface or something. Assume from the web app's perspective that every request is allowed and take care of where you redirect. In the proxy server, e.g. nginx which is a very nice asynchronous C-based proxy server on Linux, call your authorization service from a filter/module. 'Security in depth' and you can share configuration for security in the Authorization Service.
The principle that you follow is that if something is not allowed in a web application you do throw new HttpException(405, "The current operation you are trying to perform is now allowed for your role or user or chosen path in life") in the AuthorizeRequest event. Note that there's a AuthenticateRequest and another AuthorizeRequest event
You should usually have one point where users can be authenticated - get confirmed that they are who they claim they are. Next, you are probably talking about authorisation, which is a matter of allowing/denying performing certain operation to the user, like sending a GET request. Authorisation rules in a simple scenarios can be configured in the web.config through location element, as presented by Tom.

HttpContext.Current.Session is null when routing requests

Without routing, HttpContext.Current.Session is there so I know that the StateServer is working. When I route my requests, HttpContext.Current.Session is null in the routed page. I am using .NET 3.5 sp1 on IIS 7.0, without the MVC previews. It appears that AcquireRequestState is never fired when using the routes and so the session variable isn't instantiated/filled.
When I try to access the Session variables, I get this error:
base {System.Runtime.InteropServices.ExternalException} = {"Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the <configuration>.
While debugging, I also get the error that the HttpContext.Current.Session is not accessible in that context.
--
My web.config looks like this:
<configuration>
...
<system.web>
<pages enableSessionState="true">
<controls>
...
</controls>
</pages>
...
</system.web>
<sessionState cookieless="AutoDetect" mode="StateServer" timeout="22" />
...
</configuration>
Here's the IRouteHandler implementation:
public class WebPageRouteHandler : IRouteHandler, IRequiresSessionState
{
public string m_VirtualPath { get; private set; }
public bool m_CheckPhysicalUrlAccess { get; set; }
public WebPageRouteHandler(string virtualPath) : this(virtualPath, false)
{
}
public WebPageRouteHandler(string virtualPath, bool checkPhysicalUrlAccess)
{
m_VirtualPath = virtualPath;
m_CheckPhysicalUrlAccess = checkPhysicalUrlAccess;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
if (m_CheckPhysicalUrlAccess
&& !UrlAuthorizationModule.CheckUrlAccessForPrincipal(
m_VirtualPath,
requestContext.HttpContext.User,
requestContext.HttpContext.Request.HttpMethod))
{
throw new SecurityException();
}
string var = String.Empty;
foreach (var value in requestContext.RouteData.Values)
{
requestContext.HttpContext.Items[value.Key] = value.Value;
}
Page page = BuildManager.CreateInstanceFromVirtualPath(
m_VirtualPath,
typeof(Page)) as Page;// IHttpHandler;
if (page != null)
{
return page;
}
return page;
}
}
I've also tried to put EnableSessionState="True" on the top of the aspx pages but still, nothing.
Any insights? Should I write another HttpRequestHandler that implements IRequiresSessionState?
Thanks.
Got it. Quite stupid, actually. It worked after I removed & added the SessionStateModule like so:
<configuration>
...
<system.webServer>
...
<modules>
<remove name="Session" />
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
...
</modules>
</system.webServer>
</configuration>
Simply adding it won't work since "Session" should have already been defined in the machine.config.
Now, I wonder if that is the usual thing to do. It surely doesn't seem so since it seems so crude...
Just add attribute runAllManagedModulesForAllRequests="true" to system.webServer\modules in web.config.
This attribute is enabled by default in MVC and Dynamic Data projects.
runAllManagedModulesForAllRequests=true is actually a real bad solution. This increased the load time of my application by 200%. The better solution is to manually remove and add the session object and to avoid the run all managed modules attribute all together.
None of these solutions worked for me. I added the following method into global.asax.cs then Session was not null:
protected void Application_PostAuthorizeRequest()
{
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
What #Bogdan Maxim said. Or change to use InProc if you're not using an external sesssion state server.
<sessionState mode="InProc" timeout="20" cookieless="AutoDetect" />
Look here for more info on the SessionState directive.
Nice job! I've been having the exact same problem. Adding and removing the Session module worked perfectly for me too. It didn't however bring back by HttpContext.Current.User so I tried your little trick with the FormsAuth module and sure enough, that did it.
<remove name="FormsAuthentication" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule"/>
It seems that you have forgotten to add your state server address in the config file.
<sessionstate mode="StateServer" timeout="20" server="127.0.0.1" port="42424" />
The config section seems sound as it works if when pages are accessed normally. I've tried the other configurations suggested but the problem is still there.
I doubt the problem is in the Session provider since it works without the routing.
I think this part of code make changes to the context.
Page page = BuildManager.CreateInstanceFromVirtualPath(
m_VirtualPath,
typeof(Page)) as Page;// IHttpHandler;
Also this part of code is useless:
if (page != null)
{
return page;
}
return page;
It will always return the page wither it's null or not.
I was missing a reference to System.web.mvc dll in the session adapter, and adding the same fixed the issue.
Hopefully it will help someone else going through same scenario.
a better solution is
runAllManagedModulesForAllRequest is a clever thing to do respect removing and resinserting session module.
alk.

Categories