Skip to content

Identity Provider Configuration

Overview

Cesivi Server supports multiple authentication methods to fit different use cases, from simple development testing to production-grade enterprise deployments.

Available Providers: - AcceptAll - Zero-configuration default for development - OAuth2/OIDC - Modern JWT Bearer tokens for production - NTLM - Windows/Enterprise authentication - TrustedCaller - Identity delegation from trusted applications (WebUI) - ConfigUsers - Static config-defined Basic/Forms users for tests, demos, and E2E fixtures

All providers use a priority-based selection system - the server tries providers in order until one successfully authenticates the request.


Quick Comparison

Provider Best For Setup Complexity Use Cases
AcceptAll Development, Testing None Local development, unit tests, demos
OAuth2/OIDC Production, SPA, Mobile Medium Cloud apps, microservices, modern web apps
NTLM Enterprise, Legacy apps Low-Medium Desktop apps, intranet, SharePoint migrations
TrustedCaller WebUI, Service-to-Service Medium Identity delegation from trusted apps
ConfigUsers Tests, demos, E2E fixtures Low Named test users with predictable groups/permissions — never production

AcceptAll Provider (Default)

The simplest authentication mode - accepts all credentials without validation.

When to Use

  • Local development and testing
  • Automated tests (unit, integration)
  • Proof-of-concept demos
  • Internal sandboxes

Configuration

Enabled by default - no configuration needed!

{
  "Cesivi": {
    "Identity": {
      "Providers": {
        "AcceptAll": {
          "Enabled": true,
          "Priority": 1000,
          "DefaultUsername": "SHAREPOINT\\administrator"
        }
      }
    }
  }
}

Example Usage

// CSOM - any credentials work
var context = new ClientContext("http://localhost:5000");
context.Credentials = new NetworkCredential("user", "password");
# PnP PowerShell - any credentials work
Connect-PnPOnline -Url "http://localhost:5000" -Credentials (Get-Credential)

OAuth2/OIDC Provider

Modern authentication using JWT Bearer tokens from identity providers like Azure AD, Okta, Auth0, Keycloak.

When to Use

  • Production deployments
  • Single Page Applications (SPA)
  • Mobile apps
  • Microservices architectures
  • Multi-tenant scenarios

Quick Start

  1. Enable OAuth2 provider in appsettings.json
  2. Configure your identity provider (Azure AD, Okta, etc.)
  3. Get a token from your IdP
  4. Use Bearer token in requests
{
  "Cesivi": {
    "Identity": {
      "Providers": {
        "OAuth2": {
          "Enabled": true,
          "Priority": 50,
          "Authority": "https://login.microsoftonline.com/{tenant-id}/v2.0",
          "Audience": "api://cesivi"
        }
      }
    }
  }
}

Example Usage

# Get token from identity provider
TOKEN=$(curl ... get token ...)

# Use with Cesivi
curl http://localhost:5000/_api/web \
  -H "Authorization: Bearer $TOKEN"

See: OAuth2 Setup Guide for detailed configuration


NTLM Provider

Windows/Enterprise authentication with Type 1/2/3 challenge-response protocol.

When to Use

  • Enterprise environments with Active Directory
  • Desktop applications (SharePoint Designer, InfoPath)
  • Intranet scenarios
  • SharePoint migration projects
  • Compatibility with legacy tools

Quick Start

Three backends available: 1. Configuration-based - Define users in appsettings.json (default) 2. Active Directory - Authenticate against real AD via LDAP (✅ fully implemented) 3. Pure LDAP - OpenLDAP, 389 DS, FreeIPA, etc. (✅ fully implemented)

Configuration-Based Users

{
  "Cesivi": {
    "Identity": {
      "Providers": {
        "NTLM": {
          "Enabled": true,
          "Priority": 100,
          "Backend": "Configuration",
          "Configuration": {
            "Users": [
              {
                "Username": "testuser",
                "Domain": "CONTOSO",
                "Password": "Test@1234",
                "Email": "testuser@contoso.com",
                "DisplayName": "Test User"
              }
            ]
          }
        }
      }
    }
  }
}

Example Usage

// CSOM with NTLM
var context = new ClientContext("http://localhost:5000");
context.Credentials = new NetworkCredential("testuser", "Test@1234", "CONTOSO");

See: NTLM Setup Guide for detailed configuration


ConfigUsers Provider

⚠️ NEVER enable in production. Passwords are stored and compared in plaintext (a constant-time compare only guards against timing side channels — it does not add hashing, salting, rate-limiting, or lockout). This provider exists for tests, demos, and local dev fixtures where you need named, predictable users without standing up a real IDP.

A static, config-defined list of Basic + Forms users and (optionally nested) groups. Disabled by default (Enabled: false) — the server does not register the provider at all unless explicitly turned on.

