Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/WebExpress.WebCore.Test/Data/MockIdentityProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ public IIdentity Authenticate(IRequest request)
return null; // not needed for this test
}

/// <summary>
/// Logs out the specified request by clearing any authentication state.
/// </summary>
/// <param name="request">
/// The request whose authentication state should be cleared. Cannot be null.
/// </param>
public void Logout(IRequest request)
{
// not needed for this test
}

/// <summary>
/// Displays a login dialog using the specified request and identity information.
/// </summary>
Expand All @@ -77,5 +88,27 @@ public IResponse CreateAuthenticationPrompt(IRequest request, IEndpointContext i
{
return null;
}

/// <summary>
/// Creates a forbidden response page for the specified request when the authenticated
/// user lacks the required permissions to access the requested resource.
/// </summary>
/// <param name="request">
/// The request for which access was denied. Cannot be null.
/// </param>
/// <param name="initiator">
/// The endpoint that the user attempted to access.
/// </param>
/// <param name="identity">
/// The authenticated identity that lacks sufficient permissions.
/// </param>
/// <returns>
/// A response representing the forbidden page if this provider can handle the forbidden
/// scenario; otherwise, <c>null</c>.
/// </returns>
public IResponse CreateForbiddenResponse(IRequest request, IEndpointContext initiator, IIdentity identity)
{
return null;
}
}
}
18 changes: 18 additions & 0 deletions src/WebExpress.WebCore/HttpServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,24 @@ public async Task ProcessRequestAsync(IHttpContext httpContext)
// check again
if (!_componentHub.IdentityManager.CheckAccess(identity, searchResult.EndpointContext))
{
// if the user is authenticated but lacks the required permissions, show the forbidden page
if (identity is not null)
{
var forbiddenResponse = _componentHub.IdentityManager.CreateForbiddenResponse
(
httpContext.Request,
searchResult.EndpointContext,
identity
);

if (forbiddenResponse is not null)
{
await responseSender.SendAsync(httpContext, forbiddenResponse);
return;
}
}

// if the user is not authenticated, show the login prompt
var loginResponse = _componentHub.IdentityManager.CreateAuthenticationPrompt
(
httpContext.Request,
Expand Down
20 changes: 20 additions & 0 deletions src/WebExpress.WebCore/WebIdentity/IIdentityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ public interface IIdentityManager : IComponentManager
/// </returns>
IResponse CreateAuthenticationPrompt(IRequest request, IEndpointContext initiator, IIdentity identity = null);

/// <summary>
/// Creates a forbidden response page for the specified request when the authenticated
/// user lacks the required permissions to access the requested resource.
/// </summary>
/// <param name="request">
/// The request for which access was denied. Cannot be null.
/// </param>
/// <param name="initiator">
/// The endpoint that the user attempted to access. Used to determine the origin and
/// context of the authorization failure.
/// </param>
/// <param name="identity">
/// The authenticated identity that lacks sufficient permissions. Cannot be null.
/// </param>
/// <returns>
/// A response representing the forbidden page if a registered identity provider can handle the
/// forbidden scenario; otherwise, <c>null</c>.
/// </returns>
IResponse CreateForbiddenResponse(IRequest request, IEndpointContext initiator, IIdentity identity);

/// <summary>
/// Attempts to authenticate the specified request within the given application context.
/// </summary>
Expand Down
29 changes: 29 additions & 0 deletions src/WebExpress.WebCore/WebIdentity/IIdentityProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ public interface IIdentityProvider
/// </returns>
IIdentity Authenticate(IRequest request);

/// <summary>
/// Logs out the specified request by clearing any authentication state
/// managed by this identity provider.
/// </summary>
/// <param name="request">
/// The request whose authentication state should be cleared. Cannot be null.
/// </param>
void Logout(IRequest request);

/// <summary>
/// Displays a login dialog using the specified request and identity information.
/// </summary>
Expand All @@ -49,5 +58,25 @@ public interface IIdentityProvider
/// relevant status information.
/// </returns>
IResponse CreateAuthenticationPrompt(IRequest request, IEndpointContext initiator, IIdentity identity);

/// <summary>
/// Creates a forbidden response page for the specified request when the authenticated
/// user lacks the required permissions to access the requested resource.
/// </summary>
/// <param name="request">
/// The request for which access was denied. Cannot be null.
/// </param>
/// <param name="initiator">
/// The endpoint that the user attempted to access. Used to determine the origin and
/// context of the authorization failure.
/// </param>
/// <param name="identity">
/// The authenticated identity that lacks sufficient permissions. Cannot be null.
/// </param>
/// <returns>
/// A response representing the forbidden page if this provider can handle the forbidden
/// scenario; otherwise, <c>null</c>.
/// </returns>
IResponse CreateForbiddenResponse(IRequest request, IEndpointContext initiator, IIdentity identity);
}
}
39 changes: 39 additions & 0 deletions src/WebExpress.WebCore/WebIdentity/IdentityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,36 @@ public IResponse CreateAuthenticationPrompt(IRequest request, IEndpointContext i
return null;
}

/// <summary>
/// Creates a forbidden response page for the specified request when the authenticated
/// user lacks the required permissions to access the requested resource.
/// </summary>
/// <param name="request">The request for which access was denied. Cannot be null.</param>
/// <param name="initiator">The endpoint that the user attempted to access.</param>
/// <param name="identity">The authenticated identity that lacks sufficient permissions.</param>
/// <returns>
/// A response representing the forbidden page if a registered identity provider can handle the
/// forbidden scenario; otherwise, <c>null</c>.
/// </returns>
public IResponse CreateForbiddenResponse(IRequest request, IEndpointContext initiator, IIdentity identity)
{
if (_identityProviders.TryGetValue(initiator?.ApplicationContext, out var list))
{
foreach (var provider in list)
{
var response = provider.CreateForbiddenResponse(request, initiator, identity);

if (response is not null)
{
// the first provider that can show a forbidden page wins
return response;
}
}
}

return null;
}

/// <summary>
/// Attempts to authenticate the specified request within the given application context.
/// </summary>
Expand Down Expand Up @@ -454,6 +484,15 @@ public bool Login(IRequest request, IIdentity identity)
/// <param name="request">The request.</param>
public void Logout(IRequest request)
{
// notify all registered identity providers so they can clear their own state
foreach (var list in _identityProviders.Values)
{
foreach (var provider in list)
{
provider.Logout(request);
}
}

var session = _componentHub.SessionManager.GetSession(request);
session.RemoveProperty<SessionPropertyAuthentification>();
}
Expand Down
Loading