Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhanced Digest Authentication, JWT Authentication, Certificate Management & RFC Compliance #1470

Open
wants to merge 72 commits into
base: develop
Choose a base branch
from

Conversation

mdaneri
Copy link
Contributor

@mdaneri mdaneri commented Jan 29, 2025

Overview

This pull request improves Pode’s authentication mechanisms by ensuring RFC compliance, fixing WWW-Authenticate headers on authentication failures, and improving request handling. Additionally, it enhances JWT authentication by supporting full RFC 7518 compliance and adds private key support for RSA and ECDSA algorithms. It also introduces support for bearer tokens in query parameters, following RFC 6750.

Furthermore, this update adds new certificate management functions to enhance Pode's ability to generate, import, and manage certificates. These new functions allow better control over X.509 certificates, making it easier to secure endpoints, implement JWT authentication, and enforce certificate purposes.

Key Enhancements & Fixes

New Certificate Management Functions

  • Introduces New-PodeCertificateRequest, allowing users to generate Certificate Signing Requests (CSRs) for obtaining valid CA-signed certificates.
  • Adds New-PodeSelfSignedCertificate, which enables the creation of self-signed certificates with RSA or ECDSA keys for development and testing.
  • Implements Import-PodeCertificate for importing X.509 certificates from PFX, PEM, or the Windows certificate store.
  • Supports Export-PodeCertificate, allowing certificates to be exported as PFX, PEM, or CER files with optional private key protection.
  • Adds Get-PodeCertificatePurpose, which retrieves the Enhanced Key Usage (EKU) attributes of a certificate, ensuring certificates are used correctly (e.g., ServerAuth, ClientAuth, CodeSigning).
  • Improves endpoint certificate enforcement by rejecting certificates that do not match the expected EKU (e.g., requiring ServerAuth for HTTPS endpoints).
  • Allows easy binding of certificates to endpoints and authentication schemes, ensuring seamless integration with Pode’s security mechanisms.

JWT Authentication Updates (RFC 7518 Compliance)

  • Full support for RFC 7518, expanding supported JWT algorithms:
    • NONE, HS256, HS384, HS512 (HMAC)
    • RS256, RS384, RS512 (RSA)
    • PS256, PS384, PS512 (RSA-PSS)
    • ES256, ES384, ES512 (ECDSA)
  • New -PrivateKey parameter in New-PodeAuthScheme for RSA and ECDSA verification.
  • Ensures JWT signature verification follows RFC 7518 standards.
  • Improved JWT validation, including better error handling for expired or malformed tokens.
  • Support for generating signed tokens that match an existing authentication scheme by using ConvertTo-PodeJwt -Authentication <Name>. Pode automatically applies the named scheme’s secret/certificate/algorithm to create a token. This keeps token generation and verification consistent.
  • Support JWT extension using Update-PodeJwt
  • ConvertFrom-PodeJwt and Update-PodeJwt don't need any parameters when used inside an authenticated route

Bearer Token Support in Query Parameters (RFC 6750 Compliance)

  • Pode now supports passing bearer tokens via query parameters in addition to the Authorization header.
  • Example:
    GET /protected-resource?access_token=<jwt>
    
  • Security Note: Query parameter usage is not recommended unless necessary, as tokens may be logged in URLs. The Authorization header remains the preferred method.
  • Body-based token transmission (RFC 6750 Section 2.2) is supported.

Digest Authentication Updates (RFC 7616 Compliance)

  • Support for multiple algorithms: MD5, SHA-1, SHA-256, SHA-384, SHA-512, and SHA-512/256.
  • Quality of Protection (qop) enhancements: Implements auth-int to include message integrity verification.
  • Algorithm negotiation: Allows clients to select the strongest supported algorithm.
  • Fixes WWW-Authenticate header: Ensures the WWW-Authenticate header is always returned on authentication failure, per RFC 7616.

Fixes to WWW-Authenticate Header for All Authentication Methods

This update ensures that the WWW-Authenticate header is correctly returned when authentication fails, adhering to RFC standards:

  • Basic Authentication (RFC 7617): Ensures WWW-Authenticate: Basic realm="ExampleRealm" is included.
  • Bearer Authentication (RFC 6750): Returns WWW-Authenticate: Bearer error="invalid_token" when authentication fails.
  • Client Certificate Authentication (RFC 5246): Ensures proper handling for TLS mutual authentication failures.
  • Form Authentication: Ensures WWW-Authenticate consistency on failed login attempts.
  • Digest Authentication (RFC 7616): Correctly formats WWW-Authenticate, even when authentication fails.

New $WebEvent.RawData Field

  • Introduces $WebEvent.RawData, which captures the raw request body before parsing.
  • Enables auth-int in Digest Authentication and custom authentication mechanisms.

Windows-Specific Limitations

  • Windows' built-in Digest authentication only supports MD5.
  • auth-int is not supported natively.
  • Windows fails if multiple algorithms are listed in WWW-Authenticate.
  • These features can still be implemented manually; see examples/Utilities/DigestClient.ps1 for reference.

Example Usage

Example: JWT Authentication with RSA

$privateKey = Get-Content 'C:\\path\\to\\private-key.pem' -Raw | ConvertTo-SecureString -AsPlainText -Force

New-PodeAuthScheme -Bearer -AsJWT -PrivateKey $privateKey | Add-PodeAuth -Name 'ExampleJWT' -Sessionless -ScriptBlock {
    param($payload)
    Write-Output "Authenticated user: $($payload.sub)"
}

Example: Bearer Token in Query Parameter

