Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
        private async Task SetTokenParamsTimestamp(AuthOptions authOptions, TokenParams tokenParams)
        {
            if (authOptions.QueryTime.GetValueOrDefault(false) &&
                !ServerTimeOffset().HasValue)
            {
                await SetServerTimeOffset();
            }

            if (!tokenParams.Timestamp.HasValue)
            {
                tokenParams.Timestamp = ServerTimeOffset();
            }
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        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);
        }
Ejemplo n.º 8
0
        /// <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);
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        /// <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);
        }
Ejemplo n.º 11
0
        /// <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);
        }
Ejemplo n.º 12
0
        /// <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));
        }
Ejemplo n.º 13
0
        /// <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);
        }
Ejemplo n.º 14
0
 public TokenRequest CreateTokenRequest(TokenParams tokenParams = null,
                                        AuthOptions authOptions = null)
 {
     return(AsyncHelper.RunSync(() => CreateTokenRequestAsync(tokenParams, authOptions)));
 }
Ejemplo n.º 15
0
 public TokenDetails Authorise(TokenParams tokenParams = null,
                               AuthOptions options     = null)
 {
     return(AsyncHelper.RunSync(() => AuthoriseAsync(tokenParams, options)));
 }
Ejemplo n.º 16
0
 public TokenDetails RequestToken(TokenParams tokenParams = null,
                                  AuthOptions options     = null)
 {
     return(AsyncHelper.RunSync(() => RequestTokenAsync(tokenParams, options)));
 }
Ejemplo n.º 17
0
 private void SetCurrentTokenParams(TokenParams authTokenParams)
 {
     CurrentTokenParams           = authTokenParams.Clone();
     CurrentTokenParams.Timestamp = null;
 }
Ejemplo n.º 18
0
 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));
 }
Ejemplo n.º 19
0
        /// <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);
        }
Ejemplo n.º 20
0
 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)));
 }