private async Task <HttpResponseMessage> SendAuthenticatedRequest(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            await EnsureValidAccessTokenAsync(cancellationToken);

            request.Headers.Authorization = new AuthenticationHeaderValue(AccessTokenTypeParser.ToString(_accessToken.Type), _accessToken.Value);
            return(await base.SendAsync(request, cancellationToken));
        }
        private AccessTokenType ParseAccessTokenType(string str)
        {
            var type = AccessTokenTypeParser.FromString(str);

            if (!type.HasValue)
            {
                throw new InvalidOperationException($"Unknown access token type '{str}'");
            }

            return(type.Value);
        }
Example #3
0
        private async Task WriteAccessTokenAsync(IOwinResponse response, string accessToken, AccessTokenType accessTokenType, TimeSpan expiresIn)
        {
            response.ContentType = "application/json; charset=UTF-8";

            var tokenObj = new JObject(
                new JProperty("access_token", accessToken),
                new JProperty("token_type", AccessTokenTypeParser.ToString(accessTokenType)),
                new JProperty("expires_in", (int)expiresIn.TotalSeconds));

            await response.WriteAsync(tokenObj.ToString());
        }
Example #4
0
        public static void SetAuthenticationFailed(
            this IOwinResponse response,
            AccessTokenType type,
            string error,
            string errorDescription = null,
            string requiredScope    = null)
        {
            if (error == null)
            {
                throw new ArgumentNullException(nameof(error));
            }

            if (error == AuthenticationErrorCodes.InvalidRequest)
            {
                response.StatusCode = 400;
            }

            if (error == AuthenticationErrorCodes.InvalidToken)
            {
                response.StatusCode = 401;
            }

            if (error == AuthenticationErrorCodes.InsufficentScope)
            {
                response.StatusCode = 403;
            }

            response.OnSendingHeaders(rsp =>
            {
                var sb = new StringBuilder($@"{AccessTokenTypeParser.ToString(type)} error=""{error}""");

                if (!string.IsNullOrEmpty(errorDescription))
                {
                    sb.Append($@",error_description=""{errorDescription}""");
                }

                if (!string.IsNullOrEmpty(requiredScope))
                {
                    sb.Append($@",scope=""{requiredScope}""");
                }

                ((IOwinResponse)rsp).Headers.Set(
                    "WWW-Authenticate",
                    sb.ToString()
                    );
            }, response);
        }
 private static bool IsInvalidToken(HttpResponseMessage response)
 {
     return(response.Headers.WwwAuthenticate.Any(x =>
                                                 AccessTokenTypeParser.FromString(x.Scheme).HasValue&&
                                                 HttpHeaderUtils.ParseOAuthSchemeParameter(x.Parameter)["error"].Equals(AuthenticationErrorCodes.InvalidToken, StringComparison.OrdinalIgnoreCase)));
 }
        public async Task <AccessToken> GetTokenAsync(GenericXmlSecurityToken securityToken, CancellationToken cancellationToken)
        {
            if (securityToken == null)
            {
                throw new ArgumentNullException(nameof(securityToken));
            }

            string samlToken;

            using (var stream = new MemoryStream())
            {
                using (var writer = XmlWriter.Create(stream))
                {
                    securityToken.TokenXml.WriteTo(writer);
                }

                samlToken = Convert.ToBase64String(stream.ToArray());
            }

            var requestHandler = new WebRequestHandler
            {
                ClientCertificates = { _settings.ClientCertificate }
            };

            var formFields = new Dictionary <string, string>
            {
                { "saml-token", samlToken }
            };

            if (_settings.DesiredAccessTokenExpiry.HasValue)
            {
                formFields["should-expire-in"] =
                    ((int)_settings.DesiredAccessTokenExpiry.Value.TotalSeconds).ToString();
            }

            var client   = new HttpClient(requestHandler);
            var response = await client.PostAsync(
                _settings.AccessTokenIssuerEndpoint,
                new FormUrlEncodedContent(formFields),
                cancellationToken);

            if (!response.IsSuccessStatusCode)
            {
                //just find the first valid authenticate header we recognize
                var challenge = response.Headers.WwwAuthenticate
                                .Select(x => new
                {
                    Type = AccessTokenTypeParser.FromString(x.Scheme),
                    x.Parameter
                })
                                .FirstOrDefault(x => x.Type.HasValue);

                if (challenge != null)
                {
                    var parms = HttpHeaderUtils.ParseOAuthSchemeParameter(challenge.Parameter);
                    throw new OioIdwsChallengeException(
                              challenge.Type.Value,
                              parms["error"],
                              parms["error_description"],
                              $@"Got unexpected challenge while issuing access token from '{
                                _settings.AccessTokenIssuerEndpoint
                            }'
({response.StatusCode})': {parms["error"]} - {parms["error_description"]}");
                }

                throw new InvalidOperationException(
                          $@"Got unexpected response while issuing access token from '{_settings.AccessTokenIssuerEndpoint}'
{response.StatusCode}: {await response.Content.ReadAsStringAsync()}");
            }

            var json = await response.Content.ReadAsStringAsync();

            var jsonValue = JObject.Parse(json);

            var accessToken = new Rest.Client.AccessToken.AccessToken
            {
                Value          = (string)jsonValue["access_token"],
                ExpiresIn      = TimeSpan.FromSeconds((int)jsonValue["expires_in"]),
                RetrievedAtUtc = DateTime.UtcNow,
                Type           = ParseAccessTokenType((string)jsonValue["token_type"])
            };

            return(accessToken);
        }
        protected override async Task <AuthenticationTicket> AuthenticateCoreAsync()
        {
            try
            {
                AuthenticationHeaderValue authHeader;
                if (AuthenticationHeaderValue.TryParse(Context.Request.Headers["Authorization"], out authHeader))
                {
                    var requestAccessTokenType = AccessTokenTypeParser.FromString(authHeader.Scheme);

                    if (!requestAccessTokenType.HasValue)
                    {
                        _logger.WriteVerbose($"Ignoring unhandled authorization scheme '{authHeader.Scheme}'");
                        return(null);
                    }

                    var accessToken = authHeader.Parameter;

                    _logger.WriteEntry(Log.ProcessingToken(accessToken));

                    //The token provider validates that the token is known and not expired.
                    var tokenRetrievalResult = await Options.TokenProvider.RetrieveTokenAsync(accessToken);

                    if (tokenRetrievalResult.Success)
                    {
                        var token = tokenRetrievalResult.Result;

                        if (requestAccessTokenType != token.Type)
                        {
                            StoreAuthenticationFailed(AuthenticationErrorCodes.InvalidToken, "Authentication scheme was not valid", token.Type);
                            _logger.WriteEntry(Log.InvalidTokenType(authHeader.Scheme));
                            return(null);
                        }

                        if (token.Type == AccessTokenType.HolderOfKey)
                        {
                            var cert = Context.Get <X509Certificate2>("ssl.ClientCertificate");

                            if (cert?.Thumbprint == null || !cert.Thumbprint.Equals(token.CertificateThumbprint, StringComparison.OrdinalIgnoreCase))
                            {
                                StoreAuthenticationFailed(AuthenticationErrorCodes.InvalidToken, "A valid certificate must be presented when presenting a Holder-of-key token", requestAccessTokenType.Value);
                                _logger.WriteEntry(Log.HolderOfKeyNoCertificatePresented(accessToken, cert?.Thumbprint));
                                return(null);
                            }
                        }

                        var identity = await Options.IdentityBuilder.BuildIdentityAsync(token);

                        _logger.WriteEntry(Log.TokenValidatedAndRequestAuthenticated(accessToken));
                        return(new AuthenticationTicket(identity, new AuthenticationProperties()));
                    }

                    if (tokenRetrievalResult.Expired)
                    {
                        _logger.WriteEntry(Log.TokenExpired(accessToken));
                        StoreAuthenticationFailed(AuthenticationErrorCodes.InvalidToken, "Token was expired", AccessTokenTypeParser.FromString(authHeader.Scheme) ?? AccessTokenType.Bearer);
                    }
                    else
                    {
                        _logger.WriteEntry(Log.TokenWasNotRetrievedFromAuthorizationServer(accessToken));
                        StoreAuthenticationFailed(AuthenticationErrorCodes.InvalidToken, "Token information could not be retrieved from the Authorization Server. The access token might be unknown or expired", requestAccessTokenType.Value);
                    }

                    return(null);
                }
            }
            catch (Exception ex)
            {
                _logger.WriteError("Unhandled exception", ex);
            }

            return(null);
        }