Проверьте маркер Oauth Bearer, отсутствует IIssuerSecurityTokenProvider в Microsoft.Owin.Security.Jwt 4.x - PullRequest
0 голосов
/ 04 июля 2019

Я пытаюсь заставить мой .Net Web API (приложение Azure API, использующее OWIN) принять маркер OAuth Bearer для гранта client_credentials, но я продолжаю получать 401 Unauthorized.

Также кажется, что все образцы Microsoft устарели (не соответствуют последним пакетам nuget для Owin).

JwtFormat раскрывает IIssuerSecurityTokenProvider, но он больше не существует - вместо этого JwtFormat ожидает IIssuerSecurityKeyProvider, но я не могу обернуться, как его использовать.

Сервер Azure OAuth работает

Я зарегистрировал два приложения (API и клиент) в Azure Active Directory. Поскольку это всего лишь небольшая демонстрация, я дам вам все идентификаторы и секреты;)

Я могу получить токен от Azure AD, см. https://reqbin.com/817shtc2 для полного запроса, пока что все хорошо.

API

ClientId : 44cf7574-88a2-42d6-9497-bff43cc8dc09

Конечная точка : https://apim -demo-mglentoft.azure-api.net / api / Значения (GET)

Клиент

ClientId : 5f7ee334-b8db-46d3-972f-09f52e186d1d

Секрет : ggKp94] HZHWZ.c * 5wUC? ToSVfknyqLB3

Я следовал за примером на https://github.com/azureadquickstarts/appmodelv2-nativeclient-dotnet,, но он ссылается на Microsoft.Owin.Security.Jwt.IIssuerSecurityTokenProvider, которого нет в nuget v4.0.1.0.

Я попытался просто закомментировать второй параметр для JwtFormat, но это не работает. Любые идеи, как заставить это работать, используя Microsoft.Owin.Security.Jwt.IIssuerSecurityKeyProvider?

Ниже представлен весь startup.cs

Я могу заставить это работать, используя .Net Core, но по разным причинам мне приходится придерживаться .Net Framework 4.7.2

using System;
using System.Configuration;
using System.Threading.Tasks;
using System.Web.Http;
using DemoAPI.Middleware;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Jwt;
using Microsoft.Owin.Security.OAuth;
using Owin;

[assembly: OwinStartup(typeof(DemoAPI.App_Start.Startup))]

namespace DemoAPI.App_Start
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var config = new HttpConfiguration();

            ConfigureAuth(app);
            app.Use(typeof(CorrelationHandlerMiddleware));


            app.UseCors(CorsOptions.AllowAll);
            WebApiConfig.Register(config);
            app.UseWebApi(config);
        }

        private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];

        public void ConfigureAuth(IAppBuilder app)
        {
            // NOTE: The usual WindowsAzureActiveDirectoryBearerAuthentication middleware uses a
            // metadata endpoint which is not supported by the v2.0 endpoint.  Instead, this 
            // OpenIdConnectSecurityTokenProvider implementation can be used to fetch & use the OpenIdConnect
            // metadata document - which for the v2 endpoint is https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration


            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
            {
                AccessTokenFormat = new JwtFormat(
                    new TokenValidationParameters
                    {
                        // Check if the audience is intended to be this application
                        ValidAudiences = new[] { clientId, $"api://{clientId}" },`enter code here`

                        // Change below to 'true' if you want this Web API to accept tokens issued to one Azure AD tenant only (single-tenant)
                        // Note that this is a simplification for the quickstart here. You should validate the issuer. For details, 
                        // see https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore
                        ValidateIssuer = false,

                    }//,
                     //new OpenIdConnectSecurityKeyProvider("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration")
                     //the OpenIdConnectSecurityKeyProvider implements IIssuerSecurityTokenProvider, which is not part of Microsoft.Owin.Security.Jwt 4.0
                ),
            });
        }
    }
}

