ASP.NET response.redirect with IIS7 - asp.net

I have a site that is up and running on IIS6 in Windows 2003, and a development environment in XP. Everything works just fine.
I have been forced to create a new development environment in Windows 7.
Since using this, I have found that Reponse.Redirect no longer works... in some situations!
I have the following code:
Response.Redirect(Globals.NavigateURL( PortalSettings.ActiveTab.TabID ));
It works fine on IIS6.
It also works fine in most of the site on IIS7.5. However in some pages, it's not.
I have looked at the returning header, and can see there is a GET response in the Request header, which is for the correct page it should redirect too, but it's not!
There is an RadAjaxPanel around the buttons used to fire this redirect, but in a parent control. The buttons not working are in a separate ascx control.
I have the following in my Web.Config that I've found from other similar posts:
<system.webServer>
<modules>
<add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
And
<httpModules>
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
(both have ending tags)
But this hasn't helped.
Can anyone think of anything to try to get these working?

Have you tried
Response.Redirect(Globals.NavigateURL( PortalSettings.ActiveTab.TabID ), false);

This is not the perfect solution but a workaround -
private void Redirect(string url)
{
// Define the name and type of the client script on the page.
String csName = "RedirectScript";
Type csType = this.GetType();
// Get a ClientScriptManager reference from the Page class.
ClientScriptManager cs = Page.ClientScript;
// Check to see if the client script is already registered.
if (!cs.IsClientScriptBlockRegistered(csType, csName))
{
StringBuilder csText = new StringBuilder();
csText.Append("<script type=\"text/javascript\"> ");
csText.Append("window.location.href = {0} </", url);
csText.Append("script>");
cs.RegisterClientScriptBlock(csType, csName, csText.ToString());
}
}
Call from a page -
Redirect(Globals.NavigateURL( PortalSettings.ActiveTab.TabID ));
This will use JavaScript to let your page redirect.
You can move above method in a common utility class.

Related

How does WIF (WSFederationAuthentication) know which user I am?