When to Use

  • Playwright/E2E test fixtures that need stable usernames, groups, and permission levels
  • Local dev or demo environments where NTLM/OAuth2/SAML setup is overkill
  • Reproducing a specific group-membership shape (including nested groups) for a bug repro

Supported schemes

Basic and Forms only. Requests using NTLM, Bearer, Certificate, or Anonymous schemes are rejected (Fail) so this provider never shadows the dedicated provider for those schemes.

Quick Start

Config lives at Cesivi:Identity:Providers:ConfigUsers. Users and groups can be defined inline in appsettings.json, or in an external JSON file (set UsersFile, resolved relative to the app's content root) — external file wins over inline when both are set. This makes it easy to swap a fixture-users file per test environment without editing appsettings.

{
  "Cesivi": {
    "Identity": {
      "Providers": {
        "ConfigUsers": {
          "Enabled": true,
          "Priority": 75,
          "UsersFile": null,
          "Users": [
            {
              "Username": "alice",
              "Password": "s3cret",
              "DisplayName": "Alice Anderson",
              "Email": "alice@test.local",
              "Domain": "DOMAIN",
              "Groups": [ "Owners" ]
            },
            {
              "Username": "bob",
              "Password": "hunter2",
              "DisplayName": "Bob Baker",
              "Email": "bob@test.local",
              "Domain": "DOMAIN",
              "Groups": [ "Members" ]
            }
          ],
          "Groups": [
            { "Name": "Owners",  "DisplayName": "Site Owners" },
            { "Name": "Members", "DisplayName": "Site Members" }
          ]
        }
      }
    }
  }
}

Field reference:

Field Meaning
Enabled Master switch. false (default) means the provider isn't even registered.
Priority Default 75 — sits between OAuth2 (50) and NTLM (100), so a real Bearer/NTLM login still wins, but a Basic credential matching a config user beats AcceptAll (1000).
UsersFile Optional path to an external JSON file with the same Users/Groups shape. Wins over inline lists when set.
Users[].Domain Optional NT-style domain. When set, the login name (and SPUser LoginName) becomes DOMAIN\username; when empty, just username.
Users[].Groups Direct group memberships (by group Name). Transitive membership through nested groups is resolved at load time.
Groups[].Members A group's member list may reference users or other groups by name — the loader classifies each entry after loading. Nested groups resolve transitively.

Nested groups & cycle detection

Groups can contain other groups (e.g. AllStaff containing Owners and Members). The loader builds the full membership graph at startup and validates it's acyclic — a cyclic group definition (e.g. A contains B contains A) makes the server refuse to start, with the exact cycle path in the error. This is a fail-fast config error, not a runtime fallback.

Example Usage

# Basic auth against a ConfigUsers-defined user
curl -u "alice:s3cret" http://localhost:5000/_api/web
# PnP PowerShell with a ConfigUsers credential
$cred = Get-Credential  # username: alice, password: s3cret
Connect-CSOnline -Url http://localhost:5000 -Credentials $cred

Source: Cesivi.Common/Identity/Providers/ConfigUsers/ · sample config: Cesivi.Server/appsettings.json (Cesivi:Identity:Providers:ConfigUsers, disabled by default).


TrustedCaller Provider

Identity delegation for trusted applications like Cesivi WebUI. Allows a front-end application to authenticate users locally and pass that identity securely to SPM for authorization.

When to Use

  • Cesivi WebUI
  • Service-to-service authentication
  • Custom front-end applications
  • Scenarios requiring identity delegation

How It Works

  1. WebUI authenticates user (via its own login page)
  2. WebUI requests a challenge from SPM (/_spmock/trust/challenge)
  3. WebUI signs the challenge with its private key + user identity
  4. SPM validates signature using the trusted caller's public key
  5. SPM accepts delegated identity for authorization decisions

This certificate-based challenge-response protocol prevents replay attacks and ensures only trusted callers can delegate identities.

Quick Start

  1. Generate certificates using the provided script
  2. Configure WebUI with certificate path and password
  3. Configure SPM with certificate thumbprint
  4. Enable the trusted caller in SPM
# Generate certificates
cd Scripts
.\New-TrustCertificate.ps1

Configuration

SPM Server (appsettings.json):

{
  "Cesivi": {
    "TrustedCallers": [
      {
        "CallerId": "webui-001",
        "CertificateThumbprint": "<thumbprint from script>",
        "AllowedScopes": ["read", "write", "admin"],
        "Description": "Cesivi WebUI",
        "Enabled": true
      }
    ]
  }
}

WebUI (appsettings.json):

{
  "SpmClient": {
    "BaseUrl": "http://localhost:5000",
    "TrustCertificatePath": "certificates/webui-001.pfx",
    "TrustCertificatePassword": "<password from script>",
    "TrustedCallerId": "webui-001"
  }
}

Security Features

  • Challenge expiration: 5 minutes (prevents replay attacks)
  • Challenge single-use: Each challenge can only be used once
  • Identity timestamp: Delegated identity valid for 5 minutes
  • Certificate-based signing: RSA SHA256 signatures
  • Priority 10: Processed before other providers

See: WebUI Setup Guide for detailed configuration


Provider Priority

Cesivi tries providers in priority order (lower number = higher priority):

Priority Provider Why This Order?
10 TrustedCaller Highest - trusted apps with signed delegation
50 OAuth2/OIDC High specificity - only handles Bearer tokens
75 ConfigUsers Between OAuth2 and NTLM - a real Bearer/NTLM login still wins first
100 NTLM Medium specificity - handles NTLM/Negotiate
1000 AcceptAll Fallback - accepts everything

This ensures: - Trusted caller headers go to TrustedCaller provider (signed delegation) - Bearer tokens go to OAuth2 provider (JWT validation) - Config-defined Basic/Forms users go to ConfigUsers before falling through to NTLM/AcceptAll - NTLM requests go to NTLM provider (challenge-response) - Everything else falls back to AcceptAll (development mode)


Enabling Multiple Providers

You can enable multiple providers simultaneously. The server will try them in priority order:

{
  "Cesivi": {
    "Identity": {
      "Providers": {
        "OAuth2": {
          "Enabled": true,
          "Priority": 50
        },
        "NTLM": {
          "Enabled": true,
          "Priority": 100
        },
        "AcceptAll": {
          "Enabled": true,
          "Priority": 1000
        }
      }
    }
  }
}

Flow: 1. Request arrives with Bearer token → OAuth2 validates JWT 2. Request arrives with NTLM header → NTLM does challenge-response 3. Request arrives with Basic auth → Falls back to AcceptAll


Security Considerations

AcceptAll Provider

⚠️ NOT FOR PRODUCTION

  • Accepts any credentials without validation
  • No actual security
  • Use only for development/testing

OAuth2/OIDC Provider

✅ Production Ready

  • Full JWT signature validation
  • Token expiration checking
  • Issuer and audience validation
  • Configurable clock skew (default: 5 minutes)

Best Practices: - Use HTTPS in production - Rotate signing keys regularly - Set appropriate token lifetimes - Validate audience claims

NTLM Provider

✅ Production Ready (with AD backend)

  • Full challenge-response protocol
  • Configuration mode: Passwords stored in appsettings (⚠️ secure your config!)
  • AD/LDAP mode: Delegates to Active Directory

Best Practices: - Use encrypted configuration (User Secrets, Azure Key Vault) - Enable SSL/TLS for LDAP connections - Use service accounts with minimal privileges


Troubleshooting

"Authentication failed" with OAuth2

Check: 1. Token is not expired (exp claim) 2. Audience matches configuration (aud claim) 3. Issuer matches configuration (iss claim) 4. OIDC discovery URL is accessible ({Authority}/.well-known/openid-configuration)

Solution: Enable debug logging to see JWT validation errors

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

"NTLM authentication failed"

Check: 1. Username/password correct in configuration 2. Domain name matches exactly (case-sensitive) 3. NTLM provider enabled

Solution: Check logs for detailed NTLM negotiation steps

"All providers rejected request"

Check: 1. At least one provider is enabled 2. AcceptAll is enabled as fallback 3. Authorization header is present

Solution: Enable AcceptAll as fallback during development


Migration Guide

From AcceptAll to OAuth2

  1. Set up your identity provider (Azure AD, Okta, etc.)
  2. Enable OAuth2 in appsettings.json with your configuration
  3. Keep AcceptAll enabled initially (for testing)
  4. Test OAuth2 authentication with real tokens
  5. Disable AcceptAll once OAuth2 is working

From AcceptAll to NTLM

  1. Define users in configuration or set up AD/LDAP backend
  2. Enable NTLM in appsettings.json
  3. Keep AcceptAll enabled initially (for testing)
  4. Test NTLM authentication with valid credentials
  5. Disable AcceptAll once NTLM is working

Advanced Configuration

Custom Priorities

You can change provider priorities to control the order:

{
  "Cesivi": {
    "Identity": {
      "Providers": {
        "NTLM": {
          "Priority": 10
        },
        "OAuth2": {
          "Priority": 20
        },
        "AcceptAll": {
          "Priority": 1000
        }
      }
    }
  }
}

Disabling Providers

Set "Enabled": false to disable a provider:

{
  "Cesivi": {
    "Identity": {
      "Providers": {
        "AcceptAll": {
          "Enabled": false
        }
      }
    }
  }
}

See Also