2013-08-12 15:06:12 +02:00
|
|
|
|
using System;
|
2015-02-06 13:47:00 +11:00
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Collections.Specialized;
|
2015-11-19 18:12:21 +01:00
|
|
|
|
using System.ComponentModel;
|
2015-02-06 13:47:00 +11:00
|
|
|
|
using System.Linq;
|
2013-12-02 17:20:50 +11:00
|
|
|
|
using System.Net.Http;
|
|
|
|
|
|
using System.Net.Http.Headers;
|
2015-04-10 14:22:09 +10:00
|
|
|
|
using System.Security.Claims;
|
2013-11-01 15:37:59 +11:00
|
|
|
|
using System.Security.Principal;
|
|
|
|
|
|
using System.Threading;
|
2013-08-12 15:06:12 +02:00
|
|
|
|
using System.Web;
|
|
|
|
|
|
using System.Web.Security;
|
2015-03-24 20:17:37 +11:00
|
|
|
|
using AutoMapper;
|
2015-02-06 13:47:00 +11:00
|
|
|
|
using Microsoft.Owin;
|
2013-08-12 15:06:12 +02:00
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
using Umbraco.Core.Configuration;
|
2015-03-24 20:17:37 +11:00
|
|
|
|
using Umbraco.Core.Models.Membership;
|
2015-04-15 17:03:12 +10:00
|
|
|
|
using Umbraco.Core.Logging;
|
2013-08-12 15:06:12 +02:00
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Core.Security
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Extensions to create and renew and remove authentication tickets for the Umbraco back office
|
|
|
|
|
|
/// </summary>
|
2014-05-06 18:15:38 +10:00
|
|
|
|
public static class AuthenticationExtensions
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// This will check the ticket to see if it is valid, if it is it will set the current thread's user and culture
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http"></param>
|
|
|
|
|
|
/// <param name="ticket"></param>
|
|
|
|
|
|
/// <param name="renewTicket">If true will attempt to renew the ticket</param>
|
|
|
|
|
|
public static bool AuthenticateCurrentRequest(this HttpContextBase http, FormsAuthenticationTicket ticket, bool renewTicket)
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
|
|
|
|
|
|
|
|
|
|
|
//if there was a ticket, it's not expired, - it should not be renewed or its renewable
|
|
|
|
|
|
if (ticket != null && ticket.Expired == false && (renewTicket == false || http.RenewUmbracoAuthTicket()))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
//create the Umbraco user identity
|
|
|
|
|
|
var identity = new UmbracoBackOfficeIdentity(ticket);
|
|
|
|
|
|
|
|
|
|
|
|
//set the principal object
|
|
|
|
|
|
var principal = new GenericPrincipal(identity, identity.Roles);
|
|
|
|
|
|
|
|
|
|
|
|
//It is actually not good enough to set this on the current app Context and the thread, it also needs
|
|
|
|
|
|
// to be set explicitly on the HttpContext.Current !! This is a strange web api thing that is actually
|
|
|
|
|
|
// an underlying fault of asp.net not propogating the User correctly.
|
|
|
|
|
|
if (HttpContext.Current != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
HttpContext.Current.User = principal;
|
|
|
|
|
|
}
|
|
|
|
|
|
http.User = principal;
|
|
|
|
|
|
Thread.CurrentPrincipal = principal;
|
|
|
|
|
|
|
|
|
|
|
|
//This is a back office request, we will also set the culture/ui culture
|
|
|
|
|
|
Thread.CurrentThread.CurrentCulture =
|
|
|
|
|
|
Thread.CurrentThread.CurrentUICulture =
|
|
|
|
|
|
new System.Globalization.CultureInfo(identity.Culture);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ex is FormatException || ex is JsonReaderException)
|
|
|
|
|
|
{
|
|
|
|
|
|
//this will occur if the cookie data is invalid
|
|
|
|
|
|
http.UmbracoLogout();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-11-01 15:37:59 +11:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// This will return the current back office identity.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http"></param>
|
2014-12-05 10:29:18 +11:00
|
|
|
|
/// <param name="authenticateRequestIfNotFound">
|
2013-11-01 15:37:59 +11:00
|
|
|
|
/// If set to true and a back office identity is not found and not authenticated, this will attempt to authenticate the
|
2015-01-12 21:45:52 +11:00
|
|
|
|
/// request just as is done in the Umbraco module and then set the current identity if it is valid.
|
|
|
|
|
|
/// Just like in the UmbracoModule, if this is true then the user's culture will be assigned to the request.
|
2013-11-01 15:37:59 +11:00
|
|
|
|
/// </param>
|
|
|
|
|
|
/// <returns>
|
|
|
|
|
|
/// Returns the current back office identity if an admin is authenticated otherwise null
|
|
|
|
|
|
/// </returns>
|
|
|
|
|
|
public static UmbracoBackOfficeIdentity GetCurrentIdentity(this HttpContextBase http, bool authenticateRequestIfNotFound)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
2014-05-12 14:32:34 +10:00
|
|
|
|
if (http.User == null) return null; //there's no user at all so no identity
|
2015-04-10 14:22:09 +10:00
|
|
|
|
|
|
|
|
|
|
//If it's already a UmbracoBackOfficeIdentity
|
|
|
|
|
|
var backOfficeIdentity = http.User.Identity as UmbracoBackOfficeIdentity;
|
|
|
|
|
|
if (backOfficeIdentity != null) return backOfficeIdentity;
|
|
|
|
|
|
|
2016-03-09 17:35:50 +01:00
|
|
|
|
//Check if there's more than one identity assigned and see if it's a UmbracoBackOfficeIdentity and use that
|
|
|
|
|
|
var claimsPrincipal = http.User as ClaimsPrincipal;
|
|
|
|
|
|
if (claimsPrincipal != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
backOfficeIdentity = claimsPrincipal.Identities.OfType<UmbracoBackOfficeIdentity>().FirstOrDefault();
|
|
|
|
|
|
if (backOfficeIdentity != null) return backOfficeIdentity;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-04-15 17:03:12 +10:00
|
|
|
|
//Otherwise convert to a UmbracoBackOfficeIdentity if it's auth'd and has the back office session
|
2015-04-10 14:22:09 +10:00
|
|
|
|
var claimsIdentity = http.User.Identity as ClaimsIdentity;
|
2015-04-15 17:03:12 +10:00
|
|
|
|
if (claimsIdentity != null && claimsIdentity.IsAuthenticated)
|
2016-03-09 17:35:50 +01:00
|
|
|
|
{
|
2015-04-15 17:03:12 +10:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
return UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (InvalidOperationException ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
//This will occur if the required claim types are missing which would mean something strange is going on
|
|
|
|
|
|
LogHelper.Error(typeof(AuthenticationExtensions), "The current identity cannot be converted to " + typeof(UmbracoBackOfficeIdentity), ex);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2014-12-05 10:29:18 +11:00
|
|
|
|
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (authenticateRequestIfNotFound == false) return null;
|
2014-12-05 10:29:18 +11:00
|
|
|
|
|
2013-11-01 15:37:59 +11:00
|
|
|
|
//even if authenticateRequestIfNotFound is true we cannot continue if the request is actually authenticated
|
|
|
|
|
|
// which would mean something strange is going on that it is not an umbraco identity.
|
|
|
|
|
|
if (http.User.Identity.IsAuthenticated) return null;
|
2014-12-05 10:29:18 +11:00
|
|
|
|
|
|
|
|
|
|
//So the user is not authed but we've been asked to do the auth if authenticateRequestIfNotFound = true,
|
|
|
|
|
|
// which might occur in old webforms style things or for routes that aren't included as a back office request.
|
|
|
|
|
|
// in this case, we are just reverting to authing using the cookie.
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: Even though this is in theory legacy, we have legacy bits laying around and we'd need to do the auth based on
|
|
|
|
|
|
// how the Module will eventually do it (by calling in to any registered authenticators).
|
2013-11-01 15:37:59 +11:00
|
|
|
|
|
|
|
|
|
|
var ticket = http.GetUmbracoAuthTicket();
|
|
|
|
|
|
if (http.AuthenticateCurrentRequest(ticket, true))
|
|
|
|
|
|
{
|
|
|
|
|
|
//now we 'should have an umbraco identity
|
|
|
|
|
|
return http.User.Identity as UmbracoBackOfficeIdentity;
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// This will return the current back office identity.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http"></param>
|
|
|
|
|
|
/// <param name="authenticateRequestIfNotFound">
|
|
|
|
|
|
/// If set to true and a back office identity is not found and not authenticated, this will attempt to authenticate the
|
|
|
|
|
|
/// request just as is done in the Umbraco module and then set the current identity if it is valid
|
|
|
|
|
|
/// </param>
|
|
|
|
|
|
/// <returns>
|
|
|
|
|
|
/// Returns the current back office identity if an admin is authenticated otherwise null
|
|
|
|
|
|
/// </returns>
|
|
|
|
|
|
internal static UmbracoBackOfficeIdentity GetCurrentIdentity(this HttpContext http, bool authenticateRequestIfNotFound)
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
|
|
|
|
|
return new HttpContextWrapper(http).GetCurrentIdentity(authenticateRequestIfNotFound);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void UmbracoLogout(this HttpContextBase http)
|
|
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
2013-09-25 19:23:41 +10:00
|
|
|
|
Logout(http, UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-12-02 17:20:50 +11:00
|
|
|
|
/// <summary>
|
2014-05-06 18:15:38 +10:00
|
|
|
|
/// This clears the forms authentication cookie for webapi since cookies are handled differently
|
2013-12-02 17:20:50 +11:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="response"></param>
|
2016-02-03 10:14:53 +01:00
|
|
|
|
[Obsolete("Use OWIN IAuthenticationManager.SignOut instead", true)]
|
2015-11-19 18:12:21 +01:00
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
2014-05-06 18:15:38 +10:00
|
|
|
|
public static void UmbracoLogoutWebApi(this HttpResponseMessage response)
|
2013-12-02 17:20:50 +11:00
|
|
|
|
{
|
2016-02-03 10:14:53 +01:00
|
|
|
|
throw new NotSupportedException("This method is not supported and should not be used, it has been removed in Umbraco 7.4");
|
2015-03-24 20:17:37 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-02-03 10:14:53 +01:00
|
|
|
|
[Obsolete("Use WebSecurity.SetPrincipalForRequest", true)]
|
2015-11-19 18:12:21 +01:00
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
2015-03-24 20:17:37 +11:00
|
|
|
|
public static FormsAuthenticationTicket UmbracoLoginWebApi(this HttpResponseMessage response, IUser user)
|
|
|
|
|
|
{
|
2016-02-03 10:14:53 +01:00
|
|
|
|
throw new NotSupportedException("This method is not supported and should not be used, it has been removed in Umbraco 7.4");
|
2013-12-02 17:20:50 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// This clears the forms authentication cookie
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http"></param>
|
2013-08-12 15:06:12 +02:00
|
|
|
|
internal static void UmbracoLogout(this HttpContext http)
|
|
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
2013-08-12 15:06:12 +02:00
|
|
|
|
new HttpContextWrapper(http).UmbracoLogout();
|
|
|
|
|
|
}
|
2015-11-19 18:12:21 +01:00
|
|
|
|
|
2013-08-12 15:06:12 +02:00
|
|
|
|
/// <summary>
|
2015-11-19 18:12:21 +01:00
|
|
|
|
/// This will force ticket renewal in the OWIN pipeline
|
2013-08-12 15:06:12 +02:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2013-10-15 18:46:44 +11:00
|
|
|
|
public static bool RenewUmbracoAuthTicket(this HttpContextBase http)
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
2015-11-19 18:12:21 +01:00
|
|
|
|
http.Items["umbraco-force-auth"] = true;
|
|
|
|
|
|
return true;
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-19 18:12:21 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// This will force ticket renewal in the OWIN pipeline
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2013-10-15 18:46:44 +11:00
|
|
|
|
internal static bool RenewUmbracoAuthTicket(this HttpContext http)
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
2015-11-19 18:12:21 +01:00
|
|
|
|
http.Items["umbraco-force-auth"] = true;
|
|
|
|
|
|
return true;
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Creates the umbraco authentication ticket
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http"></param>
|
|
|
|
|
|
/// <param name="userdata"></param>
|
2013-10-16 12:00:42 +11:00
|
|
|
|
public static FormsAuthenticationTicket CreateUmbracoAuthTicket(this HttpContextBase http, UserData userdata)
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
|
|
|
|
|
if (userdata == null) throw new ArgumentNullException("userdata");
|
2013-08-12 15:06:12 +02:00
|
|
|
|
var userDataString = JsonConvert.SerializeObject(userdata);
|
2013-10-16 12:00:42 +11:00
|
|
|
|
return CreateAuthTicketAndCookie(
|
2013-08-12 15:06:12 +02:00
|
|
|
|
http,
|
|
|
|
|
|
userdata.Username,
|
|
|
|
|
|
userDataString,
|
2013-10-15 18:46:44 +11:00
|
|
|
|
//use the configuration timeout - this is the same timeout that will be used when renewing the ticket.
|
2013-08-12 15:06:12 +02:00
|
|
|
|
GlobalSettings.TimeOutInMinutes,
|
|
|
|
|
|
//Umbraco has always persisted it's original cookie for 1 day so we'll keep it that way
|
|
|
|
|
|
1440,
|
2013-09-25 19:23:41 +10:00
|
|
|
|
UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName,
|
|
|
|
|
|
UmbracoConfig.For.UmbracoSettings().Security.AuthCookieDomain);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-10-16 12:00:42 +11:00
|
|
|
|
internal static FormsAuthenticationTicket CreateUmbracoAuthTicket(this HttpContext http, UserData userdata)
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
|
|
|
|
|
if (userdata == null) throw new ArgumentNullException("userdata");
|
2013-10-16 12:00:42 +11:00
|
|
|
|
return new HttpContextWrapper(http).CreateUmbracoAuthTicket(userdata);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-10-15 18:46:44 +11:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// returns the number of seconds the user has until their auth session times out
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static double GetRemainingAuthSeconds(this HttpContextBase http)
|
|
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
2013-10-15 18:46:44 +11:00
|
|
|
|
var ticket = http.GetUmbracoAuthTicket();
|
2013-10-16 12:00:42 +11:00
|
|
|
|
return ticket.GetRemainingAuthSeconds();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// returns the number of seconds the user has until their auth session times out
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="ticket"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static double GetRemainingAuthSeconds(this FormsAuthenticationTicket ticket)
|
|
|
|
|
|
{
|
2013-10-15 18:46:44 +11:00
|
|
|
|
if (ticket == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
var utcExpired = ticket.Expiration.ToUniversalTime();
|
|
|
|
|
|
var secondsRemaining = utcExpired.Subtract(DateTime.UtcNow).TotalSeconds;
|
|
|
|
|
|
return secondsRemaining;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-08-12 15:06:12 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the umbraco auth ticket
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static FormsAuthenticationTicket GetUmbracoAuthTicket(this HttpContextBase http)
|
|
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
2013-09-25 19:23:41 +10:00
|
|
|
|
return GetAuthTicket(http, UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal static FormsAuthenticationTicket GetUmbracoAuthTicket(this HttpContext http)
|
|
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
2013-08-12 15:06:12 +02:00
|
|
|
|
return new HttpContextWrapper(http).GetUmbracoAuthTicket();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-06 13:47:00 +11:00
|
|
|
|
internal static FormsAuthenticationTicket GetUmbracoAuthTicket(this IOwinContext ctx)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctx == null) throw new ArgumentNullException("ctx");
|
|
|
|
|
|
//get the ticket
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
return GetAuthTicket(ctx.Request.Cookies.ToDictionary(x => x.Key, x => x.Value), UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
//TODO: Do we need to do more here?? need to make sure that the forms cookie is gone, but is that
|
|
|
|
|
|
// taken care of in our custom middleware somehow?
|
2015-12-15 10:34:11 +01:00
|
|
|
|
ctx.Authentication.SignOut(
|
|
|
|
|
|
Core.Constants.Security.BackOfficeAuthenticationType,
|
|
|
|
|
|
Core.Constants.Security.BackOfficeExternalAuthenticationType);
|
2015-02-06 13:47:00 +11:00
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-08-12 15:06:12 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// This clears the forms authentication cookie
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http"></param>
|
|
|
|
|
|
/// <param name="cookieName"></param>
|
|
|
|
|
|
private static void Logout(this HttpContextBase http, string cookieName)
|
|
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
2015-03-24 20:17:37 +11:00
|
|
|
|
//clear the preview cookie and external login
|
2015-03-25 12:21:41 +11:00
|
|
|
|
var cookies = new[] { cookieName, Constants.Web.PreviewCookieName, Constants.Security.BackOfficeExternalCookieName };
|
2014-01-16 20:49:19 +11:00
|
|
|
|
foreach (var c in cookies)
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2014-01-16 20:49:19 +11:00
|
|
|
|
//remove from the request
|
|
|
|
|
|
http.Request.Cookies.Remove(c);
|
|
|
|
|
|
|
|
|
|
|
|
//expire from the response
|
|
|
|
|
|
var formsCookie = http.Response.Cookies[c];
|
|
|
|
|
|
if (formsCookie != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
//this will expire immediately and be removed from the browser
|
|
|
|
|
|
formsCookie.Expires = DateTime.Now.AddYears(-1);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
//ensure there's def an expired cookie
|
|
|
|
|
|
http.Response.Cookies.Add(new HttpCookie(c) { Expires = DateTime.Now.AddYears(-1) });
|
|
|
|
|
|
}
|
2015-11-19 18:12:21 +01:00
|
|
|
|
}
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static FormsAuthenticationTicket GetAuthTicket(this HttpContextBase http, string cookieName)
|
|
|
|
|
|
{
|
2015-02-09 12:14:59 +11:00
|
|
|
|
var asDictionary = new Dictionary<string, string>();
|
2015-02-06 13:47:00 +11:00
|
|
|
|
for (var i = 0; i < http.Request.Cookies.Keys.Count; i++)
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2015-02-09 12:14:59 +11:00
|
|
|
|
var key = http.Request.Cookies.Keys.Get(i);
|
|
|
|
|
|
asDictionary[key] = http.Request.Cookies[key].Value;
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
2015-02-06 13:47:00 +11:00
|
|
|
|
|
2013-08-12 15:06:12 +02:00
|
|
|
|
//get the ticket
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2015-02-06 13:47:00 +11:00
|
|
|
|
|
|
|
|
|
|
return GetAuthTicket(asDictionary, cookieName);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
//occurs when decryption fails
|
|
|
|
|
|
http.Logout(cookieName);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-06 13:47:00 +11:00
|
|
|
|
private static FormsAuthenticationTicket GetAuthTicket(IDictionary<string, string> cookies, string cookieName)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (cookies == null) throw new ArgumentNullException("cookies");
|
|
|
|
|
|
|
|
|
|
|
|
if (cookies.ContainsKey(cookieName) == false) return null;
|
|
|
|
|
|
|
|
|
|
|
|
var formsCookie = cookies[cookieName];
|
|
|
|
|
|
if (formsCookie == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
//get the ticket
|
|
|
|
|
|
return FormsAuthentication.Decrypt(formsCookie);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-08-12 15:06:12 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Creates a custom FormsAuthentication ticket with the data specified
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="http">The HTTP.</param>
|
|
|
|
|
|
/// <param name="username">The username.</param>
|
|
|
|
|
|
/// <param name="userData">The user data.</param>
|
|
|
|
|
|
/// <param name="loginTimeoutMins">The login timeout mins.</param>
|
|
|
|
|
|
/// <param name="minutesPersisted">The minutes persisted.</param>
|
|
|
|
|
|
/// <param name="cookieName">Name of the cookie.</param>
|
|
|
|
|
|
/// <param name="cookieDomain">The cookie domain.</param>
|
2013-10-16 12:00:42 +11:00
|
|
|
|
private static FormsAuthenticationTicket CreateAuthTicketAndCookie(this HttpContextBase http,
|
2013-08-12 15:06:12 +02:00
|
|
|
|
string username,
|
|
|
|
|
|
string userData,
|
|
|
|
|
|
int loginTimeoutMins,
|
|
|
|
|
|
int minutesPersisted,
|
|
|
|
|
|
string cookieName,
|
|
|
|
|
|
string cookieDomain)
|
|
|
|
|
|
{
|
2013-11-01 15:37:59 +11:00
|
|
|
|
if (http == null) throw new ArgumentNullException("http");
|
2013-08-12 15:06:12 +02:00
|
|
|
|
// Create a new ticket used for authentication
|
|
|
|
|
|
var ticket = new FormsAuthenticationTicket(
|
|
|
|
|
|
4,
|
|
|
|
|
|
username,
|
|
|
|
|
|
DateTime.Now,
|
|
|
|
|
|
DateTime.Now.AddMinutes(loginTimeoutMins),
|
|
|
|
|
|
true,
|
|
|
|
|
|
userData,
|
2015-02-09 17:37:21 +11:00
|
|
|
|
"/"
|
2013-08-12 15:06:12 +02:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// Encrypt the cookie using the machine key for secure transport
|
|
|
|
|
|
var hash = FormsAuthentication.Encrypt(ticket);
|
|
|
|
|
|
var cookie = new HttpCookie(
|
|
|
|
|
|
cookieName,
|
|
|
|
|
|
hash)
|
|
|
|
|
|
{
|
|
|
|
|
|
Expires = DateTime.Now.AddMinutes(minutesPersisted),
|
2015-02-06 14:05:29 +11:00
|
|
|
|
Domain = cookieDomain,
|
2015-02-09 17:37:21 +11:00
|
|
|
|
Path = "/"
|
2013-08-12 15:06:12 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (GlobalSettings.UseSSL)
|
|
|
|
|
|
cookie.Secure = true;
|
|
|
|
|
|
|
|
|
|
|
|
//ensure http only, this should only be able to be accessed via the server
|
|
|
|
|
|
cookie.HttpOnly = true;
|
|
|
|
|
|
|
|
|
|
|
|
http.Response.Cookies.Set(cookie);
|
2013-10-16 12:00:42 +11:00
|
|
|
|
|
|
|
|
|
|
return ticket;
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2013-07-31 17:08:56 +10:00
|
|
|
|
}
|