U4-7121 - Issue: OWIN Identity ForUmbracoBackOffice prefixes AuthenticationType and breaks external AzureAD auth.

Created by Robert Foster 21 Sep 2015, 13:55:10 Updated by Shannon Deminick 26 Oct 2015, 14:25:04

I have the following code in my UmbracoADAuthExtensions based on the UmbracoIdentityExtensions with some modification from looking through example code and my own discovery (the authority in the current UmbracoIdentityExtensions codebase is wrong for AzureAD):

public static void ConfigureBackOfficeAzureActiveDirectoryAuth(this IAppBuilder app, string tenant, string clientId, string postLogoutRedirectUri, Guid issuerId, string caption = "Active Directory", string style = "btn-microsoft", string icon = "fa-windows") {
var authority = string.Format( CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}", tenant);

        var adOptions = new OpenIdConnectAuthenticationOptions
        {
            SignInAsAuthenticationType = Constants.Security.BackOfficeExternalAuthenticationType,
            ClientId = clientId,
            PostLogoutRedirectUri = postLogoutRedirectUri,
            Authority = authority,
            // Need to set the auth type as the issuer path so that we can use auto-registration.
            AuthenticationType = string.Format(CultureInfo.InvariantCulture, "https://sts.windows.net/{0}/", issuerId)
        };

        adOptions.ForUmbracoBackOffice(style, icon);  // Have just discovered that this modifies the AuthenticationType
        adOptions.Caption = caption;
        app.UseOpenIdConnectAuthentication(adOptions); 
    }    

After several hours of trying to get auth to work and getting frustrated with the following error:

The requested provider (https://sts.windows.net//) has not been linked to to an account

I found in the code that the extension method ForUmbracoBackOffice in Umbraco.Web.Security.Identity.AuthenticationOptionsExtensions is prepending the AuthenticationType with "Umbraco." which breaks the authType check in AutoLinkAndSignInExternalAccount

ForUmbracoBackOffice:

        //Ensure the prefix is set
        if (options.AuthenticationType.StartsWith(Constants.Security.BackOfficeExternalAuthenticationTypePrefix) == false)
        {
            options.AuthenticationType = Constants.Security.BackOfficeExternalAuthenticationTypePrefix + options.AuthenticationType;    
        }

AutoLinkAndSignInExternalAccount: var authType = OwinContext.Authentication.GetExternalAuthenticationTypes().FirstOrDefault(x => x.AuthenticationType == loginInfo.Login.LoginProvider);

So I have two questions:

Why is the AuthenticationType being prefixed but the prefix doesn't appear to be in use anywhere else...

Should AutoLinkAndSignInExternalAccount be using the prefix in it's check for a supported ExternalAuthenticationType?

Comments

Shannon Deminick 21 Sep 2015, 14:08:33

Yes for AzureAD the auth type needs to be specific, this is an oversight for this specific provider. The notes in this class hint at this requirement and in fact re-correct the auth type properly:

https://github.com/umbraco/UmbracoIdentityExtensions/blob/master/src/App_Start/UmbracoADAuthExtensions.cs

The reason why we prefix the 'auth type' is to differentiate it from the front-end. For example, someone can be using google for both front-end and back-office logins but with different providers. the 'auth type' is really just a name, however in the case of azure ad, it's very specific unfortunately.

You can work around this issue by doing this by doing exactly what is in the class shown above.

The only thing we can do to make this slightly clearer is to offer an overload of ForUmbracoBackOffice to not prefix the auth type, otherwise you should just use the code supplied with the identity extensions.

I will add more docs for this stuff when there is time and when identity extensions is actually released which will be post launch of 7.3.


Robert Foster 21 Sep 2015, 14:13:57

@Shandem Thanks for that; yes - found the override, was wondering why it was initially set up that way.

I've corrected it and am now looking at implementing ExternalSignInAutoLinkOptions for the AzureAD auth provider.

I'd like to be able to set it up so that staff can log in without having to worry about creating a corresponding user in Umbraco first, at least, that was my plan.


Shannon Deminick 21 Sep 2015, 14:21:55

Yup, that's the point of these options (of course you'd never enable this for something like a Google provider! ;) )

Can you point me to the code where you are asking about

