コード例 #1
0
        public DefaultRequestExecutor(
            IHttpClient httpClient,
            IClientApiKey apiKey,
            AuthenticationScheme authenticationScheme,
            ILogger logger,
            IBackoffStrategy defaultBackoffStrategy,
            IBackoffStrategy throttlingBackoffStrategy)
        {
            if (!apiKey.IsValid())
            {
                throw new ApplicationException("API Key is invalid.");
            }

            this.httpClient      = httpClient;
            this.syncHttpClient  = httpClient as ISynchronousHttpClient;
            this.asyncHttpClient = httpClient as IAsynchronousHttpClient;

            this.apiKey = apiKey;
            this.authenticationScheme = authenticationScheme;

            IRequestAuthenticatorFactory requestAuthenticatorFactory = new DefaultRequestAuthenticatorFactory();

            this.requestAuthenticator = requestAuthenticatorFactory.Create(authenticationScheme);

            this.logger = logger;
            this.defaultBackoffStrategy    = defaultBackoffStrategy;
            this.throttlingBackoffStrategy = throttlingBackoffStrategy;
        }
コード例 #2
0
        void IRequestAuthenticator.Authenticate(IHttpRequest request, IClientApiKey apiKey)
        {
            var now   = DateTimeOffset.UtcNow;
            var nonce = Guid.NewGuid().ToString();

            this.AuthenticateCore(request, apiKey, now, nonce);
        }
コード例 #3
0
        public DefaultRequestExecutor(
            IHttpClient httpClient,
            IClientApiKey apiKey,
            AuthenticationScheme authenticationScheme,
            ILogger logger,
            IBackoffStrategy defaultBackoffStrategy,
            IBackoffStrategy throttlingBackoffStrategy)
        {
            if (!apiKey.IsValid())
            {
                throw new ApplicationException("API Key is invalid.");
            }

            this.httpClient = httpClient;
            this.syncHttpClient = httpClient as ISynchronousHttpClient;
            this.asyncHttpClient = httpClient as IAsynchronousHttpClient;

            this.apiKey = apiKey;
            this.authenticationScheme = authenticationScheme;

            IRequestAuthenticatorFactory requestAuthenticatorFactory = new DefaultRequestAuthenticatorFactory();
            this.requestAuthenticator = requestAuthenticatorFactory.Create(authenticationScheme);

            this.logger = logger;
            this.defaultBackoffStrategy = defaultBackoffStrategy;
            this.throttlingBackoffStrategy = throttlingBackoffStrategy;
        }
コード例 #4
0
 public DefaultRequestExecutor(
     IHttpClient httpClient,
     IClientApiKey apiKey,
     AuthenticationScheme authenticationScheme,
     ILogger logger)
     : this(httpClient, apiKey, authenticationScheme, logger, new DefaultBackoffStrategy(MaxBackoffMilliseconds), new ThrottlingBackoffStrategy(MaxBackoffMilliseconds))
 {
 }
コード例 #5
0
        internal void AuthenticateCore(IHttpRequest request, IClientApiKey apiKey, DateTimeOffset now)
        {
            request.Headers.Add(StormpathDateHeaderName, Iso8601.Format(now, withSeparators: false));

            var authorizationHeaderContent = $"{apiKey.GetId()}:{apiKey.GetSecret()}";
            var authorizationHeaderEncrypted = Base64.Encode(authorizationHeaderContent, Encoding.UTF8);
            request.Headers.Authorization = new AuthorizationHeaderValue("Basic", authorizationHeaderEncrypted);
        }
コード例 #6
0
 public DefaultRequestExecutor(
     IHttpClient httpClient,
     IClientApiKey apiKey,
     AuthenticationScheme authenticationScheme,
     ILogger logger)
     : this(httpClient, apiKey, authenticationScheme, logger, new DefaultBackoffStrategy(MaxBackoffMilliseconds), new ThrottlingBackoffStrategy(MaxBackoffMilliseconds))
 {
 }
コード例 #7
0
        internal void AuthenticateCore(IHttpRequest request, IClientApiKey apiKey, DateTimeOffset now)
        {
            request.Headers.Add(StormpathDateHeaderName, Iso8601.Format(now, withSeparators: false));

            var authorizationHeaderContent   = $"{apiKey.GetId()}:{apiKey.GetSecret()}";
            var authorizationHeaderEncrypted = Base64.Encode(authorizationHeaderContent, Encoding.UTF8);

            request.Headers.Authorization = new AuthorizationHeaderValue("Basic", authorizationHeaderEncrypted);
        }
        internal static void ThrowIfJwtSignatureInvalid(string jwtApiKey, IClientApiKey clientApiKey, IJwt jwt)
        {
            if (!clientApiKey.GetId().Equals(jwtApiKey, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new JwtSignatureException("The client used to sign the response is different than the one used in this DataStore.");
            }

            var signingKey = Encoding.UTF8.GetBytes(clientApiKey.GetSecret());

            if (!new JwtSignatureValidator(signingKey).IsValid(jwt))
            {
                throw new JwtSignatureException("The JWT signature is invalid.");
            }
        }
コード例 #9
0
        IClientBuilder IClientBuilder.SetApiKey(IClientApiKey apiKey)
        {
            if (apiKey == null)
            {
                throw new ArgumentNullException("API Key cannot be null.");
            }

            if (!apiKey.IsValid())
            {
                throw new ArgumentException("API Key is not valid.");
            }

            this.apiKey = apiKey;
            return(this);
        }
コード例 #10
0
        public DefaultClient(
            IClientApiKey apiKey,
            string baseUrl,
            AuthenticationScheme authenticationScheme,
            int connectionTimeout,
            IWebProxy proxy,
            IHttpClient httpClient,
            IJsonSerializer serializer,
            ICacheProvider cacheProvider,
            IUserAgentBuilder userAgentBuilder,
            ILogger logger,
            TimeSpan identityMapExpiration)
        {
            if (apiKey == null || !apiKey.IsValid())
            {
                throw new ArgumentException("API Key is not valid.");
            }

            if (string.IsNullOrEmpty(baseUrl))
            {
                throw new ArgumentNullException("Base URL cannot be empty.");
            }

            if (connectionTimeout < 0)
            {
                throw new ArgumentException("Timeout cannot be negative.");
            }

            this.logger = logger;
            this.apiKey = apiKey;
            this.baseUrl = baseUrl;
            this.connectionTimeout = connectionTimeout;
            this.proxy = proxy;
            this.cacheProvider = cacheProvider;
            this.authenticationScheme = authenticationScheme;
            this.serializer = serializer;
            this.httpClient = httpClient;

            var requestExecutor = new DefaultRequestExecutor(httpClient, apiKey, authenticationScheme, this.logger);

            this.dataStore = new DefaultDataStore(this as IClient, requestExecutor, baseUrl, this.serializer, this.logger, userAgentBuilder, cacheProvider, identityMapExpiration);
            this.dataStoreAsync = this.dataStore as IInternalAsyncDataStore;
            this.dataStoreSync = this.dataStore as IInternalSyncDataStore;
        }
コード例 #11
0
        public DefaultClient(
            IClientApiKey apiKey,
            string baseUrl,
            AuthenticationScheme authenticationScheme,
            int connectionTimeout,
            IWebProxy proxy,
            IHttpClient httpClient,
            IJsonSerializer serializer,
            ICacheProvider cacheProvider,
            IUserAgentBuilder userAgentBuilder,
            ILogger logger,
            TimeSpan identityMapExpiration)
        {
            if (apiKey == null || !apiKey.IsValid())
            {
                throw new ArgumentException("API Key is not valid.");
            }

            if (string.IsNullOrEmpty(baseUrl))
            {
                throw new ArgumentNullException("Base URL cannot be empty.");
            }

            if (connectionTimeout < 0)
            {
                throw new ArgumentException("Timeout cannot be negative.");
            }

            this.logger               = logger;
            this.apiKey               = apiKey;
            this.baseUrl              = baseUrl;
            this.connectionTimeout    = connectionTimeout;
            this.proxy                = proxy;
            this.cacheProvider        = cacheProvider;
            this.authenticationScheme = authenticationScheme;
            this.serializer           = serializer;
            this.httpClient           = httpClient;

            var requestExecutor = new DefaultRequestExecutor(httpClient, apiKey, authenticationScheme, this.logger);

            this.dataStore      = new DefaultDataStore(this as IClient, requestExecutor, baseUrl, this.serializer, this.logger, userAgentBuilder, cacheProvider, identityMapExpiration);
            this.dataStoreAsync = this.dataStore as IInternalAsyncDataStore;
            this.dataStoreSync  = this.dataStore as IInternalSyncDataStore;
        }
コード例 #12
0
        public StubRequestExecutor(string resourceJson, IClientApiKey clientApiKey = null)
        {
            this.resourceJson = resourceJson;
            this.fakeRequestExecutor = Substitute.For<IRequestExecutor>();

            // API Key
            this.fakeRequestExecutor.ApiKey.Returns(clientApiKey);

            // All GETs return 200 OK
            this.fakeRequestExecutor
                .ExecuteAsync(
                    Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Get), Arg.Any<CancellationToken>())
                .Returns(
                    Task.FromResult(new DefaultHttpResponse(200, "OK", new HttpHeaders(), resourceJson, "application/json", transportError: false) as IHttpResponse));
            this.fakeRequestExecutor
                .Execute(
                    Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Get))
                .Returns(new DefaultHttpResponse(200, "OK", new HttpHeaders(), resourceJson, "application/json", transportError: false));

            // All POSTs return 201 Created
            this.fakeRequestExecutor
                .ExecuteAsync(
                    Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Post), Arg.Any<CancellationToken>())
                .Returns(
                    Task.FromResult(new DefaultHttpResponse(201, "Created", new HttpHeaders(), resourceJson, "application/json", transportError: false) as IHttpResponse));
            this.fakeRequestExecutor
                .Execute(
                    Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Post))
                .Returns(new DefaultHttpResponse(201, "Created", new HttpHeaders(), resourceJson, "application/json", transportError: false));

            // All DELETEs return 204 No Content
            this.fakeRequestExecutor
                .ExecuteAsync(
                    Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Delete), Arg.Any<CancellationToken>())
                .Returns(
                    Task.FromResult(new DefaultHttpResponse(204, "No Content", new HttpHeaders(), null, null, transportError: false) as IHttpResponse));
            this.fakeRequestExecutor
                .Execute(
                    Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Delete))
                .Returns(new DefaultHttpResponse(204, "No Content", new HttpHeaders(), null, null, transportError: false));
        }
コード例 #13
0
        public StubRequestExecutor(string resourceJson, IClientApiKey clientApiKey = null)
        {
            this.resourceJson        = resourceJson;
            this.fakeRequestExecutor = Substitute.For <IRequestExecutor>();

            // API Key
            this.fakeRequestExecutor.ApiKey.Returns(clientApiKey);

            // All GETs return 200 OK
            this.fakeRequestExecutor
            .ExecuteAsync(
                Arg.Is <IHttpRequest>(req => req.Method == HttpMethod.Get), Arg.Any <CancellationToken>())
            .Returns(
                Task.FromResult(new DefaultHttpResponse(200, "OK", new HttpHeaders(), resourceJson, "application/json", transportError: false) as IHttpResponse));
            this.fakeRequestExecutor
            .Execute(
                Arg.Is <IHttpRequest>(req => req.Method == HttpMethod.Get))
            .Returns(new DefaultHttpResponse(200, "OK", new HttpHeaders(), resourceJson, "application/json", transportError: false));

            // All POSTs return 201 Created
            this.fakeRequestExecutor
            .ExecuteAsync(
                Arg.Is <IHttpRequest>(req => req.Method == HttpMethod.Post), Arg.Any <CancellationToken>())
            .Returns(
                Task.FromResult(new DefaultHttpResponse(201, "Created", new HttpHeaders(), resourceJson, "application/json", transportError: false) as IHttpResponse));
            this.fakeRequestExecutor
            .Execute(
                Arg.Is <IHttpRequest>(req => req.Method == HttpMethod.Post))
            .Returns(new DefaultHttpResponse(201, "Created", new HttpHeaders(), resourceJson, "application/json", transportError: false));

            // All DELETEs return 204 No Content
            this.fakeRequestExecutor
            .ExecuteAsync(
                Arg.Is <IHttpRequest>(req => req.Method == HttpMethod.Delete), Arg.Any <CancellationToken>())
            .Returns(
                Task.FromResult(new DefaultHttpResponse(204, "No Content", new HttpHeaders(), null, null, transportError: false) as IHttpResponse));
            this.fakeRequestExecutor
            .Execute(
                Arg.Is <IHttpRequest>(req => req.Method == HttpMethod.Delete))
            .Returns(new DefaultHttpResponse(204, "No Content", new HttpHeaders(), null, null, transportError: false));
        }
