using System; using System.Net.Http; using System.Text; namespace Deploymentcenter.Client { /// /// Zugangsdaten fuer die Release-Ablage. /// /// Die Verzeichnisse unter /releases/ liegen hinter HTTP-Basic-Auth. Wer /// herunterladen darf, entscheidet der Lizenzschluessel: Eine Anwendung /// mit gueltiger Lizenz versorgt sich damit selbst weiter, ohne dass /// zusaetzliche Geheimnisse verteilt werden muessten. Zuvor war die Ablage /// offen - und damit auch fuer jeden im Internet herunterladbar. /// /// Bei einer Erstinstallation gibt es noch keinen Schluessel; dort treten /// die Zugangsdaten des Installationskontos an seine Stelle. /// public sealed class ReleaseCredentials { private ReleaseCredentials(string user, string password) { User = user; Password = password; } public string User { get; } public string Password { get; } /// /// Zugang ueber den Lizenzschluessel. /// /// Benutzername und Passwort sind beide der Schluessel: Basic Auth /// verlangt zwei Felder, es gibt aber nur ein Geheimnis, und /// Benutzernamen muessen innerhalb einer .htpasswd eindeutig sein. /// public static ReleaseCredentials? FromLicenseKey(string? licenseKey) { string key = (licenseKey ?? string.Empty).Trim(); return key.Length == 0 ? null : new ReleaseCredentials(key, key); } /// Zugang ueber ein Installationskonto. public static ReleaseCredentials? FromUser(string? user, string? password) { string u = (user ?? string.Empty).Trim(); string p = password ?? string.Empty; return u.Length == 0 ? null : new ReleaseCredentials(u, p); } /// Wert fuer den Authorization-Header. public string ToHeaderValue() { string raw = User + ":" + Password; return "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(raw)); } /// /// Haengt den Header an eine Anfrage. Ohne Zugangsdaten passiert /// nichts - eine noch ungeschuetzte Ablage bleibt damit erreichbar. /// public static void Apply(HttpRequestMessage request, ReleaseCredentials? credentials) { if (credentials == null || request == null) return; // Nicht doppelt setzen, falls der Aufrufer schon etwas mitgibt. if (request.Headers.Contains("Authorization")) return; request.Headers.TryAddWithoutValidation("Authorization", credentials.ToHeaderValue()); } /// /// Erklaerung fuer den Menschen davor, wenn der Server 401 antwortet. /// Ohne diesen Hinweis sieht ein abgelaufener Vertrag aus wie ein /// Netzwerkfehler, und man sucht an der falschen Stelle. /// public static string DescribeUnauthorized(ReleaseCredentials? credentials) { if (credentials == null) { return "Die Release-Ablage verlangt Zugangsdaten, es wurden aber keine mitgegeben. " + "Erwartet wird der Lizenzschluessel dieser Installation."; } return "Die Release-Ablage hat die Zugangsdaten abgelehnt. Moegliche Gruende: die Lizenz " + "ist abgelaufen, wurde widerrufen oder gehoert zu einem anderen Produkt."; } } }