Should AutoLinkAndSignInExternalAccount be using the prefix in it's check for a supported ExternalAuthenticationType?

?

Sorry, my brain is full of a bunch of different codebases and haven't worked on this for a while now.


Robert Foster 21 Sep 2015, 14:26:30

Here you go:

https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/Editors/BackOfficeController.cs#L512


Robert Foster 21 Sep 2015, 14:30:40

The other issue I'm going to have with this is I need to allow staff access to the front end (extranet web app) as well as the backend (a subset - I plan on using groups to differentiate).

Using the prefix is not going to work in this scenario since I'm effectively overriding it here.

Probably need a slightly more sophisticated option. If I use group membership in AzureAD to restrict access to the backend I will probably have to sue the OnAutoLinking callback in the ExternalSignInAutoLinkOptions object.

Not yet sure how this is going to go... still just a concept in my head for the most part.


Shannon Deminick 21 Sep 2015, 14:38:35

Well in order for the azure ad stuff to work, you can't really have a prefix. So you need to remove the prefix as is done in the ext method i mentioned. The prefix shouldn't play a role with regards to auto-linking, since all it's doing is checking that the auth type matches what the oauth provider has specified for it's LoginProvider value. So the auto-linking should just work so long as you remove the prefix.

... does it ?

As for using the same provider for the front-end and the back-end, that should be possible as well. For front-end identity (i.e. Members), you should use my UmbracoIdentity project: https://github.com/Shazwazza/umbracoidentity ... this stuff will eventually be merged into the core but there is no time for that at the moment so if you want ASP.Net Identity to work for front-end you can use this and it should work seamlessly along side 7.3. Of course I need to document some stuff in regards to the integration such as owin startup code, etc... but if you've got this far you should be aware of what is required. For the external auth providers, they all offer callbacks to do something with the data before handing it off to ASP.Net identity. You could probably inspect the user that they've logged in with and check it's groups and then determine if that will or will not work for either a front-end member or back office user. There's plenty of Identity extension points you can use, i definitely don't know all of them but you should be able to do what you want in one way or another.


Robert Foster 21 Sep 2015, 14:42:23

Yep, backend auth works fine provided I have an existing user - just about to start testing the SetExternalSignInAutoLinkOptions() stuff now - right after I figure out how to get the Email field of the Identity to populate from AzureAD that is.

I was looking at your UmbracoIdentity project - planning to tackle that next.


Shannon Deminick 21 Sep 2015, 14:47:31

The email property should just work it's part of the ExternalLoginInfo class, Azure response should auto-populate this data


Robert Foster 21 Sep 2015, 14:51:24

Should, but isn't - probably a configuration issue with the Azure AD app. Looking into it...


Shannon Deminick 21 Sep 2015, 14:54:49

Hrm, it would also be worth testing with a simple provider like Google to ensure the normal flow is happening there for you since azure ad provider is pretty insane. The config you see there is the tiny config, the original config i had to do was three times as big and confusing.


Robert Foster 21 Sep 2015, 16:11:07

It looks like Azure AD doesn't yet support the Email claim in the Identity:

https://azure.microsoft.com/en-us/documentation/articles/active-directory-authentication-scenarios/#claims-in-azure-ad-security-tokens

and

https://azure.microsoft.com/en-us/documentation/articles/active-directory-token-and-claims/

I don't see the Email claim mentioned anywhere; and it's currently null for all users I've tested so far - worth noting that this is an Office 365 Azure AD, will do some more testing in the morning with a vanilla Azure AD but I don't think it's going to change much.

Azure AD might have to have some extra special attention to get this working as I'd like. At the moment it seems the only reliable way to link an Azure AD account to the backoffice is if there's already an account in there with the same login name.

The other thing about this is the error messages on the Umbraco backoffice login screen currently include the provider details - in this case it's the https://sts.windows.net with the issuer Id - probably doesn't pose too much of a security issue, but it does look ugly; and may confuse users. Not a problem if we can use a friendly provider name, but in this case it's not good probably...


Priority: Normal

Type: Bug

State: Open

Assignee: Shannon Deminick

Difficulty: Normal

Category:

Backwards Compatible: True

Fix Submitted:

Affected versions: 7.3.0

Due in version:

Sprint:

Story Points:

Cycle: