diff --git a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs
index 3ba5b4259a..5060cb5912 100644
--- a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs
+++ b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs
@@ -11,9 +11,9 @@ namespace Umbraco.Core.Models.Identity
/// Gets/sets the user's real name
///
public string Name { get; set; }
- public int StartContentNode { get; set; }
- public int StartMediaNode { get; set; }
- public string[] AllowedApplications { get; set; }
+ public int StartContentId { get; set; }
+ public int StartMediaId { get; set; }
+ public string[] AllowedSections { get; set; }
public string Culture { get; set; }
public string UserTypeAlias { get; set; }
diff --git a/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs b/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs
index 8fa2703f39..def71a8982 100644
--- a/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs
+++ b/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs
@@ -18,12 +18,12 @@ namespace Umbraco.Core.Models.Identity
.ForMember(user => user.LockoutEndDateUtc, expression => expression.UseValue(DateTime.MaxValue.ToUniversalTime()))
.ForMember(user => user.UserName, expression => expression.MapFrom(user => user.Username))
.ForMember(user => user.PasswordHash, expression => expression.MapFrom(user => GetPasswordHash(user.RawPasswordValue)))
- .ForMember(user => user.Culture, expression => expression.MapFrom(user => user.Language))
+ .ForMember(user => user.Culture, expression => expression.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
.ForMember(user => user.Name, expression => expression.MapFrom(user => user.Name))
- .ForMember(user => user.StartMediaNode, expression => expression.MapFrom(user => user.StartMediaId))
- .ForMember(user => user.StartContentNode, expression => expression.MapFrom(user => user.StartContentId))
+ .ForMember(user => user.StartMediaId, expression => expression.MapFrom(user => user.StartMediaId))
+ .ForMember(user => user.StartContentId, expression => expression.MapFrom(user => user.StartContentId))
.ForMember(user => user.UserTypeAlias, expression => expression.MapFrom(user => user.UserType.Alias))
- .ForMember(user => user.AllowedApplications, expression => expression.MapFrom(user => user.AllowedSections.ToArray()));
+ .ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()));
}
private string GetPasswordHash(string storedPass)
diff --git a/src/Umbraco.Core/Security/AuthenticationExtensions.cs b/src/Umbraco.Core/Security/AuthenticationExtensions.cs
index e71dd0e00c..ca597a8fef 100644
--- a/src/Umbraco.Core/Security/AuthenticationExtensions.cs
+++ b/src/Umbraco.Core/Security/AuthenticationExtensions.cs
@@ -9,9 +9,11 @@ using System.Security.Principal;
using System.Threading;
using System.Web;
using System.Web.Security;
+using AutoMapper;
using Microsoft.Owin;
using Newtonsoft.Json;
using Umbraco.Core.Configuration;
+using Umbraco.Core.Models.Membership;
namespace Umbraco.Core.Security
{
@@ -163,8 +165,60 @@ namespace Umbraco.Core.Security
Expires = DateTime.Now.AddYears(-1),
Path = "/"
};
+ //remove the external login cookie too
+ var extLoginCookie = new CookieHeaderValue(Constants.Security.BackOfficeExternalAuthenticationType, "")
+ {
+ Expires = DateTime.Now.AddYears(-1),
+ Path = "/"
+ };
- response.Headers.AddCookies(new[] { authCookie, prevCookie });
+ response.Headers.AddCookies(new[] { authCookie, prevCookie, extLoginCookie });
+ }
+
+ ///
+ /// This adds the forms authentication cookie for webapi since cookies are handled differently
+ ///
+ ///
+ ///
+ public static FormsAuthenticationTicket UmbracoLoginWebApi(this HttpResponseMessage response, IUser user)
+ {
+ if (response == null) throw new ArgumentNullException("response");
+
+ //remove the external login cookie
+ var extLoginCookie = new CookieHeaderValue(Constants.Security.BackOfficeExternalAuthenticationType, "")
+ {
+ Expires = DateTime.Now.AddYears(-1),
+ Path = "/"
+ };
+
+ var userDataString = JsonConvert.SerializeObject(Mapper.Map(user));
+
+ var ticket = new FormsAuthenticationTicket(
+ 4,
+ user.Username,
+ DateTime.Now,
+ DateTime.Now.AddMinutes(GlobalSettings.TimeOutInMinutes),
+ true,
+ userDataString,
+ "/"
+ );
+
+ // Encrypt the cookie using the machine key for secure transport
+ var encrypted = FormsAuthentication.Encrypt(ticket);
+
+ //add the cookie
+ var authCookie = new CookieHeaderValue(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, encrypted)
+ {
+ //Umbraco has always persisted it's original cookie for 1 day so we'll keep it that way
+ Expires = DateTime.Now.AddMinutes(1440),
+ Path = "/",
+ Secure = GlobalSettings.UseSSL,
+ HttpOnly = true
+ };
+
+ response.Headers.AddCookies(new[] { authCookie, extLoginCookie });
+
+ return ticket;
}
///
@@ -297,8 +351,8 @@ namespace Umbraco.Core.Security
private static void Logout(this HttpContextBase http, string cookieName)
{
if (http == null) throw new ArgumentNullException("http");
- //clear the preview cookie too
- var cookies = new[] { cookieName, Constants.Web.PreviewCookieName };
+ //clear the preview cookie and external login
+ var cookies = new[] { cookieName, Constants.Web.PreviewCookieName, Constants.Security.BackOfficeExternalAuthenticationType };
foreach (var c in cookies)
{
//remove from the request
@@ -411,7 +465,6 @@ namespace Umbraco.Core.Security
/// The user data.
/// The login timeout mins.
/// The minutes persisted.
- /// The cookie path.
/// Name of the cookie.
/// The cookie domain.
private static FormsAuthenticationTicket CreateAuthTicketAndCookie(this HttpContextBase http,
diff --git a/src/Umbraco.Core/Security/BackOfficeClaimsIdentityFactory.cs b/src/Umbraco.Core/Security/BackOfficeClaimsIdentityFactory.cs
index 54b537faab..b6d19b78eb 100644
--- a/src/Umbraco.Core/Security/BackOfficeClaimsIdentityFactory.cs
+++ b/src/Umbraco.Core/Security/BackOfficeClaimsIdentityFactory.cs
@@ -22,11 +22,11 @@ namespace Umbraco.Core.Security
Id = user.Id,
Username = user.UserName,
RealName = user.Name,
- AllowedApplications = user.AllowedApplications,
+ AllowedApplications = user.AllowedSections,
Culture = user.Culture,
Roles = user.Roles.Select(x => x.RoleId).ToArray(),
- StartContentNode = user.StartContentNode,
- StartMediaNode = user.StartMediaNode
+ StartContentNode = user.StartContentId,
+ StartMediaNode = user.StartMediaId
});
return umbracoIdentity;
diff --git a/src/Umbraco.Core/Security/BackOfficeUserStore.cs b/src/Umbraco.Core/Security/BackOfficeUserStore.cs
index dd2041fd51..0b1c95deb9 100644
--- a/src/Umbraco.Core/Security/BackOfficeUserStore.cs
+++ b/src/Umbraco.Core/Security/BackOfficeUserStore.cs
@@ -414,25 +414,25 @@ namespace Umbraco.Core.Security
anythingChanged = true;
user.Language = identityUser.Culture;
}
- if (user.StartMediaId != identityUser.StartMediaNode)
+ if (user.StartMediaId != identityUser.StartMediaId)
{
anythingChanged = true;
- user.StartMediaId = identityUser.StartMediaNode;
+ user.StartMediaId = identityUser.StartMediaId;
}
- if (user.StartContentId != identityUser.StartContentNode)
+ if (user.StartContentId != identityUser.StartContentId)
{
anythingChanged = true;
- user.StartContentId = identityUser.StartContentNode;
+ user.StartContentId = identityUser.StartContentId;
}
- if (user.AllowedSections.ContainsAll(identityUser.AllowedApplications) == false
- || identityUser.AllowedApplications.ContainsAll(user.AllowedSections) == false)
+ if (user.AllowedSections.ContainsAll(identityUser.AllowedSections) == false
+ || identityUser.AllowedSections.ContainsAll(user.AllowedSections) == false)
{
anythingChanged = true;
foreach (var allowedSection in user.AllowedSections)
{
user.RemoveAllowedSection(allowedSection);
}
- foreach (var allowedApplication in identityUser.AllowedApplications)
+ foreach (var allowedApplication in identityUser.AllowedSections)
{
user.AddAllowedSection(allowedApplication);
}
@@ -448,7 +448,7 @@ namespace Umbraco.Core.Security
///
public Task AddToRoleAsync(BackOfficeIdentityUser user, string roleName)
{
- if (user.AllowedApplications.InvariantContains(roleName)) return Task.FromResult(0);
+ if (user.AllowedSections.InvariantContains(roleName)) return Task.FromResult(0);
var asInt = user.Id.TryConvertTo();
if (asInt == false)
@@ -474,7 +474,7 @@ namespace Umbraco.Core.Security
///
public Task RemoveFromRoleAsync(BackOfficeIdentityUser user, string roleName)
{
- if (user.AllowedApplications.InvariantContains(roleName) == false) return Task.FromResult(0);
+ if (user.AllowedSections.InvariantContains(roleName) == false) return Task.FromResult(0);
var asInt = user.Id.TryConvertTo();
if (asInt == false)
@@ -500,7 +500,7 @@ namespace Umbraco.Core.Security
///
public Task> GetRolesAsync(BackOfficeIdentityUser user)
{
- return Task.FromResult((IList)user.AllowedApplications.ToList());
+ return Task.FromResult((IList)user.AllowedSections.ToList());
}
///
@@ -510,7 +510,7 @@ namespace Umbraco.Core.Security
///
public Task IsInRoleAsync(BackOfficeIdentityUser user, string roleName)
{
- return Task.FromResult(user.AllowedApplications.InvariantContains(roleName));
+ return Task.FromResult(user.AllowedSections.InvariantContains(roleName));
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs
index a1e12401b1..0606cec1dd 100644
--- a/src/Umbraco.Web/Editors/AuthenticationController.cs
+++ b/src/Umbraco.Web/Editors/AuthenticationController.cs
@@ -43,7 +43,14 @@ namespace Umbraco.Web.Editors
[IsBackOffice]
public class AuthenticationController : UmbracoApiController
{
-
+
+ private BackOfficeUserManager _userManager;
+
+ protected BackOfficeUserManager UserManager
+ {
+ get { return _userManager ?? (_userManager = TryGetOwinContext().Result.GetUserManager()); }
+ }
+
///
/// This is a special method that will return the current users' remaining session seconds, the reason
/// it is special is because this route is ignored in the UmbracoModule so that the auth ticket doesn't get
@@ -85,33 +92,6 @@ namespace Umbraco.Web.Editors
}
}
- private void AddModelErrors(IdentityResult result, string prefix = "")
- {
- foreach (var error in result.Errors)
- {
- ModelState.AddModelError(prefix, error);
- }
- }
-
- private async Task SignInAsync(BackOfficeIdentityUser user, bool isPersistent)
- {
- var owinContext = TryGetOwinContext().Result;
-
- owinContext.Authentication.SignOut(Core.Constants.Security.BackOfficeExternalAuthenticationType);
-
- owinContext.Authentication.SignIn(
- new AuthenticationProperties() { IsPersistent = isPersistent },
- await GenerateUserIdentityAsync(user));
- }
-
- private async Task GenerateUserIdentityAsync(BackOfficeIdentityUser user)
- {
- // NOTE the authenticationType must match the umbraco one
- // defined in CookieAuthenticationOptions.AuthenticationType
- var userIdentity = await UserManager.CreateIdentityAsync(user, global::Umbraco.Core.Constants.Security.BackOfficeAuthenticationType);
- return userIdentity;
- }
-
///
/// Checks if the current user's cookie is valid and if so returns OK or a 400 (BadRequest)
///
@@ -154,53 +134,45 @@ namespace Umbraco.Web.Editors
}
[WebApi.UmbracoAuthorize]
- [SetAngularAntiForgeryTokens]
+ [ValidateAngularAntiForgeryToken]
public async Task> GetCurrentUserLinkedLogins()
{
var identityUser = await UserManager.FindByIdAsync(UmbracoContext.Security.GetUserId());
return identityUser.Logins.ToDictionary(x => x.LoginProvider, x => x.ProviderKey);
}
- private BackOfficeUserManager _userManager;
-
- protected BackOfficeUserManager UserManager
- {
- get { return _userManager ?? (_userManager = TryGetOwinContext().Result.GetUserManager()); }
- }
-
///
/// Logs a user in
///
///
[SetAngularAntiForgeryTokens]
- public UserDetail PostLogin(LoginModel loginModel)
+ public HttpResponseMessage PostLogin(LoginModel loginModel)
{
if (UmbracoContext.Security.ValidateBackOfficeCredentials(loginModel.Username, loginModel.Password))
{
+ //get the user
var user = Security.GetBackOfficeUser(loginModel.Username);
+ var userDetail = Mapper.Map(user);
- //TODO: Clean up the int cast!
- var ticket = UmbracoContext.Security.PerformLogin(user);
+ //create a response with the userDetail object
+ var response = Request.CreateResponse(HttpStatusCode.OK, userDetail);
- //TODO: Normally we'd do something like this for identity, but we're mixing and matching legacy and new here
- // so we'll keep the legacy way and move forward with this in our custom handler for now, eventually replacing
- // the above legacy logic with the new stuff.
-
- //OwinContext.Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
- //OwinContext.Authentication.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent },
- // await user.GenerateUserIdentityAsync(UserManager));
+ //set the response cookies with the ticket (NOTE: This needs to be done with the custom webapi extension because
+ // we cannot mix HttpContext.Response.Cookies and the way WebApi/Owin work)
+ var ticket = response.UmbracoLoginWebApi(user);
var http = this.TryGetHttpContext();
if (http.Success == false)
{
throw new InvalidOperationException("This method requires that an HttpContext be active");
}
+ //This ensure the current principal is set, otherwise any logic executing after this wouldn't actually be authenticated
http.Result.AuthenticateCurrentRequest(ticket, false);
+
+ //update the userDetail and set their remaining seconds
+ userDetail.SecondsUntilTimeout = ticket.GetRemainingAuthSeconds();
- var result = Mapper.Map(user);
- //set their remaining seconds
- result.SecondsUntilTimeout = ticket.GetRemainingAuthSeconds();
- return result;
+ return response;
}
//return BadRequest (400), we don't want to return a 401 because that get's intercepted
@@ -222,5 +194,32 @@ namespace Umbraco.Web.Editors
{
return Request.CreateResponse(HttpStatusCode.OK);
}
+
+ private void AddModelErrors(IdentityResult result, string prefix = "")
+ {
+ foreach (var error in result.Errors)
+ {
+ ModelState.AddModelError(prefix, error);
+ }
+ }
+
+ private async Task SignInAsync(BackOfficeIdentityUser user, bool isPersistent)
+ {
+ var owinContext = TryGetOwinContext().Result;
+
+ owinContext.Authentication.SignOut(Core.Constants.Security.BackOfficeExternalAuthenticationType);
+
+ owinContext.Authentication.SignIn(
+ new AuthenticationProperties() { IsPersistent = isPersistent },
+ await GenerateUserIdentityAsync(user));
+ }
+
+ private async Task GenerateUserIdentityAsync(BackOfficeIdentityUser user)
+ {
+ // NOTE the authenticationType must match the umbraco one
+ // defined in CookieAuthenticationOptions.AuthenticationType
+ var userIdentity = await UserManager.CreateIdentityAsync(user, global::Umbraco.Core.Constants.Security.BackOfficeAuthenticationType);
+ return userIdentity;
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs
index 0bda50e1fc..7200f2a7c2 100644
--- a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs
@@ -5,6 +5,9 @@ using Umbraco.Core.Models.Mapping;
using Umbraco.Core.Models.Membership;
using Umbraco.Web.Models.ContentEditing;
using umbraco;
+using Umbraco.Core.Models;
+using Umbraco.Core.Models.Identity;
+using Umbraco.Core.Security;
namespace Umbraco.Web.Models.Mapping
{
@@ -17,7 +20,19 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(detail => detail.UserType, opt => opt.MapFrom(user => user.UserType.Alias))
.ForMember(detail => detail.StartContentId, opt => opt.MapFrom(user => user.StartContentId))
.ForMember(detail => detail.StartMediaId, opt => opt.MapFrom(user => user.StartMediaId))
- .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => ui.Culture(user)))
+ .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
+ .ForMember(
+ detail => detail.EmailHash,
+ opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().ToMd5()))
+ .ForMember(detail => detail.SecondsUntilTimeout, opt => opt.Ignore());
+
+ config.CreateMap()
+ .ForMember(detail => detail.UserId, opt => opt.MapFrom(user => user.Id))
+ .ForMember(detail => detail.UserType, opt => opt.MapFrom(user => user.UserTypeAlias))
+ .ForMember(detail => detail.StartContentId, opt => opt.MapFrom(user => user.StartContentId))
+ .ForMember(detail => detail.StartMediaId, opt => opt.MapFrom(user => user.StartMediaId))
+ .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.Culture))
+ .ForMember(detail => detail.AllowedSections, opt => opt.MapFrom(user => user.AllowedSections))
.ForMember(
detail => detail.EmailHash,
opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().ToMd5()))
@@ -25,6 +40,18 @@ namespace Umbraco.Web.Models.Mapping
config.CreateMap()
.ForMember(detail => detail.UserId, opt => opt.MapFrom(profile => GetIntId(profile.Id)));
+
+ config.CreateMap()
+ .ConstructUsing((IUser user) => new UserData(Guid.NewGuid().ToString("N"))) //this is the 'session id'
+ .ForMember(detail => detail.Id, opt => opt.MapFrom(user => user.Id))
+ .ForMember(detail => detail.AllowedApplications, opt => opt.MapFrom(user => user.AllowedSections))
+ .ForMember(detail => detail.RealName, opt => opt.MapFrom(user => user.Name))
+ .ForMember(detail => detail.Roles, opt => opt.MapFrom(user => new[] {user.UserType.Alias}))
+ .ForMember(detail => detail.StartContentNode, opt => opt.MapFrom(user => user.StartContentId))
+ .ForMember(detail => detail.StartMediaNode, opt => opt.MapFrom(user => user.StartMediaId))
+ .ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.Username))
+ .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)));
+
}
private static int GetIntId(object id)
diff --git a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs
index 912b19fd2e..7e70ba2958 100644
--- a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs
+++ b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs
@@ -84,6 +84,8 @@ namespace Umbraco.Web.Security.Identity
{
Provider = new CookieAuthenticationProvider
{
+ //TODO: Need to implement IUserSecurityStampStore on BackOfficeUserStore!
+
//// Enables the application to validate the security stamp when the user
//// logs in. This is a security feature which is used when you
//// change a password or add an external login to your account.
diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs
index b6ec3680d8..19857ddbcf 100644
--- a/src/Umbraco.Web/Security/WebSecurity.cs
+++ b/src/Umbraco.Web/Security/WebSecurity.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
+using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Membership;
@@ -94,18 +95,18 @@ namespace Umbraco.Web.Security
/// returns the Forms Auth ticket created which is used to log them in
public virtual FormsAuthenticationTicket PerformLogin(IUser user)
{
- var ticket = _httpContext.CreateUmbracoAuthTicket(new UserData(Guid.NewGuid().ToString("N"))
+ //clear the external cookie - we do this without owin context because we're writing cookies directly to httpcontext
+ // and cookie handling is different with httpcontext vs webapi and owin, normally we'd do:
+ //_httpContext.GetOwinContext().Authentication.SignOut(Constants.Security.BackOfficeExternalAuthenticationType);
+
+ var externalLoginCookie = _httpContext.Request.Cookies.Get(Constants.Security.BackOfficeExternalAuthenticationType);
+ if (externalLoginCookie != null)
{
- Id = user.Id,
- AllowedApplications = user.AllowedSections.ToArray(),
- RealName = user.Name,
- //currently we only have one user type!
- Roles = new[] { user.UserType.Alias },
- StartContentNode = user.StartContentId,
- StartMediaNode = user.StartMediaId,
- Username = user.Username,
- Culture = ui.Culture(user)
- });
+ externalLoginCookie.Expires = DateTime.Now.AddYears(-1);
+ _httpContext.Response.Cookies.Set(externalLoginCookie);
+ }
+
+ var ticket = _httpContext.CreateUmbracoAuthTicket(Mapper.Map(user));
LogHelper.Info("User Id: {0} logged in", () => user.Id);
diff --git a/src/Umbraco.Web/WebApi/Filters/AngularAntiForgeryHelper.cs b/src/Umbraco.Web/WebApi/Filters/AngularAntiForgeryHelper.cs
index 2e4b4176bb..d48cd66077 100644
--- a/src/Umbraco.Web/WebApi/Filters/AngularAntiForgeryHelper.cs
+++ b/src/Umbraco.Web/WebApi/Filters/AngularAntiForgeryHelper.cs
@@ -1,8 +1,10 @@
-using System.Linq;
+using System;
+using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Helpers;
using Umbraco.Core;
+using Umbraco.Core.Logging;
namespace Umbraco.Web.WebApi.Filters
{
@@ -54,8 +56,9 @@ namespace Umbraco.Web.WebApi.Filters
{
AntiForgery.Validate(cookieToken, headerToken);
}
- catch
+ catch (Exception ex)
{
+ LogHelper.Error(typeof(AngularAntiForgeryHelper), "Could not validate XSRF token", ex);
return false;
}
return true;
diff --git a/src/Umbraco.Web/WebApi/Filters/UmbracoBackOfficeLogoutAttribute.cs b/src/Umbraco.Web/WebApi/Filters/UmbracoBackOfficeLogoutAttribute.cs
index ecde11023b..693d45c792 100644
--- a/src/Umbraco.Web/WebApi/Filters/UmbracoBackOfficeLogoutAttribute.cs
+++ b/src/Umbraco.Web/WebApi/Filters/UmbracoBackOfficeLogoutAttribute.cs
@@ -7,7 +7,7 @@ namespace Umbraco.Web.WebApi.Filters
/// A filter that is used to remove the authorization cookie for the current user when the request is successful
///
///
- /// This is used so that we can log a user out in conjunction with using other filters that modify the cookies collection.
+ /// This is used so that we can log a user OUT in conjunction with using other filters that modify the cookies collection.
/// SD: I beleive this is a bug with web api since if you modify the cookies collection on the HttpContext.Current and then
/// use a filter to write the cookie headers, the filter seems to have no affect at all.
///