I've been put in charge of figuring out a way to allow users to authenticate into our forms based site. Our corporate IT has set up a development adfs server, and the relying party trust has been set up to one of our dev environments.
I've been reading and looking for tutorials for about two weeks, so I'm by no means an expert, and I can't seem to understand how the STS (our ADFS server) is supposed to figure out which user is requesting authentication.
I've been following Wiktor Zychla's blog because it actually includes code examples and messes less with the web.config as opposed to most other tutorials. (http://www.wiktorzychla.com/2014/11/simplest-saml11-federated-authentication.html)
Here's the pipeline so far as I can see it.
User comes to the log in page.
Page_Load automatically redirects user to ADFS
User gets authenticated and redirected back to the log in page
In the Page_Load I then consume some token and use that to authorize
the user.
Redirect the user to a page that requires authentication.
Code and Web.config changes I've made to the site:
protected void Page_Load(object sender, System.EventArgs e)
{
var sam = FederatedAuthentication.SessionAuthenticationModule;
var fam = new WSFederationAuthenticationModule();
fam.FederationConfiguration = FederatedAuthentication.FederationConfiguration;
var request = new HttpContextWrapper(this.Context).Request;
if (UseADFS)
{
// is this the response from the STS
if (!fam.IsSignInResponse(request))
{
// no
// the STS
fam.Issuer = WsFederationIssuerName;
// the return address
fam.Realm = WsRealm;
fam.Reply = WsReply;
var req = fam.CreateSignInRequest(string.Empty, null, false);
// go to STS
Response.Redirect(req.WriteQueryString());
}
// is this the response from the STS
else
{
// yes, get the SAML token
var securityToken = fam.GetSecurityToken(request);
var config = new SecurityTokenHandlerConfiguration
{
CertificateValidator = X509CertificateValidator.None,
IssuerNameRegistry = new CustomIssuerNameRegistry()
};
config.AudienceRestriction.AudienceMode = AudienceUriMode.Never;
var tokenHandler = new SamlSecurityTokenHandler
{
CertificateValidator = X509CertificateValidator.None,
Configuration = config
};
// validate the token and get the ClaimsIdentity out of it
var identity = tokenHandler.ValidateToken(securityToken);
var principal = new ClaimsPrincipal(identity);
var token = sam.CreateSessionSecurityToken(principal, string.Empty,
DateTime.Now.ToUniversalTime(), DateTime.Now.AddMinutes(20).ToUniversalTime(), false);
sam.WriteSessionTokenToCookie(token);
if (identity[0].IsAuthenticated)
{
//string email = principal.Claims.Where(x => x.Type == ClaimTypes.Email).Select(x => x.Value).SingleOrDefault();
string name = principal.Claims.Where(x => x.Type == ClaimTypes.Name).Select(x => x.Value).SingleOrDefault();
CustomClaimsObject claim = new CustomClaimsObject(name, principal);
doSigninWork(true, claim);
}
}
}
else if (!this.IsPostBack && !fam.IsSignInResponse(request))
{
Session.Abandon();
}
}
<configSections>
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</configSections>
<httpModules>
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler"/>
</httpModules>
<modules>
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler"/>
</modules>
<system.identityModel>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandler requireSsl="false" />
</federationConfiguration>
</system.identityModel.services>
<authentication mode="Forms">
<forms loginUrl="Public/invalidlogin.aspx?err=sessiontimeout" protection="All" requireSSL="false" slidingExpiration="true"/>
</authentication>
How is the STS supposed to figure out who is requesting authentication? I'm not posting any relevant user info to it. Am I supposed to add something to my request? Or is the context somehow supposed to have relevant data? Or does the ADFS box need to have a log in where the user enters their credentials?
Right now when I navigate to the user to (by way of the button click) https://xxx-xxx.xxxxx.xxxxxx.com/adfs/ls/ I get this error.
Encountered error during federation passive request.
Additional Data
Protocol Name:
wsfed
Relying Party:
Exception details:
Microsoft.IdentityServer.Web.CookieManagers.InvalidContextException: MSIS7001: The passive protocol context was not found or not valid. If the context was stored in cookies, the cookies that were presented by the client were not valid. Ensure that the client browser is configured to accept cookies from this website and retry this request.
at Microsoft.IdentityServer.Web.Protocols.GenericProtocolRequest.ParseEncodedRequestParts(String[] encodedRequestParts)
at Microsoft.IdentityServer.Web.Protocols.GenericProtocolRequest..ctor(String encodedGenericRequest)
at Microsoft.IdentityServer.Web.Protocols.WSFederation.WSFederationProtocolHandler.GetOriginalRequestFromResponse(ProtocolContext context)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.ProcessProtocolRequest(ProtocolContext protocolContext, PassiveProtocolHandler protocolHandler)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.OnGetContext(WrappedHttpListenerContext context)
Can someone kick me in the right direction? I'm sure I'm missing something obvious to anyone with experience.
Update:
Login with adfs working. But now I'm struggling a bit with the logout.
My logout code is below. Essentially whats happening is the authentication on my claims identity is still true even after I've attempted to "logout" with the code below. The only claim I'm sending from ADFS to my relying party is en E-mail claim. Not sure if that makes a difference.
WSFederationAuthenticationModule authModule = FederatedAuthentication.WSFederationAuthenticationModule;
string signoutUrl = (WSFederationAuthenticationModule.GetFederationPassiveSignOutUrl(WsFederationIssuerName, eURL.BuildURL(), null));
WSFederationAuthenticationModule.FederatedSignOut(new Uri(signoutUrl), null);
Update 2:
So I've realized the sign out is working correctly. However it seems ADFS is redirecting to my sign in page before it redirects to my log out page. This is causing the Sign in code to be run again which fires another claim to ADFS. Is there a way to stop this? Or a way to know if I'm coming from the adfs logout?
Update 3:
Solved the issue by wrapping an if statement around the if(UseADFS) clause to check to see where I'm coming from.
if(request.UrlReferrer.Authority.Contains(authority))
I just check to see if the place I'm coming from is my server (your adfs domain) vs (your website domain). This together with a parameter placed in my redirect url was enough to decipher whether the user was logging out or logging in.

Configure an OWIN static file server at a specific route prefix

I'm experimenting with keeping my content in non-default locations (eg in bower_components or /packages/../tools). As part of the experiment I am trying to set up an asp.net mvc 5 application where hitting a certain route allows me to browse files in the undersorejs package directory.
I have the following nuget packages (in addition to the default)
Install-Package underscore.js
Install-Package Microsoft.Owin.StaticFiles
Install-Package Microsoft.Owin.Host.SystemWeb
This is what I have in an OWIN startup class
var fileSystem = new PhysicalFileSystem(
HttpContext.Current.Server.MapPath("~")+"/../packages/underscore.js.1.6.0"
);
var options = new FileServerOptions {EnableDirectoryBrowsing = true, FileSystem = fileSystem};
app.MapWhen(ctx =>
ctx.Request.Uri.AbsolutePath.StartsWith("/__underscore"),
ab => ab.UseFileServer(options)
);
To my understanding and previous experimentation this is pretty straightforward - when the request begins with /__underscore use the simple static file server. However when I head over to /__underscore I get a 404 error.
However, placing breakpoints I can see that the UseFileServer lambda executes once on startup and then never again, while the predicate lambda is called on every request (and returns the correct value).
What am I missing?
You need to specify the RequestPath as well:
var options = new FileServerOptions {
EnableDirectoryBrowsing = true,
FileSystem = fileSystem,
RequestPath = PathString.FromUriComponent("/__underscore")
};
As per your comment:
If you're unable to download files, try to explicitly register OwinHttpHandler in your Web.Config:
<system.webServer>
<handlers>
<add name="Owin" verb="" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb"/>
</handlers>
</system.webServer>
Alternatively, you can set runAllManagedModulesForAllRequests to 'true':
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="FormsAuthenticationModule" />
</modules>
</system.webServer>

How can I use HttpClient in my .NET Framework 4.5 app/site?

Based on the answer here: How can I retrieve and parse just the html returned from an URL?
...I'm trying to begin by adding code based on that found here: http://msdn.microsoft.com/en-us/library/system.net.http.httpclient.aspx
...namely by adding this to \App_Code\Functions.cshtml:
#functions
{
public static string GetUrlHtml(string dynamicUrl)
{
HttpClient client = new HttpClient();
string body = await client.GetStringAsync(dynamicUrl);
// parse it using HTML Agility Pack? (http://htmlagilitypack.codeplex.com/)
}
}
HttpClient is not recognized, and does not afford a "resolve" context menu item. Intellisense does not offer me a "Http" after entering:
#using System.Net.
Is HttpClient really unavailable to me? If so, what can I have as a consolation prize? Is my best option to use WebClient like so:
WebClient wc = new WebClient();
string body = wc.DownloadString(dynamicUrl);
// parse it with html agility pack
...or, as shown at https://web.archive.org/web/20211020001935/https://www.4guysfromrolla.com/articles/011211-1.aspx#postadlink, I can use the webGet class from the HTML Agility Pack:
var webGet = new HtmlWeb();
var document = webGet.Load(dynamicUrl);
Does anybody have any supportable opinions on which option is the best?
Wrong answer is the accepted one.
This is the correct one:
Add to the config
<system.web>
<compilation>
<assemblies>
<add assembly="System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</assemblies>
</compilation>
</system.web>
Please make sure you have an assembly reference to System.Net.Http.
Install this nuget package and it will add the appropriate references http://nuget.org/packages/Microsoft.Net.Http/2.0.20710.0

Block IP Addresses In HttpModule

I have taken over a domain that had was running an old version of Community Server. Needless to say the bots are spamming me trying to find holes.
I'd like to block entire IP blocks before System.Web.HttpRequest.ValidateInputIfRequiredByConfig() is fired. I have a IHttpModule that I have tried but I assume it's getting called after because HealthMonitoring is catching the Exceptions. Here is the module:
public class IpBlockerModule : IHttpModule
{
private static readonly string[] Hacks = new[]
{
"60.169.73.",
"60.169.75.",
"61.160.232.",
"61.160.207.",
"92.85.161."
};
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += (Application_BeginRequest);
}
private void Application_BeginRequest(object source, EventArgs e)
{
var context = ((HttpApplication) source).Context;
var ipAddress = context.Request.UserHostAddress;
if (!IsHackIpAddress(ipAddress))
{
context.Response.StatusCode = 403; // (Forbidden)
}
}
private static bool IsHackIpAddress(string ip)
{
if (ip == null) return true;
return Hacks.Any(x => x.StartsWith(ip));
}
}
And the relevent web.config sections:
<system.web>
<httpModules>
<add name="IpBlockerModule" type="MyNameSpace.IpBlockerModule" />
</httpModules>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true" >
<add name="IpBlockerModule" type="MyNameSpace.IpBlockerModule" preCondition="" />
</modules>
</system.webServer>
The reasoning behind this is my inbox is getting spammed from all the
A potentially dangerous Request.Path value was detected from the
client
and
A potentially dangerous Request.Form value was detected from the client
notifications. Is something wrong with my Module, or am I correct in assuming modules don't get fired until after the fact?
As an alternative solution have you considered letting IIS do the work for you? This way the request never makes it to your application. You can do this via the web.config and there's an article detailing the process located here. The following example is copied directly from that article and would be placed inside the <system.webServer> section of your web.config:
<security>
<ipSecurity allowUnlisted="true"> <!-- this line allows everybody, except those listed below -->
<clear/> <!-- removes all upstream restrictions -->
<add ipAddress="83.116.19.53"/> <!-- blocks the specific IP of 83.116.19.53 -->
<add ipAddress="83.116.119.0" subnetMask="255.255.255.0"/> <!--blocks network 83.116.119.0 to 83.116.119.255-->
<add ipAddress="83.116.0.0" subnetMask="255.255.0.0"/> <!--blocks network 83.116.0.0 to 83.116.255.255-->
<add ipAddress="83.0.0.0" subnetMask="255.0.0.0"/> <!--blocks entire /8 network of 83.0.0.0 to 83.255.255.255-->
</ipSecurity>
</security>
You can also add the ability to get and log IP addresses so as to identify and block only the spammy ones.
Here's C# code to get IP addresses
string ipadd;
ipadd = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (ipadd == "" || ipaddress == null)
ipadd = Request.ServerVariables["REMOTE_ADDR"];
I noticed that the link in the answer above is dead, so use this well-detailed article here

How do I found the routing http modules loaded?

I am using the traditional Asp.Net website in which I am using the System.Web.Routing module. I want to find the way in which I know that the routing http modules is loaded or not?
All you need to know is the module's name as you have it configured in your web.config file
for example mine is named: "UrlRoutingModule" as you can see from this snippet here (formatted for StackOverflow):
<add name="UrlRoutingModule"
type="System.Web.Routing.UrlRoutingModule, System.Web.Routing,
Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
once you have that, all you need to do is check the application's Modules property (which is of type HttpModuleCollection for your module's name and verify that it's not null. If you want to do some extra checking you can check the type of the object too (not shown).
// From Global.asax.cs
protected void Application_Start(object sender, EventArgs e)
{
if (Modules.AllKeys.Contains("UrlRoutingModules")
&& Modules["UrlRoutingModule"] != null)
{
// the module is loaded
}
}

Resources