Skip to content

Add login, logout, and forbidden pages with identity provider base class#10

Closed
Copilot wants to merge 2 commits intomainfrom
copilot/add-dedicated-logout-and-access-denied-pages
Closed

Add login, logout, and forbidden pages with identity provider base class#10
Copilot wants to merge 2 commits intomainfrom
copilot/add-dedicated-logout-and-access-denied-pages

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 14, 2026

Introduces dedicated auth-flow pages and an identity provider abstraction to support consistent login/logout UX and permission-denied handling across WebExpress applications.

New Pages

All three pages use a shared VisualTreeWebAppLogin — a stripped-down visual tree (header + centered card, no sidebar/breadcrumb) that establishes the common layout convention.

  • PageWebAppLogin — username/password form; delegates to IdentityManager.Login() with validation
  • PageWebAppLogout — calls IdentityManager.Logout() on render, then shows confirmation with link back to login
  • PageWebAppForbidden — access-denied page for authenticated users lacking permissions; offers a switch-account link to login

HTTP Status Pages

  • PageStatusWebAppForbidden[StatusResponse<ResponseForbidden>] (HTTP 403)
  • PageStatusWebAppUnauthorized[StatusResponse<ResponseUnauthorized>] (HTTP 401)

Both follow the existing PageStatusWebApp pattern.

Identity Provider

IdentityProvider is an abstract base class applications can extend:

public class MyIdentityProvider : IdentityProvider
{
    protected override IIdentity ValidateBasicCredentials(string username, string password) { ... }
    protected override IIdentity ValidateToken(string token) { ... }
    public override IEnumerable<IIdentity> GetIdentities() { ... }
    public override IEnumerable<IIdentityGroup> GetGroups() { ... }
}

Authenticate(IRequest) is implemented on the base class: parses the Authorization header and dispatches to the appropriate abstract hook based on Basic or Bearer/Token scheme.

Internationalization

Added en and de keys for all new UI strings (login form labels/errors, logout confirmation, forbidden message, 401/403 status descriptions).

Notes

  • ControlFormItemInputText is used for the password field since the framework has no dedicated password input control; a swap to ControlFormItemInputPassword is straightforward once available.
  • The SecureString wrapping in PageWebAppLogin is required by IdentityManager.Login(IRequest, IIdentity, SecureString) — the plain string is unavoidably in memory before wrapping due to how the form system works.
Original prompt

A dedicated logout page must be created to provide a clear and consistent user experience when terminating an authenticated session. This page must follow the structural and stylistic conventions established by PageWebAppLogin, including its layout, navigation behavior, and use of standardized WebExpress controls. After performing the logout operation, the page must present a concise confirmation message and offer a direct navigation path back to the login page.
In addition, a separate page must be implemented for situations where a user is authenticated but lacks the required permissions to access the requested resource. This page must also be modeled after PageWebAppLogin and must clearly communicate that access is denied due to insufficient privileges. It must provide contextual guidance, such as offering a link to switch accounts or return to a safe default location within the application.
If necessary, the IdentityProvider must be extended to support these flows, particularly to ensure that logout operations, permission checks, and state transitions are handled consistently across all authentication mechanisms.
Comprehensive unit tests must be added for both pages. These tests must verify correct rendering, proper interaction with the identity system, and the expected behavior when navigating to or from these pages. Tests must also ensure that permission‑related scenarios are handled deterministically and that the logout process reliably clears authentication state.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: using System.Collections.Generic;
using WebExpress.WebCore.WebIdentity;
using WebExpress.WebCore.WebMessage;

namespace WebExpress.WebApp.WebIdentity
{
///


/// Represents an external identity provider that supplies identities and groups
/// to the WebExpress identity system.
///

public abstract class IdentityProvider : IIdentityProvider
{
///
/// Returns all identities provided by this source.
///

public abstract IEnumerable GetIdentities();

    /// <summary>
    /// Returns all groups provided by this source.
    /// </summary>
    public abstract IEnumerable<IIdentityGroup> GetGroups();

    /// <summary>
    /// Authenticates the specified request and returns the associated identity.
    /// </summary>
    /// <param name="request">
    /// The request to authenticate. Cannot be null.
    /// </param>
    /// <returns>
    /// An identity representing the authenticated user if authentication is successful; otherwise, null.
    /// </returns>
    public IIdentity Authenticate(IRequest request)
    {
        implementiere basic autentification, token autentification
    }

    /// <summary>
    /// Displays a login dialog using the specified request and identity information.
    /// </summary>
    /// <param name="request">
    /// The request containing parameters and context for the login operation. Cannot be null.
    /// </param>
    /// <param name="identity">
    /// The identity information to be used for authentication. Cannot be null.
    /// </param>
    /// <returns>
    /// An object that represents the response to the login dialog, including authentication results and any
    /// relevant status information.
    /// </returns>
    IResponse CreateAuthenticationPrompt(IRequest request, IIdentity identity)
    {
        implementiere ein login dialog, das die benutzerinformationen anzeigt und die möglichkeit bietet, sich anzumelden oder abzubrechen
    }
}

}

Assistant: Um die Anforderungen an die Authentifizierung und den Login-Dialog in der abstrakten Klasse IdentityProvider umzusetzen, wird die Methode Authenticate so implementiert, dass sie den Autorisierungs-Header aus dem Request ausliest und mit der zuvor definierten Klasse RequestAuthorization parst. Je nach erkanntem Typ (Basic oder Token/Bearer) werden entsprechende abstrakte Validierungsmethoden aufgerufen, die von der ableitenden Klasse implementiert werden müssen, da die konkrete Prüfung von Passwörtern oder Tokens abhängig von der spezifischen Datenquelle ist.

Für die Methode CreateAuthenticationPrompt wird eine HTML-basierte Antwort generiert, die ein Login-Formular enthält. Wenn bereits eine Identität übergeben wird, kann deren Name im Formular vorausgefüllt werden. Das Formular verwendet reines Vanilla JavaScript, um die Eingaben zu verarbeiten oder den Vorgang abzubrechen.

Hier ist die vollständige und normgerechte Implementierung:

using System;
using System.Collections.Generic;
using System.Linq;
using WebExpress.WebCore.WebIdentity;
using WebExpress.WebCore.WebMessage;
using WebExpress.WebCore.WebMessage.Html; // Angenommener Namespace für HTML-Responses

namespace WebExpress.WebApp...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

Copilot AI changed the title [WIP] Create dedicated logout and access denied pages for user experience Add login, logout, and forbidden pages with identity provider base class Apr 14, 2026
Copilot AI requested a review from ReneSchwarzer April 14, 2026 18:10
@ReneSchwarzer ReneSchwarzer marked this pull request as ready for review April 14, 2026 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants