websitepanel/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/SecureSessionModule.cs
omara 127a7fc1dd Update Copyright information on updated files
Change Copyright date on footer
2012-07-04 08:37:14 -04:00

181 lines
No EOL
6.9 KiB
C#

// Copyright (c) 2012, Outercurve Foundation.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// - Neither the name of the Outercurve Foundation nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Web;
using System.Web.Security;
using System.Web.Caching;
using System.Configuration;
using System.Security.Cryptography;
using System.Runtime.Serialization;
using System.Globalization;
using System.Text;
using Microsoft.Security.Application;
namespace WebsitePanel.WebPortal
{
public class SecureSessionModule : IHttpModule
{
public const string DEFAULT_PAGE = "~/Default.aspx";
public const string PAGE_ID_PARAM = "pid";
private static string _ValidationKey = null;
public void Init(HttpApplication app)
{
// Initialize validation key if not already initialized
if (_ValidationKey == null)
_ValidationKey = GetValidationKey();
// Register handlers for BeginRequest and EndRequest events
app.BeginRequest += new EventHandler(OnBeginRequest);
app.EndRequest += new EventHandler(OnEndRequest);
}
public void Dispose() { }
void OnBeginRequest(Object sender, EventArgs e)
{
// Look for an incoming cookie named "ASP.NET_SessionID"
HttpRequest request = ((HttpApplication)sender).Request;
HttpCookie cookie = GetCookie(request, "ASP.NET_SessionId");
if (cookie != null)
{
// Throw an exception if the cookie lacks a MAC
if (cookie.Value.Length <= 24)
{
FormsAuthentication.SignOut();
HttpContext.Current.Response.Redirect(DefaultPage.GetPageUrl(PortalConfiguration.SiteSettings["DefaultPage"]));
}
// Separate the session ID and the MAC
string id = cookie.Value.Substring(0, 24);
string mac1 = cookie.Value.Substring(24);
// Generate a new MAC from the session ID and requestor info
string mac2 = GetSessionIDMac(id, request.UserHostAddress,
request.UserAgent, _ValidationKey);
// Throw an exception if the MACs don't match
if (String.CompareOrdinal(mac1, mac2) != 0)
{
FormsAuthentication.SignOut();
HttpContext.Current.Response.Redirect(DefaultPage.GetPageUrl(PortalConfiguration.SiteSettings["DefaultPage"]));
}
// Strip the MAC from the cookie before ASP.NET sees it
cookie.Value = id;
}
}
void OnEndRequest(Object sender, EventArgs e)
{
// Look for an outgoing cookie named "ASP.NET_SessionID"
HttpRequest request = ((HttpApplication)sender).Request;
HttpCookie cookie = GetCookie( request, "ASP.NET_SessionId");
if (cookie != null)
{
// Add a MAC
cookie.Value += GetSessionIDMac(cookie.Value,
request.UserHostAddress, request.UserAgent,
_ValidationKey);
}
}
private string GetValidationKey()
{
string key = ConfigurationManager.AppSettings["SessionValidationKey"];
if (key == null || key == String.Empty)
throw new InvalidSessionException
("SessionValidationKey missing");
return key;
}
private HttpCookie GetCookie(HttpRequest request, string name)
{
HttpCookieCollection cookies = request.Cookies;
return FindCookie(cookies, name);
}
private HttpCookie GetCookie(HttpResponse response, string name)
{
HttpCookieCollection cookies = response.Cookies;
return FindCookie(cookies, name);
}
private HttpCookie FindCookie(HttpCookieCollection cookies,
string name)
{
int count = cookies.Count;
for (int i = 0; i < count; i++)
{
if (String.Compare(cookies[i].Name, name, true,
CultureInfo.InvariantCulture) == 0)
return cookies[i];
}
return null;
}
private string GetSessionIDMac(string id, string ip,
string agent, string key)
{
StringBuilder builder = new StringBuilder(id, 512);
builder.Append(ip);
builder.Append(agent);
using (HMACSHA1 hmac = new HMACSHA1
(Encoding.UTF8.GetBytes(key)))
{
return Convert.ToBase64String(hmac.ComputeHash
(Encoding.UTF8.GetBytes(builder.ToString())));
}
}
}
[Serializable]
public class InvalidSessionException : Exception
{
public InvalidSessionException() :
base("Session cookie is invalid") { }
public InvalidSessionException(string message) :
base(message) { }
public InvalidSessionException(string message,
Exception inner)
: base(message, inner) { }
protected InvalidSessionException(SerializationInfo info,
StreamingContext context)
: base(info, context) { }
}
}