New-PodeAuthScheme -Bearer -BearerLocation Query | Add-PodeAuth -Name 'ExampleQuery' -Sessionless -ScriptBlock {
    param($payload)
    Write-Output "Authenticated user: $($payload.sub)"
}
GET /protected-resource?access_token=eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE2MjI1NTMyMTQsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMyJ9.LP-O8OKwix91a-SZwVK35gEClLZQmsORbW0un2Z4RkY

Recommended Alternative:

Authorization: Bearer <jwt>

Example: Digest Authentication with SHA-256 and auth-int

$uri = "http://localhost:8081/users"
$username = "morty"
$password = "pickle"

$authScheme = New-PodeAuthScheme -Digest -Algorithm "SHA-256" -QualityOfProtection "auth-int"
Start-PodeServer -Auth $authScheme

Additional JWT Generation Example
Here’s a quick example of generating a signed JWT that aligns with an existing RSA-based scheme (i.e., ExampleJWT) using ConvertTo-PodeJwt -Authentication in a login route:

Add-PodeRoute -Method Post -Path '/user/login' -ScriptBlock {
    param()

    # Example credentials check
    $username = $WebEvent.Data['username']
    $password = $WebEvent.Data['password']
    # If valid, generate the token:
    $jwt = ConvertTo-PodeJwt -Authentication 'ExampleJWT'

    Write-PodeJsonResponse -StatusCode 200 -Value @{ jwt_token = $jwt }
}

Example: Generating a CSR and Importing a Signed Certificate

$csr = New-PodeCertificateRequest -DnsName "example.com" -CommonName "example.com" -KeyType "RSA" -KeyLength 2048
# Submit the generated CSR to a CA and obtain a signed certificate.
																											  

$cert = Import-PodeCertificate -FilePath "C:\Certs\signed-cert.pfx" -CertificatePassword (ConvertTo-SecureString "MyPass" -AsPlainText -Force")

Example: Creating a Self-Signed Certificate and Using It for HTTPS

$cert = New-PodeSelfSignedCertificate -DnsName "example.com" -CertificatePurpose ServerAuth

Start-PodeServer {
    Add-PodeEndpoint -Address * -Port 8443 -Protocol Https -X509Certificate $cert
													  
}

Example: JWT Authentication with RSA

$privateKey = Get-Content 'C:\\path\\to\\private-key.pem' -Raw | ConvertTo-SecureString -AsPlainText -Force

New-PodeAuthScheme -Bearer -AsJWT -PrivateKey $privateKey | Add-PodeAuth -Name 'ExampleJWT' -Sessionless -ScriptBlock {

																												
    param($payload)
    Write-Output "Authenticated user: $($payload.sub)"
}

Example: Checking Certificate Purpose

$purposes = Get-PodeCertificatePurpose -Certificate $cert
$purposes
								  

Example: Exporting a Certificate as PFX

Export-PodeCertificate -Certificate $cert -FilePath "C:\Certs\mycert" -Format "PFX" -CertificatePassword (ConvertTo-SecureString "MyPass" -AsPlainText -Force)

Testing

  • Verified compliance with RFC 7518, 7616, 7617, 6750, and 5246.
  • Tested JWT authentication with HMAC, RSA, and ECDSA signatures.
  • Verified bearer tokens work in both Authorization headers and query parameters.
  • Tested Digest Authentication with auth and auth-int modes.
  • Confirmed WWW-Authenticate is always present on authentication failure.
  • Ensured $WebEvent.RawData correctly captures raw request body content.

References


PR Links:

Note on .NET 9 Issue and Reflection Workaround

This pull request includes a reflection-based workaround to access the RSA KeySize from System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPrivateKey on Linux, due to an existing issue in .NET 9 where the KeySize property is currently write-only.

The issue has been reported to the .NET team here:
dotnet/runtime#112622
and Powershell team:
PowerShell/PowerShell#25038

Once the issue is resolved, this workaround can be revisited and potentially replaced with the official fix for improved maintainability and performance.

@mdaneri mdaneri marked this pull request as draft January 29, 2025 17:02
@mdaneri mdaneri changed the title RFC-7616 compliance Enhanced Digest Authentication Support Jan 30, 2025
@mdaneri mdaneri changed the title Enhanced Digest Authentication Support Enhanced Authentication & RFC Compliance Jan 30, 2025
@mdaneri mdaneri changed the title Enhanced Authentication & RFC Compliance 🔐 **Enhanced Authentication & RFC Compliance** Jan 30, 2025
@mdaneri mdaneri changed the title 🔐 **Enhanced Authentication & RFC Compliance** Enhanced Authentication & RFC Compliance Jan 30, 2025
@mdaneri mdaneri marked this pull request as ready for review January 30, 2025 18:31
@mdaneri mdaneri changed the title Enhanced Authentication & RFC Compliance Enhanced Digest Authentication & RFC Compliance Jan 31, 2025
@mdaneri mdaneri changed the title Enhanced Digest Authentication & RFC Compliance Enhanced Digest Authentication, JWT & RFC Compliance Feb 8, 2025
mdaneri and others added 13 commits February 8, 2025 10:16
…ery Support

- Added full support for RFC 7518 JWT algorithms: NONE, HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512.
- Introduced `-PrivateKey` parameter in `New-PodeAuthScheme` for RSA and ECDSA JWT signature verification.
- Ensured JWT signature validation follows RFC 7518 standards.
- Improved JWT validation for `exp` (expiration) and `nbf` (not before) claims.
- Added support for passing Bearer tokens via query parameters (`-BearerLocation Query`) as per RFC 6750.
- Updated `WWW-Authenticate` handling to correctly return headers on authentication failures for all authentication methods.
- Ensured Pode authentication mechanisms align with industry security standards.
- Updated documentation to reflect these enhancements.
remove Invoke-PodeJWTSign
merge Invoke-PodeJWTSign in New-PodeJwtSignature
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: high Target for next release or soon after. A priority but not critical
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants