Как я могу пройти аутентификацию в Microsoft Graph, если мое приложение использует Azure "Easy Auth" - PullRequest
1 голос
/ 11 июля 2019

Я пытаюсь выполнить поиск основной пользовательской информации в Azure Active Directory в установленном приложении ASP.NET MVC с использованием Microsoft Graph SDK. Не обнаружив упоминаний об использовании этих двух элементов вместе и о том, что мои собственные попытки реализации не увенчались успехом, я задаюсь вопросом, сделал ли это кто-то еще, или известно, что это невозможно.

В настоящее время наше приложение размещено в службе приложений Azure (xyz.azurewebsites.net), которая настроена на проверку подлинности всех запросов перед доступом к приложению. Я понимаю, что это называется «Easy Auth», как задокументировано здесь или здесь .

В качестве теста я более или менее выполнил шаги, описанные в этого учебного пособия , понимая, что оно предназначено для регистрации приложения Azure Active Directory. Я добавил контроллер barebones в проект, который вызвал еще одну проблему аутентификации, например:

public void Index()
{
    // Signal OWIN to send an auth request to Azure
    Request.GetOwinContext().Authentication.Challenge(
        new AuthenticationProperties { RedirectUri = "/" },
        OpenIdConnectAuthenticationDefaults.AuthenticationType);
}

Задача аутентификации может быть успешно завершена (даже если пользователь авторизован уже через xyz.azurewebsites.net). Проверка ответа после завершения вызова показывает, что я получаю ответ code в данных формы. Однако код, который должен выполнить и обработать успешную аутентификацию, никогда этого не делает (он показан внизу этого поста).

По сути, текущий поток таков:

  1. Пользователь переходит на xyz.azurewebsites.net
  2. xyz.azurewebsites.net видит, что пользователь не аутентифицирован, и переносит их на login.microsoftonline.com/{tenant}/oauth2/authorize
  3. Пользователь вводит свои учетные данные для AAD и регистрируется, попадая на корневую страницу xyz.azurewebsites.net

Все, что за этим пунктом, тестируется

  1. Для тестирования я перехожу к xyz.azurewebsites.net/signin, где запускается вышеуказанный метод Index() (подтверждено удаленной отладкой)
  2. Задача перенаправляет меня на login.microsoftonline.com/common/oauth2/v2.0/authorize, и я снова ввожу учетные данные
  3. После успешного входа в систему меня перенаправили на xyz.azurewebsites.net и сообщили, что «у вас нет разрешения на просмотр этого каталога или страницы». Метод, который я ожидаю встретить при успешной аутентификации, никогда не запускается (подтверждено удаленной отладкой)
  4. После перехода в другие местоположения на сайте я могу получить доступ к этим страницам, что говорит о том, что я все еще аутентифицирован с помощью «Easy Auth». Мой метод проверки наличия доступа к Microsoft Graph тоже не работает.

Для тестирования мне хотелось бы, чтобы пользователь снова вводил учетные данные, успешно перенаправлялся на домашнюю страницу и контроллеры могли каким-либо образом получать доступ к Microsoft Graph.

Идеи

Некоторые идеи о том, что может помешать успеху:

  • Возможно, что то, о чем я прошу, просто не может быть сделано, и нам придется атаковать это под другим углом.

  • Я думаю, что ошибка отказа в разрешении, описанная в шаге 6, связана с обратным вызовом из вызова Graph, не включающим токен доступа, который обычно добавляется в заголовки запроса с помощью Easy Auth. Таким образом, последующие запросы будут перехватываться программой Easy Auth и работать, но поскольку первоначальный обратный вызов не выполнен, код, который, как ожидается, будет выполнен при успешном вызове, не будет обработан.

  • Если возможно, возможно, необходимо настроить службу приложения для возврата маркеров доступа для Microsoft Graph.

Код запуска OWIN

using Owin;
using Microsoft.Graph;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Notifications;
using Microsoft.Owin.Security.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Identity.Client;
using System.Configuration;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using xyz.Utilities;

[assembly: OwinStartup(typeof(xyz.Startup))]

namespace xyz
{
    public class Startup
    {
        private static string appId = ConfigurationManager.AppSettings["AzureActiveDirectoryAppId"];
        private static string appSecret = ConfigurationManager.AppSettings["AzureActiveDirectoryAppSecret"];
        private static string redirectUri = ConfigurationManager.AppSettings["AzureActiveDirectoryRedirectUri"];
        private static string graphScopes = ConfigurationManager.AppSettings["AzureActiveDirectoryGraphScopes"];

        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
            // This executes upon startup and configures the app.
        }

        public void ConfigureAuth(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions());

            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = appId,
                    Authority = "https://login.microsoftonline.com/common/v2.0",
                    Scope = $"openid email profile offline_access {graphScopes}",
                    RedirectUri = redirectUri,
                    PostLogoutRedirectUri = redirectUri,
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = false // May need to be changed. See https://docs.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.tokens.tokenvalidationparameters?view=azure-dotnet
                    },
                    Notifications = new OpenIdConnectAuthenticationNotifications 
                    {
                        AuthenticationFailed = OnAuthenticationFailedAsync,
                        AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
                    }
                }
           );
        }

        private Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
        {
            notification.HandleResponse();
            throw new System.Exception("Authentication Failed"); // This may need to be changed to redirect the user so they can try again.
        }

        private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
        {
            // This function does not execute once authentication is complete through /SignIn


            var idClient = ConfidentialClientApplicationBuilder.Create(appId)
                                                               .WithRedirectUri(redirectUri)
                                                               .WithClientSecret(appSecret)
                                                               .Build();

            var signedInUser = new ClaimsPrincipal(notification.AuthenticationTicket.Identity);
            var tokenStore = new SessionTokenStore(idClient.UserTokenCache, HttpContext.Current, signedInUser);

            string[] scopes = graphScopes.Split(' ');
            var result = await idClient.AcquireTokenByAuthorizationCode(scopes, notification.Code).ExecuteAsync();

            User userDetails = await GraphUtility.GetUserDetailAsync(result.AccessToken);

            string email = string.IsNullOrEmpty(userDetails.Mail) ? userDetails.UserPrincipalName : userDetails.Mail;

            var cachedUser = new CachedUser()
            {
                DisplayName = userDetails.DisplayName,
                Email = string.IsNullOrEmpty(userDetails.Mail) ? userDetails.UserPrincipalName : userDetails.Mail
            };

            tokenStore.SaveUserDetails(cachedUser);

        }
    }
}

1 Ответ

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

Это очень странно войти в систему дважды.Служба приложений передает заявки пользователей в ваше приложение, используя специальные заголовки.Для приложений ASP.NET 4.6 ClaimsPrincipal автоматически устанавливается с соответствующими значениями.

Некоторые примеры заголовков включают в себя:

  • X-MS-CLIENT-PRINCIPAL-NAME
  • X-MS-CLIENT-PRINCIPAL-ID

Если вы просто хотите получить доступ к заявкам пользователя , вы можете использовать этот способ.

Если вам нужно вызвать дополнительный граф apis, вы также можете получить токен доступа в заголовке запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...