コード例 #14
0
        internal void AuthenticateCore(IHttpRequest request, IClientApiKey apiKey, DateTimeOffset now, string nonce)
        {
            if (request == null)
            {
                throw new RequestAuthenticationException("Request must not be null.");
            }

            if (string.IsNullOrEmpty(request.CanonicalUri?.ToString()))
            {
                throw new RequestAuthenticationException("URL must not be empty.");
            }

            var uri = request.CanonicalUri.ToUri();

            if (!uri.IsAbsoluteUri)
            {
                throw new RequestAuthenticationException("URL must be an absolute path.");
            }

            var relativeResourcePath = uri.AbsolutePath;

            var timestamp = Iso8601.Format(now, withSeparators: false);
            var dateStamp = now.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture);

            // Add HOST header before signing
            var hostHeader = uri.Host;

            if (!uri.IsDefaultPort)
            {
                hostHeader = $"{hostHeader}:{uri.Port}";
            }

            request.Headers.Host = hostHeader;

            // Add X-Stormpath-Date before signing
            request.Headers.Add(StormpathDateHeaderName, timestamp);

            var requestBody      = request.Body.Nullable() ?? string.Empty;
            var requestBodyHash  = ToHex(Hash(requestBody, Encoding.UTF8));
            var sortedHeaderKeys = GetSortedHeaderNames(request.Headers);

            var canonicalRequest = new StringBuilder()
                                   .Append(request.Method.ToString().ToUpper())
                                   .Append(Newline)
                                   .Append(CanonicalizeResourcePath(relativeResourcePath))
                                   .Append(Newline)
                                   .Append(request.CanonicalUri.QueryString.ToString(canonical: true))
                                   .Append(Newline)
                                   .Append(CanonicalizeHeaders(request))
                                   .Append(Newline)
                                   .Append(sortedHeaderKeys)
                                   .Append(Newline)
                                   .Append(requestBodyHash)
                                   .ToString();

            var id = new StringBuilder()
                     .Append(apiKey.GetId()).Append("/")
                     .Append(dateStamp).Append("/")
                     .Append(nonce).Append("/")
                     .Append(IDTerminator)
                     .ToString();

            var canonicalRequestHash = ToHex(Hash(canonicalRequest, Encoding.UTF8));
            var stringToSign         = new StringBuilder()
                                       .Append(Algorithm)
                                       .Append(Newline)
                                       .Append(timestamp)
                                       .Append(Newline)
                                       .Append(id)
                                       .Append(Newline)
                                       .Append(canonicalRequestHash)
                                       .ToString();

            var secretFormat = $"{AuthenticationScheme}{apiKey.GetSecret()}";

            byte[] secret           = Encoding.UTF8.GetBytes(secretFormat);
            byte[] signedDate       = SignHmac256(dateStamp, secret, Encoding.UTF8);
            byte[] signedNonce      = SignHmac256(nonce, signedDate, Encoding.UTF8);
            byte[] signedTerminator = SignHmac256(IDTerminator, signedNonce, Encoding.UTF8);
            byte[] signature        = SignHmac256(stringToSign, signedTerminator, Encoding.UTF8);
            var    signatureHex     = ToHex(signature);

            var authorizationHeaderValue = new StringBuilder()
                                           .Append(SAUTHC1Id).Append("=").Append(id).Append(", ")
                                           .Append(SAUTHC1SignedHeaders).Append("=").Append(sortedHeaderKeys).Append(", ")
                                           .Append(SAUTHC1Signature).Append("=").Append(signatureHex)
                                           .ToString();

            request.Headers.Authorization = new AuthorizationHeaderValue(AuthenticationScheme, authorizationHeaderValue);
        }
