Условно используйте ADFS для входа - PullRequest
2 голосов
/ 15 марта 2019

У меня есть требование интегрировать ADFS для одного из наших клиентов.

Мы используем токены OWIN и OAuth Bearer, а также JWT Bearer Auth. Все это работает хорошо. Введите имя пользователя (адрес электронной почты) и пароль, выполните аутентификацию в нашем хранилище пользователей базы данных, получите токен на предъявителя.

Нам нужно только запросить у сервера ADFS клиента аутентификацию, когда введенное имя пользователя находится в определенном домене - у клиента. (Нам не нужно спрашивать пароль; сначала логин был изменен, чтобы спрашивать электронную почту, проверьте, является ли это доменом клиента, а затем, если нет, то спросите пароль - посмотрите, как это делает Box.com, это очень похоже. )

В настоящее время мы вообще не используем AD, и у нас нет заводов для этого, что означает, что все «федеративные» примеры, разбросанные по Интернету, никоим образом не помогают нам, поскольку предполагают, что вы уже используете ADFS или Azure AD, а мы нет.

Наше мобильное приложение использует библиотеку ADAL 1.0 и хорошо работает до определенного момента (для работы также требуется # 2)

1) Я не могу понять, как перенаправить браузер пользователя на страницу входа ADFS клиента. Все использует библиотеку, и все эти библиотеки настраиваются во время компиляции - тогда как я не знаю, в какую клиентскую ADFS отправлять пользователя, пока этот пользователь не запустит процесс входа в систему во время выполнения. Кроме того, это не использует Azure AD, это локальный сервер, поэтому я не могу использовать шлюз Microsoft.

2) Обратному вызову необходимо проанализировать токен пользователя, убедиться, что он предназначен для нас, пройти все проверки подписи, а затем мы выпускаем собственный токен на предъявителя - мы не можем использовать клиентский токен. Это должно быть относительно просто, но я не знаю, как сказать конечной точке ADFS, что такое URL обратного вызова.

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

Дополнительная информация:

Клиентская ADFS - 3,0

У меня есть возможность использовать для этого аутентификацию OWIN, и, возможно, я могу настроить клиентов во время компиляции при нажатии.

1 Ответ

0 голосов
/ 25 марта 2019

Хорошо.Я уверен, что я собираюсь получить немного дерьма для этого, но здесь идет.

Мы закончили использовать OAuth2 условно - изучите адрес электронной почты пользователя, посмотрите на домен и загрузите информацию конфигурации для ихОпыт единого входа.

