Подтвердить что ты не робот

Второй вход вызывает бесконечный цикл перенаправления после первого успешного входа в систему. MVC.NET 5 OWIN ADAL OpenIDConnect

первый пост, будьте нежны!:)

Я разрабатываю веб-приложение MVC.NET 5 для Office 365 и использую структуру OpenIDConnect. Я установил OWIN (3) и ADAL (2) и мое приложение Azure AD. Нет логина для входа пользователя, у домашнего контроллера есть атрибут [Авторизовать], заставляющий немедленный переадресацию входа в Azure AD. Я не использую роли в любом из моих атрибутов Authorize.

Проблема. Я могу войти в мои приложения успешно - ОДИН! После первого входа я закрываю браузер (или открываю новый браузер на другой машине), и я снова ударяю приложение. Он перенаправляет меня на экран входа в Azure AD, в который я вхожу, и затем он постоянно перенаправляет между приложением и Azure, пока я не получу печально известный 400 заголовков. Заглядывая в магазин печенья, я нахожу его полным нонче. Я проверяю кеш (рецепт Vittorio EFADALCache, хотя я использовал TokenCache.DefaultShared, когда эта проблема была обнаружена) и содержит сотни строк данных кэша (только одна строка, сгенерированная с успешным знаком).

Я вижу, что через выходное окно происходят перенаправления, когда каждый обратный маршрут генерирует новый токен доступа и обновления:

Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenByAuthorizationCodeHandler: Resource value in the token response was used for storing tokens in the cache
iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenByAuthorizationCodeHandler: Resource value in the token response was used for storing tokens in the cache
Microsoft.IdentityModel.Clients.ActiveDirectory Information: 2 : 31/07/2015 12:31:52:  - TokenCache: Deserialized 1 items to token cache.
iisexpress.exe Information: 0 : 31/07/2015 12:31:52:  - TokenCache: Deserialized 1 items to token cache.
Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: Storing token in the cache...
iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: Storing token in the cache...
Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: An item was stored in the cache
iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: An item was stored in the cache
Microsoft.IdentityModel.Clients.ActiveDirectory Information: 2 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenHandlerBase: === Token Acquisition finished successfully. An access token was retuned:
    Access Token Hash: PN5HoBHPlhhHIf1lxZhEWb4B4Hli69UKgcle0w7ssvo=
    Refresh Token Hash: 3xmypXCO6MIMS9qUV+37uPD4kPip9WDH6Ex29GdWL88=
    Expiration Time: 31/07/2015 13:31:51 +00:00
    User Hash: GAWUtY8c4EKcJnsHrO6NOzwcQDMW64z5BNOvVIl1vAI=

Уведомление AuthorizationCodeReceived в моем OpenIdConnectAuthenticationOptions ударяется, когда проблема возникает, поэтому я знаю, что Azure считает, что логин был успешным (или перенаправление обратно к приложению не произойдет):

    private static void PrepO365Auth(IAppBuilder app)
    {

        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions());

        //Configure OpenIDConnect, register callbacks for OpenIDConnect Notifications
        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {

                ClientId = ConfigHelper.ClientId,
                Authority = authority,
                PostLogoutRedirectUri = "https://localhost:44300/Account/SignedOut",
                RedirectUri = "https://localhost:44300/",
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthorizationCodeReceived = (context) =>
                    {
                        ClientCredential credential = new ClientCredential(ConfigHelper.ClientId, ConfigHelper.AppKey);
                        string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;

                        AuthenticationContext authContext = new AuthenticationContext(authority, new EFADALTokenCache(signedInUserID)); // TokenCache.DefaultShared Probably need a persistent token cache to handle app restarts etc
                        AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
                            context.Code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, ConfigHelper.GraphResourceId);

                        return Task.FromResult(0);
                    },

                    AuthenticationFailed = context =>
                    {
                        context.HandleResponse();
                        context.Response.Redirect("/Error/ShowError?signIn=true&errorMessage=" + context.Exception.Message);
                        return Task.FromResult(0);
                    }
                }
            });
    }
}

Я заменил (после обнаружения проблемы) Авторизованный атрибут с моим собственным атрибутом Auth, наследующим от AuthorizeAttribute, чтобы я мог попытаться войти в код авторизации и посмотреть, что происходит. Я построил PDB файл из версии исходного кода версии MVC 5 версии 5, но все, что происходит, это то, что оно возвращается в мой собственный код:( Как говорится, я переопределил все, что мог, и нашел, что filterContext.HttpContext.User.Identity.IsAuthenticated является ложным, что имеет смысл, так как это приведет к перенаправлению обратно к значку Azure.

Итак, я знаю, что:

  • Azure принимает мой логин и возвращает соответствующие токены
  • При втором входе в систему, перед OnAuthorization, filterContext.HttpContext.User.Identity.IsAuthenticated возвращает false
  • Конфигурация приложения Azure хорошо, или вообще не будет аутентифицироваться

Я думаю, что:

  • В настройке MVC Identity есть что-то неправильное. Azure работает правильно или вообще не аутентифицируется.
  • Это не проблема с cookie, так как проблема возникает, если вы выполняете второй вход на другой машине.

Мне жаль, что это немного длиннее, но есть так много из этих бесконечных проблем с перенаправлением, мне нужно было объяснить, почему моя ситуация была иной!

То, что я ищу (если не ответ!), - это толкание в правильном направлении относительно того, как я могу отлаживать дальше.

Цените любую помощь, которую вы можете дать!

Andy

4b9b3361

Ответ 1

Найди ответ для всех, кого это интересует. Это известная ошибка в Катане, где менеджер файлов cookie Katana и менеджер cookie ASP.NET сталкиваются и перезаписывают друг другу файлы cookie. Полная информация и обходные пути здесь:

http://katanaproject.codeplex.com/wikipage?title=System.Web%20response%20cookie%20integration%20issues&referringTitle=Documentation

Отображаемый ниже SystemWebCookieManager теперь можно найти в пакете Nuget Microsoft.Owin.Host.SystemWeb.

Добавление кода, когда умирает CodePlex:

//stick this in public void ConfigureAuth(IAppBuilder app)
  app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                // ...
                CookieManager = new SystemWebCookieManager()
            });