コード例 #15
0
 void IRequestAuthenticator.Authenticate(IHttpRequest request, IClientApiKey apiKey)
 {
     var now = DateTimeOffset.UtcNow;
     var nonce = Guid.NewGuid().ToString();
     this.AuthenticateCore(request, apiKey, now, nonce);
 }
コード例 #16
0
 void IRequestAuthenticator.Authenticate(IHttpRequest request, IClientApiKey apiKey)
 {
     var now = DateTimeOffset.UtcNow;
     this.AuthenticateCore(request, apiKey, now);
 }
コード例 #17
0
        internal void AuthenticateCore(IHttpRequest request, IClientApiKey apiKey, DateTimeOffset now, string nonce)
        {
            if (request == null)
            {
                throw new RequestAuthenticationException("Request must not be null.");
            }

            if (string.IsNullOrEmpty(request.CanonicalUri?.ToString()))
            {
                throw new RequestAuthenticationException("URL must not be empty.");
            }

            var uri = request.CanonicalUri.ToUri();
            if (!uri.IsAbsoluteUri)
            {
                throw new RequestAuthenticationException("URL must be an absolute path.");
            }

            var relativeResourcePath = uri.AbsolutePath;

            var timestamp = Iso8601.Format(now, withSeparators: false);
            var dateStamp = now.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture);

            // Add HOST header before signing
            var hostHeader = uri.Host;
            if (!uri.IsDefaultPort)
            {
                hostHeader = $"{hostHeader}:{uri.Port}";
            }

            request.Headers.Host = hostHeader;

            // Add X-Stormpath-Date before signing
            request.Headers.Add(StormpathDateHeaderName, timestamp);

            var requestBody = request.Body.Nullable() ?? string.Empty;
            var requestBodyHash = ToHex(Hash(requestBody, Encoding.UTF8));
            var sortedHeaderKeys = GetSortedHeaderNames(request.Headers);

            var canonicalRequest = new StringBuilder()
                .Append(request.Method.ToString().ToUpper())
                .Append(Newline)
                .Append(CanonicalizeResourcePath(relativeResourcePath))
                .Append(Newline)
                .Append(request.CanonicalUri.QueryString.ToString(canonical: true))
                .Append(Newline)
                .Append(CanonicalizeHeaders(request))
                .Append(Newline)
                .Append(sortedHeaderKeys)
                .Append(Newline)
                .Append(requestBodyHash)
                .ToString();

            var id = new StringBuilder()
                .Append(apiKey.GetId()).Append("/")
                .Append(dateStamp).Append("/")
                .Append(nonce).Append("/")
                .Append(IDTerminator)
                .ToString();

            var canonicalRequestHash = ToHex(Hash(canonicalRequest, Encoding.UTF8));
            var stringToSign = new StringBuilder()
                .Append(Algorithm)
                .Append(Newline)
                .Append(timestamp)
                .Append(Newline)
                .Append(id)
                .Append(Newline)
                .Append(canonicalRequestHash)
                .ToString();

            var secretFormat = $"{AuthenticationScheme}{apiKey.GetSecret()}";
            byte[] secret = Encoding.UTF8.GetBytes(secretFormat);
            byte[] signedDate = SignHmac256(dateStamp, secret, Encoding.UTF8);
            byte[] signedNonce = SignHmac256(nonce, signedDate, Encoding.UTF8);
            byte[] signedTerminator = SignHmac256(IDTerminator, signedNonce, Encoding.UTF8);
            byte[] signature = SignHmac256(stringToSign, signedTerminator, Encoding.UTF8);
            var signatureHex = ToHex(signature);

            var authorizationHeaderValue = new StringBuilder()
                .Append(SAUTHC1Id).Append("=").Append(id).Append(", ")
                .Append(SAUTHC1SignedHeaders).Append("=").Append(sortedHeaderKeys).Append(", ")
                .Append(SAUTHC1Signature).Append("=").Append(signatureHex)
                .ToString();
            request.Headers.Authorization = new AuthorizationHeaderValue(AuthenticationScheme, authorizationHeaderValue);
        }
