private void ThrowIfTimestampNotVerified(string timestampStr) { var challengeTimestamp = OAuthServerHelper.ParseDateTime(timestampStr); if (challengeTimestamp + MaxChallengeAge < SystemTime.UtcNow || challengeTimestamp > SystemTime.UtcNow) { throw new InvalidOperationException( "The challenge is either too old or from the future in 'ChallengeResponse' message" + $"challengeTimestamp={challengeTimestamp}, MaxChallengeAge={MaxChallengeAge}, SystemTime.UtcNow={SystemTime.UtcNow}"); } }
private async Task <AccessToken> ProcessToken(JsonOperationContext context, WebSocket webSocket) { using (var reader = await context.ReadFromWebSocket(webSocket, DebugTag, ServerStore.ServerShutdown)) { var requestContents = ExtractChallengeResponse(reader); var encryptedData = ExtractEncryptedData(requestContents); var challengeDictionary = OAuthHelper.ParseDictionary(OAuthServerHelper.DecryptAsymmetric(encryptedData)); var apiKeyName = challengeDictionary.GetOrDefault(OAuthHelper.Keys.APIKeyName); var challenge = challengeDictionary.GetOrDefault(OAuthHelper.Keys.Challenge); var response = challengeDictionary.GetOrDefault(OAuthHelper.Keys.Response); if (string.IsNullOrEmpty(apiKeyName) || string.IsNullOrEmpty(challenge) || string.IsNullOrEmpty(response)) { throw new InvalidOperationException( "Got null or empty apiKeyName/challenge/response in 'ChallengeResponse' message"); } var challengeData = OAuthHelper.ParseDictionary(OAuthServerHelper.DecryptSymmetric(challenge)); var timestampStr = challengeData.GetOrDefault(OAuthHelper.Keys.ChallengeTimestamp); if (string.IsNullOrEmpty(timestampStr)) { throw new InvalidOperationException("Got null or empty encryptedData in 'ChallengeResponse' message"); } ThrowIfTimestampNotVerified(timestampStr); string secret; var accessToken = BuildAccessTokenAndGetApiKeySecret(apiKeyName, out secret); var expectedResponse = OAuthHelper.Hash(string.Format(OAuthHelper.Keys.ResponseFormat, challenge, secret)); if (response != expectedResponse) { if (_logger.IsInfoEnabled) { _logger.Info($"Failure to authenticate api key {apiKeyName}"); } return(null); } return(accessToken); } }
private async Task SendInitialChallenge(WebSocket webSocket) { var challengeData = new Dictionary <string, string> { { OAuthHelper.Keys.ChallengeTimestamp, OAuthServerHelper.DateTimeToString(SystemTime.UtcNow) }, { OAuthHelper.Keys.ChallengeSalt, OAuthHelper.BytesToString(OAuthServerHelper.RandomBytes(OAuthHelper.Keys.ChallengeSaltLength)) } }; var json = new DynamicJsonValue { [OAuthHelper.Keys.RSAExponent] = OAuthServerHelper.RSAExponent, [OAuthHelper.Keys.RSAModulus] = OAuthServerHelper.RSAModulus, [OAuthHelper.Keys.Challenge] = OAuthServerHelper.EncryptSymmetric(OAuthHelper.DictionaryToString(challengeData)) }; await SendResponse(webSocket, json).ConfigureAwait(false); }