From 334078065c83737d171380acb62c91dbb5f774c7 Mon Sep 17 00:00:00 2001 From: joshuahenninger Date: Wed, 25 Oct 2023 16:32:31 -0700 Subject: [PATCH] + (Core) Fixed Obsidian Login block issue where external authentication did not work with custom page routes. (Fixes #5641) --- Rock.Blocks/Security/Login.cs | 57 +++++++++++++++++-- .../src/Security/login.obs | 3 +- .../Login/remoteLoginStartRequestBag.d.ts | 3 + .../Login/RemoteLoginStartRequestBag.cs | 8 +++ 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/Rock.Blocks/Security/Login.cs b/Rock.Blocks/Security/Login.cs index 11c776e1d85..107bdae7f57 100644 --- a/Rock.Blocks/Security/Login.cs +++ b/Rock.Blocks/Security/Login.cs @@ -626,7 +626,9 @@ public BlockActionResult RemoteLoginStart( RemoteLoginStartRequestBag bag ) return ActionBadRequest( "Please try a different authentication method" ); } - var loginUrl = externalRedirectAuthentication.GenerateExternalLoginUrl( GetRedirectUri(), GetRedirectUrlAfterLogin() ); + // Use the route passed from the client to build the redirect URI. + // The page route is not currently available within a block action. + var loginUrl = externalRedirectAuthentication.GenerateExternalLoginUrl( GetRedirectUri( bag.Route ), GetRedirectUrlAfterLogin() ); if ( loginUrl == null ) { @@ -735,10 +737,28 @@ private IEnumerable> GetAuthenticationCo /// /// Gets the redirect URI that can be used by external authentication components to complete authentication. /// - private string GetRedirectUri() + /// The path to use for the redirect URI. + private string GetRedirectUri( string path ) { - var uri = this.RequestContext.RequestUri; - return uri.Scheme + "://" + uri.GetComponents( UriComponents.HostAndPort, UriFormat.UriEscaped ).EnsureTrailingForwardslash() + $"page/{PageCache.Id}"; + // If the path is not valid then default to the current page. + if ( !IsPageRouteValid( path ) ) + { + path = this.GetCurrentPageUrl(); + } + + var uriBuilder = new UriBuilder + { + Scheme = this.RequestContext.RequestUri.Scheme, + Host = this.RequestContext.RequestUri.Host, + Port = this.RequestContext.RequestUri.Port, + Path = path + }; + + // Build the URI. This will pass a string representation of the URL (including the 443 port) to the Uri constructor. + var uri = uriBuilder.Uri; + + // Return the original string that was passed to the Uri constructor (including the 443 port). + return uri.OriginalString; } /// @@ -926,6 +946,31 @@ private bool IsExistingUser( UserLogin userLogin ) { return userLogin?.EntityType != null; } + + /// + /// Determines whether the specified route is a valid page route. + /// + /// The route. + /// + /// true if the specified route is valid page route; otherwise, false. + /// + private bool IsPageRouteValid( string route ) + { + // Ensure the supplied path is a valid page route. + if ( route.IsNullOrWhiteSpace() ) + { + return false; + } + + var simplifiedRoute = route.ToLower().RemoveLeadingForwardslash().RemoveTrailingForwardslash(); + + if ( this.PageCache.PageRoutes.Any( r => r.Route?.ToLower().RemoveLeadingForwardslash().RemoveTrailingForwardslash() == simplifiedRoute ) ) + { + return true; + } + + return simplifiedRoute == $"page/{this.PageCache.Id}"; + } /// /// Determines whether the is valid. @@ -1007,7 +1052,7 @@ private bool IsUserLockedOut( UserLogin userLogin, out string lockedOutMessage ) /// The external authentication providers. private void LogInWithExternalAuthProviderIfNeeded( LoginInitializationBox box, List> externalAuthProviders ) { - var redirectUrl = GetRedirectUri(); + var redirectUrl = GetRedirectUri( this.RequestContext.RequestUri.AbsolutePath ); foreach ( var authProvider in externalAuthProviders.Select( c => c.Component ) ) { @@ -1091,7 +1136,7 @@ private void RedirectToSingleExternalAuthProviderIfNeeded( LoginInitializationBo return; } - var authLoginUri = externalRedirectAuthentication.GenerateExternalLoginUrl( GetRedirectUri(), GetRedirectUrlAfterLogin() ).AbsoluteUri; + var authLoginUri = externalRedirectAuthentication.GenerateExternalLoginUrl( GetRedirectUri( this.RequestContext.RequestUri.AbsolutePath ), GetRedirectUrlAfterLogin() ).AbsoluteUri; if ( authLoginUri.IsNotNullOrWhiteSpace() ) { diff --git a/Rock.JavaScript.Obsidian.Blocks/src/Security/login.obs b/Rock.JavaScript.Obsidian.Blocks/src/Security/login.obs index 2ea7c2c8c91..201b1d49b11 100644 --- a/Rock.JavaScript.Obsidian.Blocks/src/Security/login.obs +++ b/Rock.JavaScript.Obsidian.Blocks/src/Security/login.obs @@ -190,7 +190,8 @@ async function onExternalLogin(externalLogin: ExternalAuthenticationButtonBag): Promise { isAuthenticating.value = true; const bag: RemoteLoginStartRequestBag = { - authenticationType: externalLogin.authenticationType + authenticationType: externalLogin.authenticationType, + route: location.pathname }; try { diff --git a/Rock.JavaScript.Obsidian/Framework/ViewModels/Blocks/Security/Login/remoteLoginStartRequestBag.d.ts b/Rock.JavaScript.Obsidian/Framework/ViewModels/Blocks/Security/Login/remoteLoginStartRequestBag.d.ts index eb619bb145c..89025e2de3a 100644 --- a/Rock.JavaScript.Obsidian/Framework/ViewModels/Blocks/Security/Login/remoteLoginStartRequestBag.d.ts +++ b/Rock.JavaScript.Obsidian/Framework/ViewModels/Blocks/Security/Login/remoteLoginStartRequestBag.d.ts @@ -25,4 +25,7 @@ export type RemoteLoginStartRequestBag = { /** Gets or sets the authentication entity type guid. */ authenticationType?: string | null; + + /** Gets or sets the current URL path. */ + route?: string | null; }; diff --git a/Rock.ViewModels/Blocks/Security/Login/RemoteLoginStartRequestBag.cs b/Rock.ViewModels/Blocks/Security/Login/RemoteLoginStartRequestBag.cs index c5e1dddcc25..e46c12a63e3 100644 --- a/Rock.ViewModels/Blocks/Security/Login/RemoteLoginStartRequestBag.cs +++ b/Rock.ViewModels/Blocks/Security/Login/RemoteLoginStartRequestBag.cs @@ -25,5 +25,13 @@ public class RemoteLoginStartRequestBag /// Gets or sets the authentication entity type guid. /// public string AuthenticationType { get; set; } + + /// + /// Gets or sets the current URL path. + /// + /// + /// The current URL path. + /// + public string Route { get; set; } } }