コード例 #18
0
        IClient IClientBuilder.Build()
        {
            if (this.apiKey == null)
            {
                if (this.clientApiKeyBuilder != null)
                {
                    this.apiKey = this.clientApiKeyBuilder.Build();
                }
                else
                {
                    throw new ApplicationException("No valid API Key and Secret could be found.");
                }
            }

            var logger = this.logger ?? new NullLogger();

            IJsonSerializer serializer = null;

            if (this.overrideSerializer != null)
            {
                serializer = this.overrideSerializer;
            }
            else
            {
                if (this.serializerBuilder == null)
                {
                    this.logger.Info("No serializer plugin specified, using default.");
                    this.serializerBuilder = Serializers.Create().AutoDetect();
                }

                serializer = this.serializerBuilder.Build();
            }

            IHttpClient httpClient = null;

            if (this.overrideHttpClient != null)
            {
                httpClient = this.overrideHttpClient;
            }
            else
            {
                if (this.httpClientBuilder == null)
                {
                    this.logger.Info("No HTTP client plugin specified, using default.");
                    this.httpClientBuilder = HttpClients.Create().AutoDetect();
                }

                this.httpClientBuilder
                .SetBaseUrl(this.baseUrl)
                .SetConnectionTimeout(this.connectionTimeout)
                .SetProxy(this.proxy)
                .SetLogger(this.logger);

                httpClient = this.httpClientBuilder.Build();
            }

            if (this.cacheProvider == null)
            {
                this.logger.Info("No CacheProvider configured. Defaulting to in-memory CacheProvider with default TTL and TTI of one hour.");

                this.cacheProvider = Caches
                                     .NewInMemoryCacheProvider()
                                     .WithDefaultTimeToIdle(TimeSpan.FromHours(1))
                                     .WithDefaultTimeToLive(TimeSpan.FromHours(1))
                                     .Build();
            }
            else
            {
                var injectableWithSerializer = this.cacheProvider as ISerializerConsumer <ICacheProvider>;
                if (injectableWithSerializer != null)
                {
                    injectableWithSerializer.SetSerializer(serializer);
                }

                var injectableWithLogger = this.cacheProvider as ILoggerConsumer <ICacheProvider>;
                if (injectableWithLogger != null)
                {
                    injectableWithLogger.SetLogger(this.logger);
                }
            }

            return(new DefaultClient(
                       this.apiKey,
                       this.baseUrl,
                       this.authenticationScheme,
                       this.connectionTimeout,
                       this.proxy,
                       httpClient,
                       serializer,
                       this.cacheProvider,
                       this.userAgentBuilder,
                       logger,
                       DefaultIdentityMapSlidingExpiration));
        }
        internal static void ThrowIfJwtSignatureInvalid(string jwtApiKey, IClientApiKey clientApiKey, IJwt jwt)
        {
            if (!clientApiKey.GetId().Equals(jwtApiKey, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new JwtSignatureException("The client used to sign the response is different than the one used in this DataStore.");
            }

            var signingKey = Encoding.UTF8.GetBytes(clientApiKey.GetSecret());
            if (!new JwtSignatureValidator(signingKey).IsValid(jwt))
            {
                throw new JwtSignatureException("The JWT signature is invalid.");
            }
        }
コード例 #20
0
 public BasicRequestAuthenticator_tests()
 {
     this.uriQualifier  = new UriQualifier(this.fakeBaseHref);
     this.authenticator = new BasicRequestAuthenticator();
     this.apiKey        = new DefaultClientApiKey(this.fakeApiKeyId, this.fakeApiKeySecret);
 }
コード例 #21
0
        void IRequestAuthenticator.Authenticate(IHttpRequest request, IClientApiKey apiKey)
        {
            var now = DateTimeOffset.UtcNow;

            this.AuthenticateCore(request, apiKey, now);
        }
コード例 #22
0
 public BasicRequestAuthenticator_tests()
 {
     this.uriQualifier = new UriQualifier(this.fakeBaseHref);
     this.authenticator = new BasicRequestAuthenticator();
     this.apiKey = new DefaultClientApiKey(this.fakeApiKeyId, this.fakeApiKeySecret);
 }