Skip to content

v2.4.8

Choose a tag to compare

@github-actions github-actions released this 24 May 21:32

v2.4.8 — Bug fix: SMTP port 465 + OIDC userinfo claim merge

Fixes #29 reported by @e64462 on an Authelia + Gmail SMTP setup.

What broke

SMTP test email over port 465 silently failed, no email sent and no useful log. System.Net.Mail.SmtpClient.EnableSsl=true triggers STARTTLS rather than Implicit TLS — port 465 expects an SSL ClientHello before any SMTP commands, so the plaintext EHLO hits a server waiting for crypto and the connection drops.

OIDC sign-in via Authelia rejected users as "not part of allowed groups" even when groups was in the scope list. The plugin only read claims from the id_token JWT, but Authelia (default config), Keycloak (most realms), and Authentik emit groups/email/email_verified only at the /userinfo endpoint. claims.Groups was therefore empty regardless of requested scopes, and the AllowedGroups allowlist rejected every user.

Fix

SMTP: migrated EmailOtpService from System.Net.Mail.SmtpClient to MailKit. New PickSocketOptions helper maps port → SecureSocketOptions:

  • 465 → SslOnConnect (Implicit TLS / SMTPS)
  • 587 → StartTls
  • other ports + UseSsl=true → StartTlsWhenAvailable
  • UseSsl=false → None (opt-in plaintext for local dev)

OIDC: OidcService.CompleteAsync now fetches /userinfo with the access_token after id_token verification and merges any groups, roles, email, email_verified, and username claims into the bundle before the AllowedGroups check and ResolveUserAsync. New internal helper ExtractClaimsFromUserInfo handles JSON-array AND comma-separated-string group formats, plus parses email_verified as bool or string. Userinfo fetch is best-effort — failure falls through to id_token-only behaviour with debug log.

Implementation

  • Adds MailKit 4.16.0 + transitive MimeKit + BouncyCastle.Cryptography to the fat package (~7.2MB total). build.sh, build.ps1, meta.json Assemblies[] all updated.
  • 11 new regression tests:
    • SmtpSocketOptionsTests (5 cases) pin port→SocketOptions mapping including the load-bearing port-465 → SslOnConnect case
    • OidcUserInfoExtractionTests (6 cases) cover groups-as-JSON-array, groups-as-CSV, groups+roles merge, missing claims, non-object root, empty/whitespace filtering

Validated end-to-end

  • Gmail smtp.gmail.com:465 (the canonical Implicit-TLS SMTPS server) sends test email successfully. Pre-v2.4.8 this is the exact failure mode reported.
  • Authelia 4.39 OIDC sign-in with AllowedGroups=jellyfin-users succeeds. The old "Account is not in an allowed group" error is gone; the userinfo merge correctly retrieves the group. Same IdP family the reporter uses.

166/166 tests pass. Build clean with TreatWarningsAsErrors=true.

Upgrade

In-place upgrade. No config changes. Users on Authelia / Keycloak / Authentik / any IdP that emits groups at /userinfo will find their OIDC allowlists actually work. Users on Gmail / Outlook365 / Mailgun port-465 SMTP will find their test emails actually send.

Verify the release

cosign verify-blob \
  --certificate Jellyfin.Plugin.TwoFactorAuthv2.4.8.0.zip.pem \
  --signature Jellyfin.Plugin.TwoFactorAuthv2.4.8.0.zip.sig \
  --certificate-identity-regexp 'https://github.com/ZL154/JellyfinSecurity/.+' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  Jellyfin.Plugin.TwoFactorAuthv2.4.8.0.zip

SLSA build provenance: Jellyfin.Plugin.TwoFactorAuthv2.4.8.0.zip.intoto.jsonl — verify with gh attestation verify --owner ZL154 Jellyfin.Plugin.TwoFactorAuthv2.4.8.0.zip.