/// <summary> /// Ensure valid auth credentials are present. This may rely in an already-known /// and valid token, and will obtain a new token if necessary or explicitly /// requested. /// Authorisation will use the parameters supplied on construction except /// where overridden with the options supplied in the call. /// </summary> /// <param name="tokenParams"><see cref="TokenParams"/> custom parameter. Pass null and default token request options will be generated used the options passed when creating the client</param> /// <param name="options"><see cref="AuthOptions"/> custom options.</param> /// <returns>Returns a valid token</returns> /// <exception cref="AblyException">Throws an ably exception representing the server response</exception> public async Task <TokenDetails> AuthoriseAsync(TokenParams tokenParams = null, AuthOptions options = null) { var authOptions = options ?? new AuthOptions(); bool force = authOptions.Force; //this is needed because I share the object and reset Force later on. authOptions.Merge(CurrentAuthOptions); SetCurrentAuthOptions(options); var authTokenParams = MergeTokenParamsWithDefaults(tokenParams); SetCurrentTokenParams(authTokenParams); if (force) { CurrentToken = await RequestTokenAsync(authTokenParams, options); } else if (CurrentToken != null) { if ((Config.Now().AddSeconds(Defaults.TokenExpireBufferInSeconds)) >= CurrentToken.Expires) { CurrentToken = await RequestTokenAsync(authTokenParams, options); } } else { CurrentToken = await RequestTokenAsync(authTokenParams, options); } AuthMethod = AuthMethod.Token; return(CurrentToken); }
private async Task <AblyResponse> CallAuthUrl(AuthOptions mergedOptions, TokenParams @params) { var url = mergedOptions.AuthUrl; var protocol = Options.UseBinaryProtocol == false ? Protocol.Json : Protocol.MsgPack; var authRequest = new AblyRequest(url.ToString(), mergedOptions.AuthMethod, protocol); if (mergedOptions.AuthMethod == HttpMethod.Get) { authRequest.AddQueryParameters(@params.ToRequestParams(mergedOptions.AuthParams)); } else { authRequest.PostParameters = @params.ToRequestParams(mergedOptions.AuthParams); } authRequest.Headers = authRequest.Headers.Merge(mergedOptions.AuthHeaders); authRequest.SkipAuthentication = true; AblyResponse response = await _rest.ExecuteRequest(authRequest); if (response.Type == ResponseType.Binary) { throw new AblyException( new ErrorInfo( string.Format("Content Type {0} is not supported by this client library", response.ContentType), 500)); } return(response); }
/// <summary> /// Get a new instance of TokenParams and applies the /// default Capability and Ttl. /// </summary> /// <returns>instance of TokenParams.</returns> public static TokenParams WithDefaultsApplied() { var tokenParams = new TokenParams { Capability = Defaults.DefaultTokenCapability, Ttl = Defaults.DefaultTokenTtl, }; return(tokenParams); }
private TokenParams MergeTokenParamsWithDefaults(TokenParams tokenParams) { TokenParams @params = tokenParams?.Merge(CurrentTokenParams); if (@params == null) { @params = CurrentTokenParams ?? TokenParams.WithDefaultsApplied(); @params.ClientId = ClientId; //Ensure the correct clientId is supplied } return(@params); }
private async Task SetTokenParamsTimestamp(AuthOptions authOptions, TokenParams tokenParams) { if (authOptions.QueryTime.GetValueOrDefault(false) && !ServerTimeOffset().HasValue) { await SetServerTimeOffset(); } if (!tokenParams.Timestamp.HasValue) { tokenParams.Timestamp = ServerTimeOffset(); } }
public TokenParams Clone() { var result = new TokenParams(); result.ClientId = ClientId; if (Capability != null) { result.Capability = new Capability(Capability.ToJson()); } result.Nonce = Nonce; result.Ttl = Ttl; result.Timestamp = Timestamp; return(result); }
public TokenParams Merge(TokenParams otherParams) { if (otherParams == null) { return(this); } var result = new TokenParams(); result.ClientId = ClientId.IsNotEmpty() ? ClientId : otherParams.ClientId; result.Capability = Capability ?? otherParams.Capability; result.Ttl = Ttl ?? otherParams.Ttl; result.Timestamp = Timestamp ?? otherParams.Timestamp; result.Nonce = Nonce ?? otherParams.Nonce; return(result); }
/// <summary> /// Creates a new instance of token params and populates all the current values. /// </summary> /// <returns>a new instance of token params.</returns> public TokenParams Clone() { var result = new TokenParams { ClientId = ClientId, Nonce = Nonce, Ttl = Ttl, Timestamp = Timestamp, }; if (Capability != null) { result.Capability = new Capability(Capability.ToJson()); } return(result); }
internal TokenRequest Populate(TokenParams tokenParams, string keyName, string keyValue) { this.KeyName = keyName; Capability = tokenParams.Capability ?? Capability.AllowAll; ClientId = tokenParams.ClientId; var now = Now(); if (tokenParams.Nonce.IsNotEmpty()) { Nonce = tokenParams.Nonce; } Ttl = tokenParams.Ttl ?? Defaults.DefaultTokenTtl; Timestamp = tokenParams.Timestamp ?? now; CalculateMac(keyValue); return(this); }
/// <summary> /// Ensure valid auth credentials are present. This may rely in an already-known /// and valid token, and will obtain a new token if necessary or explicitly /// requested. /// Authorisation will use the parameters supplied on construction except /// where overridden with the options supplied in the call. /// </summary> /// <param name="tokenParams"><see cref="TokenParams"/> custom parameter. Pass null and default token request options will be generated used the options passed when creating the client</param> /// <param name="authOptions"><see cref="AuthOptions"/> custom options.</param> /// <returns>Returns a valid token</returns> /// <exception cref="AblyException">Throws an ably exception representing the server response</exception> public async Task <TokenDetails> AuthorizeAsync(TokenParams tokenParams = null, AuthOptions authOptions = null) { // RSA10j - TokenParams and AuthOptions supersede any previously client library configured TokenParams and AuthOptions authOptions = authOptions ?? CurrentAuthOptions ?? Options; SetCurrentAuthOptions(authOptions); tokenParams = tokenParams ?? CurrentTokenParams ?? TokenParams.WithDefaultsApplied(); SetCurrentTokenParams(tokenParams); CurrentToken = await RequestTokenAsync(tokenParams, authOptions); AuthMethod = AuthMethod.Token; var eventArgs = new AblyAuthUpdatedEventArgs(CurrentToken); AuthUpdated?.Invoke(this, eventArgs); // RTC8a3 await AuthorizeCompleted(eventArgs); return(CurrentToken); }
/// <summary> /// Create a signed token request based on known credentials /// and the given token params. This would typically be used if creating /// signed requests for submission by another client. /// </summary> /// <param name="tokenParams"><see cref="TokenParams"/>. If null a token request is generated from options passed when the client was created.</param> /// <param name="authOptions"><see cref="AuthOptions"/>. If null the default AuthOptions are used.</param> /// <returns></returns> public async Task <TokenRequest> CreateTokenRequestAsync(TokenParams tokenParams, AuthOptions authOptions) { var mergedOptions = authOptions != null?authOptions.Merge(Options) : Options; if (string.IsNullOrEmpty(mergedOptions.Key)) { throw new AblyException("No key specified", 40101, HttpStatusCode.Unauthorized); } var @params = MergeTokenParamsWithDefaults(tokenParams); if (mergedOptions.QueryTime.GetValueOrDefault(false)) { @params.Timestamp = await _rest.TimeAsync(); } ApiKey key = mergedOptions.ParseKey(); var request = new TokenRequest().Populate(@params, key.KeyName, key.KeySecret); return(request); }
/// <summary> /// Create a signed token request based on known credentials /// and the given token params. This would typically be used if creating /// signed requests for submission by another client. /// </summary> /// <param name="tokenParams"><see cref="TokenParams"/>. If null a token request is generated from options passed when the client was created.</param> /// <param name="authOptions"><see cref="AuthOptions"/>. If null the default AuthOptions are used.</param> /// <returns></returns> public async Task <string> CreateTokenRequestAsync(TokenParams tokenParams, AuthOptions authOptions) { authOptions = authOptions ?? CurrentAuthOptions ?? Options; tokenParams = tokenParams ?? CurrentTokenParams ?? TokenParams.WithDefaultsApplied(); if (string.IsNullOrEmpty(authOptions.Key)) { throw new AblyException("No key specified", 40101, HttpStatusCode.Unauthorized); } await SetTokenParamsTimestamp(authOptions, tokenParams); if (authOptions.QueryTime.GetValueOrDefault(false)) { tokenParams.Timestamp = await _rest.TimeAsync(); } var apiKey = authOptions.ParseKey(); var request = new TokenRequest(Now).Populate(tokenParams, apiKey.KeyName, apiKey.KeySecret); return(JsonHelper.Serialize(request)); }
/// <summary> /// Makes a token request. This will make a token request now, even if the library already /// has a valid token. It would typically be used to issue tokens for use by other clients. /// </summary> /// <param name="tokenParams">The <see cref="TokenRequest"/> data used for the token</param> /// <param name="authOptions">Extra <see cref="AuthOptions"/> used for creating a token </param> /// <returns>A valid ably token</returns> /// <exception cref="AblyException"></exception> public virtual async Task <TokenDetails> RequestTokenAsync(TokenParams tokenParams = null, AuthOptions authOptions = null) { EnsureSecureConnection(); // (RSA8e) authOptions = authOptions ?? CurrentAuthOptions ?? Options ?? new AuthOptions(); tokenParams = tokenParams ?? CurrentTokenParams ?? TokenParams.WithDefaultsApplied(); string keyId = string.Empty, keyValue = string.Empty; if (authOptions.Key.IsNotEmpty()) { var key = authOptions.ParseKey(); keyId = key.KeyName; keyValue = key.KeySecret; } if (tokenParams.ClientId.IsEmpty()) { tokenParams.ClientId = ClientId; } await SetTokenParamsTimestamp(authOptions, tokenParams); var request = _rest.CreatePostRequest($"/keys/{keyId}/requestToken"); request.SkipAuthentication = true; TokenRequest postData = null; if (authOptions.AuthCallback != null) { bool shouldCatch = true; try { var callbackResult = await authOptions.AuthCallback(tokenParams); if (callbackResult == null) { throw new AblyException("AuthCallback returned null", 80019); } if (callbackResult is TokenDetails) { return(callbackResult as TokenDetails); } if (callbackResult is TokenRequest || callbackResult is string) { postData = GetTokenRequest(callbackResult); request.Url = $"/keys/{postData.KeyName}/requestToken"; } else { shouldCatch = false; throw new AblyException($"AuthCallback returned an unsupported type ({callbackResult.GetType()}. Expected either TokenDetails or TokenRequest", 80019, HttpStatusCode.BadRequest); } } catch (Exception ex) when(shouldCatch) { var statusCode = HttpStatusCode.Unauthorized; if (ex is AblyException aex) { statusCode = aex.ErrorInfo.StatusCode == HttpStatusCode.Forbidden ? HttpStatusCode.Forbidden : HttpStatusCode.Unauthorized; } throw new AblyException( new ErrorInfo( "Error calling AuthCallback, token request failed. See inner exception for details.", 80019, statusCode), ex); } } else if (authOptions.AuthUrl.IsNotEmpty()) { var responseText = String.Empty; try { var response = await CallAuthUrl(authOptions, tokenParams); if (response.Type == ResponseType.Text || response.Type == ResponseType.Jwt) { // RSC8c: // The token retrieved is assumed by the library to be a token string // if the response has Content-Type "text/plain" or "application/jwt" return(new TokenDetails(response.TextResponse, Now)); } responseText = response.TextResponse; var jData = JObject.Parse(responseText); if (TokenDetails.IsToken(jData)) { return(JsonHelper.DeserializeObject <TokenDetails>(jData)); } postData = JsonHelper.Deserialize <TokenRequest>(responseText); request.Url = $"/keys/{postData.KeyName}/requestToken"; } catch (AblyException ex) { throw new AblyException( new ErrorInfo( "Error calling Auth URL, token request failed. See the InnerException property for details of the underlying exception.", 80019, ex.ErrorInfo.StatusCode == HttpStatusCode.Forbidden ? ex.ErrorInfo.StatusCode : HttpStatusCode.Unauthorized, ex), ex); } catch (Exception ex) { string reason = "Error handling Auth URL, token request failed. See the InnerException property for details of the underlying exception."; if (ex is JsonReaderException) { reason = $"Error parsing JSON response '{responseText}' from Auth URL.See the InnerException property for details of the underlying exception."; } throw new AblyException( new ErrorInfo( reason, 80019, HttpStatusCode.InternalServerError, ex), ex); } } else { if (keyId.IsEmpty() || keyValue.IsEmpty()) { throw new AblyException("TokenAuth is on but there is no way to generate one", 80019); } postData = new TokenRequest(Now).Populate(tokenParams, keyId, keyValue); } request.PostData = postData; TokenDetails result = await _rest.ExecuteRequest <TokenDetails>(request); if (result == null) { throw new AblyException("Invalid token response returned", 80019); } //TODO: Very ugly stuff result.Now = Now; return(result); }
public TokenRequest CreateTokenRequest(TokenParams tokenParams = null, AuthOptions authOptions = null) { return(AsyncHelper.RunSync(() => CreateTokenRequestAsync(tokenParams, authOptions))); }
public TokenDetails Authorise(TokenParams tokenParams = null, AuthOptions options = null) { return(AsyncHelper.RunSync(() => AuthoriseAsync(tokenParams, options))); }
public TokenDetails RequestToken(TokenParams tokenParams = null, AuthOptions options = null) { return(AsyncHelper.RunSync(() => RequestTokenAsync(tokenParams, options))); }
private void SetCurrentTokenParams(TokenParams authTokenParams) { CurrentTokenParams = authTokenParams.Clone(); CurrentTokenParams.Timestamp = null; }
public async Task <TokenDetails> AuthoriseAsync(TokenParams tokenParams = null, AuthOptions options = null) { Logger.Warning("AuthoriseAsync is deprecated and will be removed in the future, please replace with a call to AuthorizeAsync"); return(await AuthorizeAsync(tokenParams, options)); }
/// <summary> /// Makes a token request. This will make a token request now, even if the library already /// has a valid token. It would typically be used to issue tokens for use by other clients. /// </summary> /// <param name="tokenParams">The <see cref="TokenRequest"/> data used for the token</param> /// <param name="options">Extra <see cref="AuthOptions"/> used for creating a token </param> /// <returns>A valid ably token</returns> /// <exception cref="AblyException"></exception> public virtual async Task <TokenDetails> RequestTokenAsync(TokenParams tokenParams = null, AuthOptions options = null) { var mergedOptions = options != null?options.Merge(Options) : Options; string keyId = "", keyValue = ""; if (mergedOptions.Key.IsNotEmpty()) { var key = mergedOptions.ParseKey(); keyId = key.KeyName; keyValue = key.KeySecret; } var @params = MergeTokenParamsWithDefaults(tokenParams); if (mergedOptions.QueryTime.GetValueOrDefault(false)) { @params.Timestamp = await _rest.TimeAsync(); } EnsureSecureConnection(); var request = _rest.CreatePostRequest($"/keys/{keyId}/requestToken"); request.SkipAuthentication = true; TokenRequest postData = null; if (mergedOptions.AuthCallback != null) { var callbackResult = await mergedOptions.AuthCallback(@params); if (callbackResult == null) { throw new AblyException("AuthCallback returned null"); } if (callbackResult is TokenDetails) { return(callbackResult as TokenDetails); } if (callbackResult is TokenRequest) { postData = callbackResult as TokenRequest; request.Url = $"/keys/{postData.KeyName}/requestToken"; } else { throw new AblyException($"AuthCallback returned an unsupported type ({callbackResult.GetType()}. Expected either TokenDetails or TokenRequest"); } } else if (mergedOptions.AuthUrl.IsNotEmpty()) { var response = await CallAuthUrl(mergedOptions, @params); if (response.Type == ResponseType.Text) //Return token string { return(new TokenDetails(response.TextResponse)); } var signedData = response.TextResponse; var jData = JObject.Parse(signedData); if (TokenDetails.IsToken(jData)) { return(JsonHelper.DeserializeObject <TokenDetails>(jData)); } postData = JsonHelper.Deserialize <TokenRequest>(signedData); request.Url = $"/keys/{postData.KeyName}/requestToken"; } else { if (keyId.IsEmpty() || keyValue.IsEmpty()) { throw new AblyException("TokenAuth is on but there is no way to generate one"); } postData = new TokenRequest().Populate(@params, keyId, keyValue); } request.PostData = postData; TokenDetails result = await _rest.ExecuteRequest <TokenDetails>(request); if (result == null) { throw new AblyException(new ErrorInfo("Invalid token response returned", 500)); } return(result); }
public TokenDetails Authorise(TokenParams tokenParams = null, AuthOptions options = null) { Logger.Warning("Authorise is deprecated and will be removed in the future, please replace with a call to Authorize."); return(AsyncHelper.RunSync(() => AuthorizeAsync(tokenParams, options))); }