Фактическая ошибка при использовании Microsoft.Owin.diagnostics

Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Ошибка: 0: аутентификация не удалась Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10501: Ошибка проверки подписи. Невозможно сопоставить ключ: kid: «[PII скрыт. Для получения более подробной информации см. https://aka.ms/IdentityModel/PII.]'. Исключения: '[PII is скрытый. Для получения более подробной информации см. https://aka.ms/IdentityModel/PII.]'. жетон: «[PII скрыт. Для получения более подробной информации см. https://aka.ms/IdentityModel/PII.]'. в System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature (String token, TokenValidationParameters validationParameters) в System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken (String токен, TokenValidationParameters validationParameters, SecurityToken & validatedToken)

Ответы [ 2 ]

1 голос
/ 04 июля 2019

попробуйте переименовать 'token' в 'key', и вы можете быть в порядке.

Итак, вместо

    IssuerSecurityTokenProviders = new IIssuedSecurityTokenProvider[]
                                   {
                                       new symmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
                                   }

У вас должно быть что-то вроде

    IssuerSecurityKeyProviders= new IIssuerSecurityKeyProvider[]
                                   {
                                       new SymmetricKeyIssuerSecurityKeyProvider(issuer, audienceSecret)
                                   }

Для получения дополнительной информации: Тема выпуска или Фактический репозиторий Github

Надеюсь, это поможет вам ...

0 голосов
/ 07 июля 2019

Я пойду дальше и отвечу на свой вопрос здесь, так как я заставил его работать, слегка изменив выборку в https://github.com/azureadquickstarts/appmodelv2-nativeclient-dotnet.

Может быть, Ответ Стефа также работает, и я просто что-то сделал не так - но вы отправили меня в правильном направлении :)

in Startup.cs :

Я изменил с реализации IIssuerSecurityTokenProvider на IIssuerSecurityKeyProvider (спасибо Stef )

string issuerEndpoint = @"https://sts.windows.net/919e9a01-27bf-4106-9d36-48528249d0ce/";
            string metadaEndpoint = $"{issuerEndpoint}v2.0/.well-known/openid-configuration";

            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
            {
                AccessTokenFormat = new JwtFormat(
                    new TokenValidationParameters
                    {
                        // Check if the audience is intended to be this application
                        ValidAudiences = new[] { clientId, $"api://{clientId}" },

                        // Change below to 'true' if you want this Web API to accept tokens issued to one Azure AD tenant only (single-tenant)
                        // Note that this is a simplification for the quickstart here. You should validate the issuer. For details, 
                        // see https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore
                        ValidateIssuer = false,

                    },
                     new OpenIdConnectSecurityKeyProvider("https://sts.windows.net/919e9a01-27bf-4106-9d36-48528249d0ce/v2.0/.well-known/openid-configuration")
                ),
            });

OpenIDConnectSecurityKeyProvider.cs

Реализация на основе образца из https://github.com/azureadquickstarts/appmodelv2-nativeclient-dotnet, изменила его для получения ключей вместо токенов.

using System.Collections.Generic;
using System.Threading;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin.Security.Jwt;

namespace DemoAPI.App_Start
{
    //This class is necessary because the OAuthBearer Middleware does not leverage
    // the OpenID Connect metadata endpoint exposed by the STS by default.

    public class OpenIdConnectSecurityKeyProvider : IIssuerSecurityKeyProvider
    {
        public ConfigurationManager<OpenIdConnectConfiguration> ConfigManager;
        private string _issuer;
        private IEnumerable<SecurityKey> _keys;
        private readonly string _metadataEndpoint;

        private readonly ReaderWriterLockSlim _synclock = new ReaderWriterLockSlim();

        public OpenIdConnectSecurityKeyProvider(string metadataEndpoint)
        {
            _metadataEndpoint = metadataEndpoint;
            ConfigManager = new ConfigurationManager<OpenIdConnectConfiguration>(metadataEndpoint, new OpenIdConnectConfigurationRetriever());

            RetrieveMetadata();
        }

        /// <summary>
        /// Gets the issuer the credentials are for.
        /// </summary>
        /// <value>
        /// The issuer the credentials are for.
        /// </value>
        public string Issuer
        {
            get
            {
                RetrieveMetadata();
                _synclock.EnterReadLock();
                try
                {
                    return _issuer;
                }
                finally
                {
                    _synclock.ExitReadLock();
                }
            }
        }

        public IEnumerable<SecurityKey> SecurityKeys
        {
            get
            {
                RetrieveMetadata();
                _synclock.EnterReadLock();
                try
                {
                    return _keys;
                }
                finally
                {
                    _synclock.ExitReadLock();
                }
            }
        }

        private void RetrieveMetadata()
        {
            _synclock.EnterWriteLock();
            try
            {
                OpenIdConnectConfiguration config = ConfigManager.GetConfigurationAsync().Result;
                _issuer = config.Issuer;
                _keys = config.SigningKeys;
            }
            finally
            {
                _synclock.ExitWriteLock();
            }
        }
    }
}
...