Skip to content

Cesivi WebUI Setup Guide

Overview

Cesivi WebUI is a web-based administration interface for managing Cesivi Server. This guide covers deployment, configuration, and setting up the trust relationship between WebUI and SPM.

Key Features: - Browse site collections, webs, lists, and libraries - View and manage list items and documents - User authentication with identity delegation to SPM - Modern Razor Pages UI with Bootstrap styling


Prerequisites

  • .NET 10 SDK (or later)
  • Cesivi Server running and accessible
  • PowerShell 5.1+ (for certificate generation on Windows)

Quick Start (Development)

For local development without trust configuration (SPM uses AcceptAll provider):

# Start SPM Server (terminal 1)
cd Cesivi.Server
dotnet run

# Start WebUI (terminal 2)
cd Cesivi.WebUI
dotnet run

URLs: - SPM Server: http://localhost:5000 - WebUI: http://localhost:5050

In development mode with AcceptAll provider, WebUI works without trust configuration.


Production Setup with Identity Delegation

For production use, configure certificate-based trust so WebUI-authenticated users are properly authorized in SPM.

Architecture Overview

┌─────────────────────────────────────────────────────────────────────┐
│                        WebUI (localhost:5050)                       │
│  ┌─────────────┐    ┌─────────────────┐    ┌───────────────────┐   │
│  │ Login Page  │───>│ Cookie Auth     │───>│ TrustHeaderHandler│   │
│  │             │    │ (ASP.NET Core)  │    │ (signs requests)  │   │
│  └─────────────┘    └─────────────────┘    └─────────┬─────────┘   │
└─────────────────────────────────────────────────────────│───────────┘
                                                          │
                  HTTP + Trust Headers                    │
                  (X-SPMock-Caller-Id, etc.)              │
                                                          ▼
┌─────────────────────────────────────────────────────────────────────┐
│                        SPM Server (localhost:5000)                  │
│  ┌─────────────────────┐    ┌─────────────────────────────────┐    │
│  │ TrustChallengeCtrl  │    │ TrustedCallerIdentityProvider   │    │
│  │ (issues challenges) │    │ (validates signatures)          │    │
│  └─────────────────────┘    └─────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────────┘

Step 1: Generate Trust Certificates

Run the certificate generation script:

cd Scripts
.\New-TrustCertificate.ps1

Output:

Generated password: xY7kM2nP9qR4sT1vW3zA5bC8
IMPORTANT: Save this password - you'll need it in appsettings.json

Creating self-signed certificate...
  Subject: CN=Cesivi.WebUI Trust (webui-001)
  Caller ID: webui-001
  Valid: 10 years

Certificate created successfully!
  Thumbprint: A1B2C3D4E5F6...

Exported PFX (private key): ..\certificates\webui-001.pfx
Exported CER (public key): ..\certificates\webui-001.cer

Save the password and thumbprint! You'll need them for configuration.

Custom Caller ID

For multiple WebUI instances or environments:

# Production WebUI
.\New-TrustCertificate.ps1 -CallerId "webui-prod"

# Staging WebUI
.\New-TrustCertificate.ps1 -CallerId "webui-staging"

# With custom password
.\New-TrustCertificate.ps1 -CallerId "webui-001" -Password "MySecurePassword123!"

Step 2: Configure SPM Server

Edit Cesivi.Server/appsettings.json:

{
  "Cesivi": {
    "TrustedCallers": [
      {
        "CallerId": "webui-001",
        "CertificateThumbprint": "A1B2C3D4E5F6...",
        "AllowedScopes": ["read", "write", "admin"],
        "Description": "Cesivi WebUI",
        "Enabled": true
      }
    ]
  }
}

Configuration Options:

Property Required Description
CallerId Yes Unique identifier matching WebUI configuration
CertificateThumbprint Yes Thumbprint from certificate generation script
AllowedScopes No Permissions: read, write, admin (default: ["read"])
Description No Human-readable description
Enabled No Enable/disable this trusted caller (default: true)

Install Public Key Certificate

The SPM server needs access to the public key to validate signatures:

