using System; using Microsoft.Owin; using Microsoft.Owin.Security; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Exceptions; namespace Umbraco.Web.Security { public static class AuthenticationOptionsExtensions { // these are used for backwards compat private const string ExternalSignInAutoLinkOptionsProperty = "ExternalSignInAutoLinkOptions"; private const string ChallengeResultCallbackProperty = "ChallengeResultCallback"; /// /// Used to specify all back office external login options /// /// /// public static void SetBackOfficeExternalLoginProviderOptions(this AuthenticationOptions authOptions, BackOfficeExternalLoginProviderOptions externalLoginProviderOptions) { authOptions.Description.Properties[Constants.Security.BackOfficeExternalLoginOptionsProperty] = externalLoginProviderOptions; // for backwards compat, we need to add these: if (externalLoginProviderOptions.AutoLinkOptions != null) authOptions.Description.Properties[ExternalSignInAutoLinkOptionsProperty] = externalLoginProviderOptions.AutoLinkOptions; if (externalLoginProviderOptions.OnChallenge != null) authOptions.Description.Properties[ChallengeResultCallbackProperty] = externalLoginProviderOptions.OnChallenge; } [Obsolete("Use SetBackOfficeExternalLoginProviderOptions instead")] public static void SetSignInChallengeResultCallback( this AuthenticationOptions authOptions, Func authProperties) { authOptions.Description.Properties[ChallengeResultCallbackProperty] = authProperties; } public static AuthenticationProperties GetSignInChallengeResult(this AuthenticationDescription authenticationDescription, IOwinContext ctx) { if (authenticationDescription.Properties.ContainsKey(ChallengeResultCallbackProperty) == false) return null; var cb = authenticationDescription.Properties[ChallengeResultCallbackProperty] as Func; if (cb == null) return null; return cb(ctx); } [Obsolete("Use SetBackOfficeExternalLoginProviderOptions instead")] public static void SetExternalSignInAutoLinkOptions( this AuthenticationOptions authOptions, ExternalSignInAutoLinkOptions options) { authOptions.Description.Properties[ExternalSignInAutoLinkOptionsProperty] = options; } [Obsolete("Use GetExternalSignInAutoLinkOptions instead")] public static ExternalSignInAutoLinkOptions GetExternalAuthenticationOptions(this AuthenticationDescription authenticationDescription) => authenticationDescription.GetExternalSignInAutoLinkOptions(); public static ExternalSignInAutoLinkOptions GetExternalSignInAutoLinkOptions(this AuthenticationDescription authenticationDescription) { if (authenticationDescription.Properties.ContainsKey(ExternalSignInAutoLinkOptionsProperty) == false) return null; var options = authenticationDescription.Properties[ExternalSignInAutoLinkOptionsProperty] as ExternalSignInAutoLinkOptions; return options; } /// /// Configures the properties of the authentication description instance for use with Umbraco back office /// /// /// /// /// /// This is important if the identity provider is to be able to authenticate when upgrading Umbraco. We will try to extract this from /// any options passed in via reflection since none of the default OWIN providers inherit from a base class but so far all of them have a consistent /// name for the 'CallbackPath' property which is of type PathString. So we'll try to extract it if it's not found or supplied. /// /// If a value is extracted or supplied, this will be added to an internal list which the UmbracoModule will use to allow the request to pass /// through without redirecting to the installer. /// public static void ForUmbracoBackOffice(this AuthenticationOptions options, string style, string icon, string callbackPath = null) { if (options == null) throw new ArgumentNullException(nameof(options)); if (string.IsNullOrEmpty(options.AuthenticationType)) throw new InvalidOperationException("The authentication type can't be null or empty."); //Ensure the prefix is set if (options.AuthenticationType.StartsWith(Constants.Security.BackOfficeExternalAuthenticationTypePrefix) == false) { options.AuthenticationType = Constants.Security.BackOfficeExternalAuthenticationTypePrefix + options.AuthenticationType; } options.Description.Properties["SocialStyle"] = style; options.Description.Properties["SocialIcon"] = icon; //flag for use in back office options.Description.Properties[Constants.Security.BackOfficeAuthenticationType] = true; if (callbackPath.IsNullOrWhiteSpace()) { try { //try to get it with reflection var prop = options.GetType().GetProperty("CallbackPath"); if (prop != null && TypeHelper.IsTypeAssignableFrom(prop.PropertyType)) { //get the value var path = (PathString) prop.GetValue(options); if (path.HasValue) { RoutableDocumentFilter.ReservedPaths.TryAdd(path.ToString()); } } } catch (System.Exception ex) { Current.Logger.Error(typeof (AuthenticationOptionsExtensions), ex, "Could not read AuthenticationOptions properties"); } } else { RoutableDocumentFilter.ReservedPaths.TryAdd(callbackPath); } } } }