Мне не удалось найти промежуточное программное обеспечение OAuth2 для OWIN, которое я мог бы вызвать условно (библиотеки ADAL не работали, даже когда я настраивал их с подписями и в пассивном режиме), поэтомуВ итоге я вручную перенаправил на IDP с соответствующими параметрами.Наш разработчик мобильных приложений использует ADAL 1.0 с Xamarin, поэтому я смог получить URL-адрес OAuth2 из этого рабочего процесса (https://adfs.example.net/oauth2/authorize) и перенаправить туда.

Для решения шага 1: я создал конечную точку обратного вызова OAuth2(который должен быть зарегистрирован в ADFS! У меня есть параметр строки запроса, который является подсказкой относительно того, какую конфигурацию единого входа следует загрузить, но это не может измениться вообще - она ​​всегда должна быть одинаковой для этого одного IdP), и установите метод дляпоменяйте местами параметр строки запроса «code» для токена. Это довольно простой вызов HTTPS, но вам придется как самостоятельно проверить токен (что требуется для моего шага 2 требования), так и иметь кучу кода длявыкопайте адрес электронной почты / утверждение имени пользователя. Вы должны настроить типы предоставления для его передачи и быть готовыми к обработке различных пространств имен утверждений. Не забудьте передать свой URL обратного вызова - стандарт OAuth2 требует, чтобы вы передали его снова, без изменений - или вашкод недействителен.

После проверки того, что токен был действительным токеном, используяотличная библиотека System.IdentityModel.Tokens.Jwt (вам нужно обратиться к другим вопросам о переполнении стека о том, как загружать сертификаты X509 в формате PEM, так как мы хотели сохранить в базе данных ключ публикации IDP в формате PEM в формате ascii-armored - код для его получениясчитается приемлемым в данный момент), И было для ожидаемой аудитории И, что эмитент был тем, кого вы ожидали (в случае, если кто-то попытается возиться с подсказками домена) И что подпись совпадает (что ловит большинство из них ранееслучаи), И чтобы он совпадал с адресом электронной почты, который набрал пользователь (это то, что делает промежуточное программное обеспечение OWIN «Внешние файлы cookie», когда вы можете его использовать):

Тогда и только тогда вы можете выдать токен.

Мне пришлось сохранить ссылку (мы используем Autofac) на нашу библиотеку защиты JWT в нашем коде запуска:

builder.RegisterInstance(customFormat).As<ISecureDataFormat<AuthenticationTicket>>();

ISecureDataFormat - это то, что зарегистрировано длязащитить / снять защиту ключей JWT.Мне не удалось найти способ подключиться к объекту аутентификации OWIN, чтобы найти способ найти этот экземпляр как свойство где-либо, поэтому мне пришлось хранить ссылку на него в нашем модуле IoC.

Наш логинКод (пользовательский поставщик аутентификации) выглядит примерно так:

        var cookiesIdentity = await _userManager.CreateIdentityAsync(user, CookieAuthenticationDefaults.AuthenticationType);
        Request.GetOwinContext().Authentication.SignIn(new AuthenticationProperties { IsPersistent = true }, cookiesIdentity);

        // login
        var properties = new AuthenticationProperties(new Dictionary<string, string>
        {
            { "userName", globalUser.UserName },
            { "userId", globalUser.Id.ToString() }
        })
        {
            IsPersistent = true,
            IssuedUtc = DateTime.UtcNow,
            ExpiresUtc = DateTime.UtcNow.AddDays(28),
        };

        // jwt
        var oAuthIdentity = await _userManager.CreateIdentityAsync(user, "JWT");
        oAuthIdentity.AddClaim(new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()));
        oAuthIdentity.AddClaim(new Claim(JwtRegisteredClaimNames.Email, user.Email));
        oAuthIdentity.AddClaim(new Claim(JwtRegisteredClaimNames.GivenName, user.Contact.ContactFirstName + " " + user.Contact.ContactLastName));

        Microsoft.Owin.Security.AuthenticationTicket at = new Microsoft.Owin.Security.AuthenticationTicket(oAuthIdentity, properties);
        string jwt = Startup.Resolve<ISecureDataFormat<AuthenticationTicket>>().Protect(at);

Строка 'jwt' - это фактический необработанный билет аутентификации, который мы храним в локальном хранилище для аутентификации в API.(Да, наше приложение странное. Вы входите на страницы MVC, но страницы вызывают API, используя токен JWT, так же, как это делает мобильное приложение. Это не SPA, но он ведет себя как один.)

Для решения шага 2: Библиотека Microsoft ADAL возвращает не код авторизации из процесса OAuth2, а фактический токен из ADFS.Я установил другую конечную точку, которая запускает процесс в середине решения шага 1, и вызывает те же методы, чтобы проверить токен, извлечь имя пользователя / адрес электронной почты и вернуть токен носителя.Библиотека ADAL уже проверила, что ввод имени пользователя в форме входа в систему соответствует утверждениям в токене, но сервер должен проверить, что токен является действительным, прежде чем заменять его на наш токен-носитель JWT.

Я уверенэто могло бы быть намного проще, но, честно говоря, OAuth2 не так уж сложно сделать вручную - но делайте это только если вы вынуждены.Промежуточное программное обеспечение OWIN хорошо протестировано и охватывает все случаи, которые я потрачу на поиски в следующем месяце - оно просто не поддерживает пропуск многих шагов.

...