# Option 1: Install to certificate store (recommended for production)
Import-Certificate -FilePath "certificates\webui-001.cer" `
  -CertStoreLocation "Cert:\LocalMachine\TrustedPeople"

# Option 2: Certificate file path (simpler for development)
# Just ensure the .cer file is accessible to SPM

Step 3: Configure WebUI

Edit Cesivi.WebUI/appsettings.json:

{
  "SpmClient": {
    "BaseUrl": "http://localhost:5000",
    "TimeoutSeconds": 30,
    "RetryCount": 3,
    "TrustCertificatePath": "certificates/webui-001.pfx",
    "TrustCertificatePassword": "xY7kM2nP9qR4sT1vW3zA5bC8",
    "TrustedCallerId": "webui-001"
  }
}

Configuration Options:

Property Required Description
BaseUrl Yes SPM Server URL
TimeoutSeconds No HTTP request timeout (default: 30)
RetryCount No Number of retry attempts (default: 3)
TrustCertificatePath Yes* Path to PFX file with private key
TrustCertificatePassword Yes* Password for PFX file
TrustedCallerId Yes* Must match SPM TrustedCallers.CallerId

*Required for identity delegation

Step 4: Start Services

# Terminal 1: Start SPM Server
cd Cesivi.Server
dotnet run

# Terminal 2: Start WebUI
cd Cesivi.WebUI
dotnet run

Step 5: Test the Configuration

  1. Navigate to WebUI: http://localhost:5050
  2. Login: Enter any username/password (demo mode accepts all)
  3. Browse: Navigate to site collections, lists, etc.
  4. Verify: Check SPM logs for authenticated user

SPM Server Log (successful delegation):

info: Cesivi.Common.Identity[0]
      TrustedCaller authentication: webui-001 delegating identity for user 'testuser'


WebUI Authentication

WebUI uses ASP.NET Core Cookie Authentication for user sessions.

Login Page

  • URL: /Account/Login
  • Demo Mode: Accepts any username/password
  • Session Duration: 8 hours (sliding expiration)

Configuring Real Authentication

For production, replace the demo login with real authentication:

Option 1: Active Directory / LDAP

// In Program.cs, replace the demo login logic with LDAP validation
// See: https://docs.microsoft.com/en-us/aspnet/core/security/authentication

Option 2: Azure AD / OIDC

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
    options.Authority = "https://login.microsoftonline.com/{tenant-id}/v2.0";
    options.ClientId = "{client-id}";
    // ... additional configuration
});

Security Considerations

Certificate Security

  1. Never commit PFX files to source control
  2. The .gitignore in certificates/ excludes *.pfx
  3. Only .cer files (public keys) are safe to commit

  4. Secure password storage

  5. Use environment variables: $env:WEBUI_CERT_PASSWORD
  6. Use Azure Key Vault or similar secrets manager
  7. Never hardcode passwords in appsettings.json for production

  8. Certificate rotation

  9. Certificates are valid for 10 years
  10. Plan for rotation before expiration
  11. Add new certificate to SPM before removing old one

Challenge-Response Security

  • 5-minute expiration: Challenges expire quickly to prevent replay
  • Single-use: Each challenge can only be used once
  • Nonce: 32-byte cryptographically random value
  • Signed identity: User identity included in signature

Network Security

  • Use HTTPS in production for both WebUI and SPM
  • Firewall rules: Limit access to SPM's trust endpoint
  • Reverse proxy: Use nginx/IIS for SSL termination

Configuration Reference

WebUI appsettings.json (Complete)

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "SpmClient": {
    "BaseUrl": "http://localhost:5000",
    "TimeoutSeconds": 30,
    "RetryCount": 3,
    "TrustCertificatePath": "certificates/webui-001.pfx",
    "TrustCertificatePassword": "",
    "TrustedCallerId": "webui-001"
  },
  "WebUI": {
    "Theme": "default",
    "PageSize": 25,
    "EnableFilePreview": true,
    "LogPath": ""
  },
  "Authentication": {
    "ExpireTimeSpanHours": 8,
    "SlidingExpiration": true
  }
}

SPM appsettings.json (TrustedCallers Section)

{
  "Cesivi": {
    "TrustedCallers": [
      {
        "CallerId": "webui-001",
        "CertificateThumbprint": "",
        "AllowedScopes": ["read", "write", "admin"],
        "Description": "Cesivi WebUI",
        "Enabled": true
      },
      {
        "CallerId": "webui-staging",
        "CertificateThumbprint": "",
        "AllowedScopes": ["read"],
        "Description": "Staging WebUI (read-only)",
        "Enabled": true
      }
    ]
  }
}

Environment Variables

WebUI supports WEBUI_* environment variables that override configuration:

Env Variable Config Key Description
WEBUI_SPM_URL SpmClient:BaseUrl SPM server URL
WEBUI_SPM_TIMEOUT SpmClient:TimeoutSeconds Request timeout
WEBUI_RETRY_COUNT SpmClient:RetryCount Retry attempts
WEBUI_CERT_PATH SpmClient:TrustCertificatePath Certificate file
WEBUI_CERT_PASSWORD SpmClient:TrustCertificatePassword Certificate password
WEBUI_CALLER_ID SpmClient:TrustedCallerId Trusted caller ID
WEBUI_LOG_PATH WebUI:LogPath Log file path
WEBUI_THEME WebUI:Theme UI theme
WEBUI_PAGE_SIZE WebUI:PageSize Items per page

Example:

# Set environment variables
$env:WEBUI_SPM_URL = "https://spm.example.com"
$env:WEBUI_CERT_PASSWORD = "secret"

# Start WebUI
dotnet run

Custom Configuration File

WebUI supports custom configuration files (same pattern as SPM Server):

# Use custom config file
dotnet run --config myconfig.json

# Config priority modes
dotnet run --config myconfig.json --config-priority default      # Custom between appsettings and env vars
dotnet run --config myconfig.json --config-priority env-first    # Env vars first, then custom config
dotnet run --config myconfig.json --config-priority force-config # Custom config overrides everything

Configuration Load Order (default mode): 1. appsettings.json (base) 2. appsettings.{Environment}.json (environment-specific) 3. Custom config file (--config) 4. Environment variables (WEBUI_*) 5. Command line arguments


Troubleshooting

"Trust validation failed"

Symptoms: WebUI requests fail with 401 Unauthorized

Check: 1. TrustedCallerId matches in both WebUI and SPM config 2. CertificateThumbprint in SPM matches the certificate 3. Enabled: true in SPM TrustedCallers 4. Certificate file exists and password is correct

Debug: Enable detailed logging in SPM:

{
  "Logging": {
    "LogLevel": {
      "Cesivi.Common.Identity": "Debug"
    }
  }
}

"Challenge expired"

Symptoms: Intermittent authentication failures

Cause: Challenge older than 5 minutes

Solution: This shouldn't happen normally as WebUI refreshes challenges at 80% lifetime (4 minutes). Check for: - Clock sync issues between WebUI and SPM servers - Network latency causing delays

"Certificate not found"

Symptoms: WebUI fails to start or sign requests

Check: 1. TrustCertificatePath is correct (relative to WebUI project) 2. File exists and is readable 3. Password is correct

"Identity delegation not working"

Symptoms: All requests appear as anonymous in SPM

Check: 1. Trust configuration is complete (both WebUI and SPM) 2. User is logged into WebUI (check cookie) 3. TrustHeaderHandler is registered in HttpClient pipeline

Debug: Check WebUI logs for TrustHeaderHandler activity:

{
  "Logging": {
    "LogLevel": {
      "Cesivi.WebUI.Services": "Debug"
    }
  }
}

Advanced Topics

Multiple WebUI Instances

For high availability or different environments:

// SPM appsettings.json
{
  "Cesivi": {
    "TrustedCallers": [
      {
        "CallerId": "webui-prod-1",
        "CertificateThumbprint": "AAA...",
        "AllowedScopes": ["read", "write", "admin"],
        "Enabled": true
      },
      {
        "CallerId": "webui-prod-2",
        "CertificateThumbprint": "BBB...",
        "AllowedScopes": ["read", "write", "admin"],
        "Enabled": true
      }
    ]
  }
}

Scope-Based Authorization

Limit what trusted callers can do:

{
  "TrustedCallers": [
    {
      "CallerId": "readonly-dashboard",
      "AllowedScopes": ["read"],
      "Description": "Read-only monitoring dashboard"
    },
    {
      "CallerId": "admin-portal",
      "AllowedScopes": ["read", "write", "admin"],
      "Description": "Full admin access"
    }
  ]
}

Custom Trust Handler

For service-to-service scenarios without user context:

// Register with service identity instead of user identity
public class ServiceTrustHeaderHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        // Add service identity instead of user identity
        var serviceIdentity = new DelegatedIdentity
        {
            Username = "SYSTEM\\ServiceAccount",
            // ...
        };
        // Sign and add headers
        return await base.SendAsync(request, cancellationToken);
    }
}

See Also