refactor(mail): send via the SSO app registration, drop SMTP basic auth
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m25s
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m25s
Mail now uses the same Entra ID app registration as "Sign in with Microsoft" (ENTRA_TENANT_ID, ENTRA_CLIENT_ID, ENTRA_CLIENT_SECRET), so only one enterprise application is needed. The app additionally gets the SMTP.SendAsApp permission; Exchange still limits it to the mailbox granted via Add-MailboxPermission. Password (basic auth) sending is removed entirely: SMTP_HOST, SMTP_PORT, SMTP_PASSWORD and the separate SMTP_OAUTH_* settings are gone. The transport is fixed to smtp.office365.com:587 with required STARTTLS. SMTP_USER (sending mailbox) and SMTP_FROM remain. - lib/entra.ts exposes readEntraAppCredentials(), shared by SSO and mail - diagnosis drops basic-auth-only causes; hints name the ENTRA_* values and warn that an expired secret breaks sign-in and mail together - admin e-mail test, .env.example, docker-compose, k8s manifests, preflight and README updated Verified against Entra ID with fake values: token error classified, client secret never exposed, missing ENTRA_CLIENT_SECRET reported. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
0620e9d79a
commit
11910dd6dd
15 files changed
+211
-309
No files matched your search
+25
-5
@@ -46,15 +46,35 @@ interface EntraConfig {
|
||||
redirectUri: string;
|
||||
}
|
||||
|
||||
export interface EntraAppCredentials {
|
||||
tenantId: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zugangsdaten der EINEN App-Registrierung in Entra ID. Sie dient zwei
|
||||
* Zwecken: der Anmeldung "Mit Microsoft anmelden" (dieses Modul) und dem
|
||||
* Mailversand ueber Microsoft 365 per OAuth 2.0 (lib/mail.ts, Berechtigung
|
||||
* SMTP.SendAsApp) — eine Unternehmensanwendung statt zwei. Beim Secret wird
|
||||
* nur ein Zeilenumbruch am Ende entfernt (typischer Fehler beim Anlegen des
|
||||
* Kubernetes-Secrets), sonstige Werte werden getrimmt. null, wenn etwas fehlt.
|
||||
*/
|
||||
export function readEntraAppCredentials(): EntraAppCredentials | null {
|
||||
const tenantId = process.env.ENTRA_TENANT_ID?.trim() ?? "";
|
||||
const clientId = process.env.ENTRA_CLIENT_ID?.trim() ?? "";
|
||||
const clientSecret = process.env.ENTRA_CLIENT_SECRET?.replace(/[\r\n]+$/, "") ?? "";
|
||||
if (!tenantId || !clientId || !clientSecret) return null;
|
||||
return { tenantId, clientId, clientSecret };
|
||||
}
|
||||
|
||||
function getEntraConfig(): EntraConfig {
|
||||
const tenantId = process.env.ENTRA_TENANT_ID;
|
||||
const clientId = process.env.ENTRA_CLIENT_ID;
|
||||
const clientSecret = process.env.ENTRA_CLIENT_SECRET;
|
||||
const credentials = readEntraAppCredentials();
|
||||
const redirectUri = process.env.ENTRA_REDIRECT_URI;
|
||||
if (!tenantId || !clientId || !clientSecret || !redirectUri) {
|
||||
if (!credentials || !redirectUri) {
|
||||
throw new EntraNotConfiguredError();
|
||||
}
|
||||
return { tenantId, clientId, clientSecret, redirectUri };
|
||||
return { ...credentials, redirectUri };
|
||||
}
|
||||
|
||||
/** Fuer die bedingte Anzeige des "Mit Microsoft anmelden"-Buttons im Login-UI. */
|
||||
|
||||
Reference in new issue
Block a user