Allgemeine Konzepte
Analysieren der Verbindungszeichenfolge
Für den Zugriff auf einen Notification Hub benötigen Sie zwei Informationseinheiten: dem Namen (Dies kann einen Pfad wie "a/b/c" sein), und eine Verbindungszeichenfolge. Die Verbindungszeichenfolge enthält Informationen über den Endpunkt des Hubs und die Sicherheitsanmeldeinformationen, die darauf zugreifen (im Fall von SAS enthält einen Regelnamen und einen Schlüsselwert).
Der folgende Code analysiert die Verbindungszeichenfolge so, dass die relevanten Informationen zu extrahieren:
public partial class ConnectionStringUtility { public string Endpoint { get; private set; } public string SasKeyName { get; private set; } public string SasKeyValue { get; private set; } public ConnectionStringUtility(string connectionString) { //Parse Connectionstring char[] separator = { ';' }; string[] parts = connectionString.Split(separator); for (int i = 0; i < parts.Length; i++) { if (parts[i].StartsWith("Endpoint")) Endpoint = "https" + parts[i].Substring(11); if (parts[i].StartsWith("SharedAccessKeyName")) SasKeyName = parts[i].Substring(20); if (parts[i].StartsWith("SharedAccessKey")) SasKeyValue = parts[i].Substring(16); } } }
String[] parts = connectionString.split(";"); if (parts.length != 3) throw new RuntimeException("Error parsing connection string: " + connectionString); for (int i = 0; i < parts.length; i++) { if (parts[i].startsWith("Endpoint")) { this.endpoint = "https" + parts[i].substring(11); } else if (parts[i].startsWith("SharedAccessKeyName")) { this.SasKeyName = parts[i].substring(20); } else if (parts[i].startsWith("SharedAccessKey")) { this.SasKeyValue = parts[i].substring(16); } }
var parts = connectionString.split(';'); if (parts.length != 3) throw "Error parsing connection string"; parts.forEach(function(part) { if (part.indexOf('Endpoint') == 0) { endpoint = 'https' + part.substring(11); } else if (part.indexOf('SharedAccessKeyName') == 0) { sasKeyName = part.substring(20); } else if (part.indexOf('SharedAccessKey') == 0) { sasKeyValue = part.substring(16); } });
Erstellen von SAS-Sicherheitstoken
Für die Authentifizierung mithilfe von SAS geben ein Client ein SAS-Token in der Authorization
-Header seiner Anforderungen. Das Token wird aus den Informationen aus der Verbindungszeichenfolge und der aktuellen Anforderung, die authentifiziert werden extrahiert erstellt. Das Token hat folgende Form:
SharedAccessSignature sig=<signature-string>&se=<expiry>&skn=<keyName>&sr=<URL-encoded-resourceURI>
Das Token, bezieht sich eine keyName
(zum Senden von Benachrichtigungen verwenden Sie normalerweise die DefaultFullSharedAccessSignature -Eigenschaft, die automatisch auf alle Notification Hubs erstellt wird).
Die Signatur für das SAS-Token wird mithilfe von HMAC-SHA256 eines zu signierende Zeichenfolge mit berechnet die PrimaryKey Eigenschaft einer Autorisierungsregel. Der Wert der Zeichenfolge für die Signatur besteht aus einer Ressourcen-URI und eine Ablaufzeit, die wie folgt formatiert:
StringToSign = <resourceURI> + "\n" + expiry;
Beachten Sie, dass Sie den uncodierten Ressourcen-URI für diesen Vorgang verwenden sollten. Der Ressourcen-URI ist der vollständige URI, der die Servicebus Ressource, auf die der Zugriff beansprucht wird. Das Format lautet wie folgt:
http://<namespace>.servicebus.windows.net/<hubName>
Zum Beispiel:
http://contoso.servicebus.windows.net/myHub
Die Ablaufzeit wird als die Anzahl der Sekunden seit der Epoche 00:00:00 UTC am 1. Januar 1970 dargestellt.
Die SAS-Autorisierungsregel, die zum Signieren verwendet, muss auf die durch diesen URI angegebene Entität konfiguriert werden. Im vorherigen Beispiel ist dies http://contoso.servicebus.windows.net/myHub
oder http://contoso.servicebus.windows.net
.
Der URL-codierte ResourceURI muss identisch mit dem URI, der in der zu signierende Zeichenfolge während der Berechnung der Signatur verwendet werden. Es sollte als Prozentwert codiert und Kleinbuchstaben sein.
Der folgende Code erhält einen URI erstellt ein SAS-Token. Die Java-Version verwendet Apache Commons Codec und die Javascript-Version CryptoJS.
public partial class ConnectionStringUtility { public string getSaSToken(string uri, int minUntilExpire) { string targetUri = Uri.EscapeDataString(uri.ToLower()).ToLower(); // Add an expiration in seconds to it. long expiresOnDate = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; expiresOnDate += minUntilExpire * 60 * 1000; long expires_seconds = expiresOnDate / 1000; String toSign = targetUri + "\n" + expires_seconds; // Generate a HMAC-SHA256 hash or the uri and expiration using your secret key. MacAlgorithmProvider macAlgorithmProvider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256); BinaryStringEncoding encoding = BinaryStringEncoding.Utf8; var messageBuffer = CryptographicBuffer.ConvertStringToBinary(toSign, encoding); IBuffer keyBuffer = CryptographicBuffer.ConvertStringToBinary(SasKeyValue, encoding); CryptographicKey hmacKey = macAlgorithmProvider.CreateKey(keyBuffer); IBuffer signedMessage = CryptographicEngine.Sign(hmacKey, messageBuffer); string signature = Uri.EscapeDataString(CryptographicBuffer.EncodeToBase64String(signedMessage)); return "SharedAccessSignature sr=" + targetUri + "&sig=" + signature + "&se=" + expires_seconds + "&skn=" + SasKeyName; } }
private String generateSasToken(URI uri) { String targetUri; try { targetUri = URLEncoder .encode(uri.toString().toLowerCase(), "UTF-8") .toLowerCase(); long expiresOnDate = System.currentTimeMillis(); int expiresInMins = 60; // 1 hour expiresOnDate += expiresInMins * 60 * 1000; long expires = expiresOnDate / 1000; String toSign = targetUri + "\n" + expires; // Get an hmac_sha1 key from the raw key bytes byte[] keyBytes = SasKeyValue.getBytes("UTF-8"); SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA256"); // Get an hmac_sha1 Mac instance and initialize with the signing key Mac mac = Mac.getInstance("HmacSHA256"); mac.init(signingKey); // Compute the hmac on input data bytes byte[] rawHmac = mac.doFinal(toSign.getBytes("UTF-8")); // using Apache commons codec for base64 String signature = URLEncoder.encode( Base64.encodeBase64String(rawHmac), "UTF-8"); // construct authorization string String token = "SharedAccessSignature sr=" + targetUri + "&sig=" + signature + "&se=" + expires + "&skn=" + SasKeyName; return token; } catch (Exception e) { throw new RuntimeException(e); } }
var getSelfSignedToken = function(targetUri, sharedKey, ruleId, expiresInMins) { targetUri = encodeURIComponent(targetUri.toLowerCase()).toLowerCase(); // Set expiration in seconds var expireOnDate = new Date(); expireOnDate.setMinutes(expireOnDate.getMinutes() + expiresInMins); var expires = Date.UTC(expireOnDate.getUTCFullYear(), expireOnDate .getUTCMonth(), expireOnDate.getUTCDate(), expireOnDate .getUTCHours(), expireOnDate.getUTCMinutes(), expireOnDate .getUTCSeconds()) / 1000; var tosign = targetUri + '\n' + expires; // using CryptoJS var signature = CryptoJS.HmacSHA256(tosign, sharedKey); var base64signature = signature.toString(CryptoJS.enc.Base64); var base64UriEncoded = encodeURIComponent(base64signature); // construct autorization string var token = "SharedAccessSignature sr=" + targetUri + "&sig=" + base64UriEncoded + "&se=" + expires + "&skn=" + ruleId; // console.log("signature:" + token); return token; };