//And create this class elsewhere:
public class SystemWebCookieManager : ICookieManager
    {
        public string GetRequestCookie(IOwinContext context, string key)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
            var cookie = webContext.Request.Cookies[key];
            return cookie == null ? null : cookie.Value;
        }

        public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);

            bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
            bool pathHasValue = !string.IsNullOrEmpty(options.Path);
            bool expiresHasValue = options.Expires.HasValue;

            var cookie = new HttpCookie(key, value);
            if (domainHasValue)
            {
                cookie.Domain = options.Domain;
            }
            if (pathHasValue)
            {
                cookie.Path = options.Path;
            }
            if (expiresHasValue)
            {
                cookie.Expires = options.Expires.Value;
            }
            if (options.Secure)
            {
                cookie.Secure = true;
            }
            if (options.HttpOnly)
            {
                cookie.HttpOnly = true;
            }

            webContext.Response.AppendCookie(cookie);
        }

        public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            AppendResponseCookie(
                context,
                key,
                string.Empty,
                new CookieOptions
                {
                    Path = options.Path,
                    Domain = options.Domain,
                    Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
                });
        }
    }

Я тоже сделал это: https://gist.github.com/irwinwilliams/823f43ef8a5e8019a95874049dbb8b00

Ответ 2

У меня не было точно описанной проблемы, но у меня был цикл переадресации во время входа на основе OpenId, а также на моей машине DEV.

В моем случае это была простая ошибка с файлами cookie. Я обращался к защищенному URL через HTTP. Убедитесь, что вы используете защищенный URL-адрес своей полагающейся стороны через HTTPS.

После аутентификации cookie аутентификации будет отправляться только через HTTPS, это означает, что при доступе к защищенному URL через HTTP браузер не отправит ваш файл cookie с запросом, и, следовательно, сервер увидит вас как не прошедший проверку. На этом этапе сервер перенаправит вас на сервер auth (где вы уже вошли в систему). Сервер Auth перенаправляет вас обратно на исходный URL-адрес, тем самым обеспечивая цикл перенаправления.

Это никогда не должно происходить в ваших развертываниях, потому что вы всегда должны использовать all-SSL в своем приложении, если у вас есть такие функции, как проверка подлинности. Это снижает риск захвата сеанса.

Ответ 3

У меня была точно такая же проблема. Невозможно изменить URL-адрес от HTTP до HTTPS из-за других зависимостей. Окончательно разрешено путем добавления session_start и session_end в global.asax.cs

  protected void Session_Start(object sender, EventArgs e)
        {
            // event is raised each time a new session is created     
        }

  protected void Session_End(object sender, EventArgs e)
        {
            // event is raised when a session is abandoned or expires

        }

Ответ 4

Я столкнулся с этой проблемой и применил ВСЕ ИСПЫТАНИЯ В ИНТЕРНЕТЕ. Ни один из них не работал, затем я вошел и посмотрел на свой файл cookie. Это было огромно. Owin-посредник обрезал его, а затем атрибут [Авторизовать] не смог проверить личность → отправить пользователю oidc → идентификатор хорошо - перенаправить на клиент → truncate cookie → не может подтвердить в [Авторизовать] → отправить пользователя на oidc → и т.д.

Исправление было в Microsoft.Owin.Host.SystemWeb 3.1.0.0 и использовании SystemWebChunkingCookieManager.

Он разделит файлы cookie и проанализирует их вместе.

  app.UseCookieAuthentication(new CookieAuthenticationOptions
  {
      AuthenticationType = "Cookies",
      CookieManager = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager()
  });

Ответ 5

Следующий код разрешил мою проблему, добавив события сеанса в файл Golbal.asax.cs.

protected void Session_Start(object sender, EventArgs e)
    {
        // event is raised each time a new session is created     
    }



protected void Session_End(object sender, EventArgs e)
    {
        // event is raised when a session is abandoned or expires

    }

И добавив ниже код в общедоступный метод ConfigureAuth (IAppBuilder) для файла Startup.Auth.cs

  app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "Cookies",
            CookieManager = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager()
        });