Preview mode breaks when using a default controller with a custom Authorize Attribute
My site implements a default controller which is decorated with a custom authorize attribute. I am using this so I can redirect members who are logged in but not authorised to the right place.
// Employ a custom base controller so all pages need authosisation by default.
DefaultRenderMvcControllerResolver.Current.SetDefaultControllerType(typeof(DefaultController));
The problem is, backoffice users get bounced to my 'not-authorised' page when attempting to preview a page. What I need is either a way to 'authorise' backoffice users or some kind of exclusion (e.g. /umbraco) from routing via my default controller.
The latter would be preferable and TBH maybe this should be logged as a bug - no other backoffice functionality is affected, apart from preview.
My abbreviated custom authorize attribute:
public class CustomAuthorize: AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (filterContext.HttpContext.User.Identity.IsAuthenticated == false)
{
... redirect to login page
return;
}
if (UmbracoContext.Current.Security.IsAuthenticated())
{
...this request is ok - how to authorise so it can continue?
}
// User is authenticated but not authorised to view the requested page.
if (filterContext.Result is HttpUnauthorizedResult)
{
...redirect to not authorised
}
}
}
Thanks Dave - the problem is though the Authorize routine still returns a Http unauthorised - I can't figure out how to override this and continue on to the initial request as an authorised user.
e.g. in the above code I am using UmbracoContext.Current.Security.IsAuthenticated() to ensure its a request from a backoffice user - just dunno how to handle it from there.
Ideally I need a solution so any /Umbraco requests do not get routed though my default controller at all. Further testing shows there are other backoffice API requests failing so I may need to raise this as a bug on the issue tracker.
Now I understand the process a bit better I am going to attempt to skip the base.OnAuthorization(filterContext); in my custom Authorise attribute when I detect a backoffice user and see if that means I can skip login altogether on preview - that would be ideal for my scenario.
I missed something quite simple here - I simply checked UmbracoContext.Current.Security.IsAuthenticated() before my custom authorize attribute method hit base.OnAuthorization(filterContext);
Therefore authorization is never performed for backoffice users on the front end. This is ideal in my scenario as it is a very simple, flat membership system with no difference in content or access depending on role.
The only gotcha (so far!) is I need to override MembershipHelper.GetCurrentMember to map backoffice users to a dummy account for front-end browsing.
Follow up to this, I am seeing lots of entries like this in the log:
2015-11-17 08:37:39,888 [P3680/D2/T41] INFO Umbraco.Core.Security.UmbracoMembershipProviderBase - Login attempt succeeded for username [email protected] from IP address 127.0.0.1
2015-11-17 08:37:50,913 [P3680/D2/T49] ERROR Umbraco.Core.Security.AuthenticationExtensions - The current identity cannot be converted to Umbraco.Core.Security.UmbracoBackOfficeIdentity
System.InvalidOperationException: Cannot create a Umbraco.Core.Security.UmbracoBackOfficeIdentity from System.Security.Claims.ClaimsIdentity since the required claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier is missing at Umbraco.Core.Security.UmbracoBackOfficeIdentity.FromClaimsIdentity(ClaimsIdentity identity) at Umbraco.Core.Security.AuthenticationExtensions.GetCurrentIdentity(HttpContextBase http, Boolean authenticateRequestIfNotFound)
This is happening immediately after a MEMBER login is performed. FYI I am overriding the MembershipHelper to provide my own (very simple) Login method:
public bool SiteLogin(string username, string password)
{
if (base.Login(username, password))
{
try
{
// Find the umb member by username and retrieve the isActivated property
var member = GetByUsername(username);
var isActivated = member.GetPropertyValue<bool>("isActivated");
return isActivated;
}
catch
{
return false;
}
}
// base Login failed
return false;
}
Thanks Shannon - looks like a fix is due in 7.4 which will be great.
Just so you know though - This error is still being reported when logging in using the OOTB MembershipHelper.Login() - on a non-protected page, with cookies all wiped beforehand. Basically I have ensured its not running through any custom code to perform the member login/authorisation, and its nothing to do with preview either.
Let me know if you want me to create a new issue for this. Hit me up if you need me to share any setup details if you need to repro (Umbraco version 7.3.0 assembly: 1.0.5750.18157).
I'm getting the same, repeated errors as Barry Fogarty in my newly upgraded 7.4.1 site.
This happens whenever a front-end member signs in and also when a backoffice user signs in or, seemingly, edits a page. I have not done any customization or overrides of the membership providers.
Preview mode breaks when using a default controller with a custom Authorize Attribute
My site implements a default controller which is decorated with a custom authorize attribute. I am using this so I can redirect members who are logged in but not authorised to the right place.
The problem is, backoffice users get bounced to my 'not-authorised' page when attempting to preview a page. What I need is either a way to 'authorise' backoffice users or some kind of exclusion (e.g. /umbraco) from routing via my default controller.
The latter would be preferable and TBH maybe this should be logged as a bug - no other backoffice functionality is affected, apart from preview.
My abbreviated custom authorize attribute:
Hi Barry,
Maybe you can check if the page is being used in Preview mode :
Dave
Thanks Dave - the problem is though the Authorize routine still returns a Http unauthorised - I can't figure out how to override this and continue on to the initial request as an authorised user.
e.g. in the above code I am using
UmbracoContext.Current.Security.IsAuthenticated()
to ensure its a request from a backoffice user - just dunno how to handle it from there.Ideally I need a solution so any /Umbraco requests do not get routed though my default controller at all. Further testing shows there are other backoffice API requests failing so I may need to raise this as a bug on the issue tracker.
I think this might have been logged on the tracker already if you wanna give searching there a try
Thanks Shannon - I found the issue and added my experience trying the workaround. Unfortunately I didnt have any success with it:
http://issues.umbraco.org/issue/U4-4219
Now I understand the process a bit better I am going to attempt to skip the
base.OnAuthorization(filterContext);
in my custom Authorise attribute when I detect a backoffice user and see if that means I can skip login altogether on preview - that would be ideal for my scenario.Cheers for pointing out the issue!
I missed something quite simple here - I simply checked
UmbracoContext.Current.Security.IsAuthenticated()
before my custom authorize attribute method hitbase.OnAuthorization(filterContext);
Therefore authorization is never performed for backoffice users on the front end. This is ideal in my scenario as it is a very simple, flat membership system with no difference in content or access depending on role.
The only gotcha (so far!) is I need to override MembershipHelper.GetCurrentMember to map backoffice users to a dummy account for front-end browsing.
Strangely I am getting the doc ID appended twice to my preview URL e.g.
/umbraco/preview/?id=10747#?id=10747
Not sure why but thought it worth noting. Preview still works fine but seems to be performing a double redirect.
Follow up to this, I am seeing lots of entries like this in the log:
2015-11-17 08:37:39,888 [P3680/D2/T41] INFO Umbraco.Core.Security.UmbracoMembershipProviderBase - Login attempt succeeded for username [email protected] from IP address 127.0.0.1
2015-11-17 08:37:50,913 [P3680/D2/T49] ERROR Umbraco.Core.Security.AuthenticationExtensions - The current identity cannot be converted to Umbraco.Core.Security.UmbracoBackOfficeIdentity System.InvalidOperationException: Cannot create a Umbraco.Core.Security.UmbracoBackOfficeIdentity from System.Security.Claims.ClaimsIdentity since the required claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier is missing at Umbraco.Core.Security.UmbracoBackOfficeIdentity.FromClaimsIdentity(ClaimsIdentity identity) at Umbraco.Core.Security.AuthenticationExtensions.GetCurrentIdentity(HttpContextBase http, Boolean authenticateRequestIfNotFound)
This is happening immediately after a MEMBER login is performed. FYI I am overriding the MembershipHelper to provide my own (very simple) Login method:
It's because it's trying to auth a back office user based on an IPrincipal from a front-end member.
As i said, this all needs to be properly fixed at the core level, if you try to force this i'm sure you'll end up with strange things happening.
Thanks Shannon - looks like a fix is due in 7.4 which will be great.
Just so you know though - This error is still being reported when logging in using the OOTB MembershipHelper.Login() - on a non-protected page, with cookies all wiped beforehand. Basically I have ensured its not running through any custom code to perform the member login/authorisation, and its nothing to do with preview either.
Let me know if you want me to create a new issue for this. Hit me up if you need me to share any setup details if you need to repro (Umbraco version 7.3.0 assembly: 1.0.5750.18157).
Ok, if you have steps to repro, please create a new issue for it and let me know the link.
I'm getting the same, repeated errors as Barry Fogarty in my newly upgraded 7.4.1 site.
This happens whenever a front-end member signs in and also when a backoffice user signs in or, seemingly, edits a page. I have not done any customization or overrides of the membership providers.
Please see http://issues.umbraco.org/issue/U4-4219 fix is due in 7.4.2
is working on a reply...