Azure AD SSO, Owin, sileng sign in, jak użyć prompt=select_account?

0

Piszę klienta SSO do AAD w C#. Używam bibliotek Microsoftu (Microsoft.Owin). Całość czasem działa, a czasem nie, bo dane zwracane przez serwer czasem przychodzą puste (User.Identity as ClaimsIdentity nie jest nullem, ale pole Claims jest puste). Po stronie Azure do logów "Sign-ins" leci wtedy błąd

Sign-in error code: 50058
Failure reason: The application tried to perform a silent sign in and the user could not be silently signed in. The application needs to start an interactive flow giving users an option to sign in.

Przegrzebałem pół internetu, znalazłem na https://docs.microsoft.com/en-us/answers/questions/3586/enterprise-app-oauth2-sso-gets-invalid-session-key.html, że do url'a, do którego przekierowywana jest przeglądarka na strony MS celem zalogowania się, należy dodać parametr prompt=select_account. To po to, żeby przeglądarka wyświetliła stronę wyboru konta, na które klient chce się zalogować. Tu się zaczyna problem. Nie mam pojęcia, jak to zrobić. W bibliotekach Owin są obecne klasy zawierające częściowo to, czego potrzebuję (OpenIdConnectParameterNames.Prompt oraz OpenIdConnectPrompt.SelectAccount), ale nie mam pojęcia jak tego użyć. Grzebanie w internecie nie pomogło, dokumentacja MS jest tak słaba, że równie dobrze mogłoby jej nie być, a jedyny znaleziony przykład używający OpenIdConnectParameterNames działa w oparciu o handler AuthorizationCodeReceived, ale my nie używamy Authorization Code, więc handler nawet nie jest wywoływany.
Jak tego użyć? Jak zalogować się do aplikacji C# tak, aby przejść przez stronę wyboru konta użytkownika, a potem dostać jego email, o ile ma go skonfigurowanego? W prawidłowo wołanej konfiguracji public void Configuration(IAppBuilder app) ustawiam sobie Scope = $"{OpenIdConnectScope.OpenIdProfile} {OpenIdConnectScope.Email} {OpenIdConnectScope.OpenId}", a więc żądam emaila, tylko mail albo przychodzi w polu email, albo przychodzi w polu preferred_name, albo nie przychodzi w niczym, bo claims jest puste.

0

W poprzedniej pracy integrowałem się z kilkoma providerami - pomiędzy OKTA, auth0 i AAD to to ostatnie było najmniej wygodne. Skończyło się właśnie na AAD, ale napisaliśmy to używając IdentityServer z własnymi handlerami, trochę bolało integrowanie tego, ale ostatecznie wszystko działało - może spróbuj w tę stronę.

1

To jest apka w ASP.NET?

Jakieś 3 lata temu integrowałem się z AAD, ale w ASP.NET Core i pamiętam, że ustawiałem ten prompt=select_account.
Jeśli dobrze kojarzę to robiłem to w evencie OnRedirectToIdentityProvider, ale jak dokładnie to już niestety nie pamiętam :/

0

@some_ONE dzięki wielkie, to było to! Poniżej rozwiązanie. Komentarze zostawiam, żeby było wiadomo jaki parametr od czego. Jeszcze opiszę po angielsku, może zagranica do nas zajrzy.

If during sign-in using Azure Active Domain (AAD) Single Sign On (SSO) you face the error

Sign-in error code: 50058
Failure reason: The application tried to perform a silent sign in and the user could not be silently signed in. The application needs to start an interactive flow giving users an option to sign in.

you need to add parameter "prompt=select_account" to the redirect url of the request that your browser does to Microsoft AAD server. Below you'll find how to add this parameter (OpenIdConnectParameterNames.Prompt = "prompt", OpenIdConnectPrompt.SelectAccount = "select_account").

using Owin;
using System.Security.Claims;
using System.Threading.Tasks;
[assembly: OwinStartup(typeof(SomeNamespace.OwinConfig))]

namespace SomeNamespace
{
    public class OwinConfig
    {
        public void Configuration(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = configuration.AzureSSOClientId, // Application ID from the application registered in the Azure portal
                    Authority = "https://login.microsoftonline.com/common/v2.0", // The STS endpoint for user to authenticate. Usually https://login.microsoftonline.com/{tenant}/v2.0 for public cloud, where {tenant} is the name of your tenant, your tenant Id, or common for a reference to the common endpoint (used for multi-tenant applications)
                    RedirectUri = configuration.AzureSSORedirectUrl, // URL where users are sent after authentication against Microsoft identity platform endpoint
                    PostLogoutRedirectUri = configuration.AzureSSOPostLogoutRedirectUrl, // URL where users are sent after signing-off
                    Scope = $"{OpenIdConnectScope.OpenIdProfile} {OpenIdConnectScope.Email} {OpenIdConnectScope.OpenId}",
                    // ResponseType is set to request the id_token - which contains basic information about the signed-in user
                    ResponseType = OpenIdConnectResponseType.IdToken,
                    // ValidateIssuer set to false to allow personal and work accounts from any organization to sign in to your application
                    // To only allow users from a single organizations, set ValidateIssuer to true and 'tenant' setting in web.config to the tenant name
                    // To allow users from only a list of specific organizations, set ValidateIssuer to true and use ValidIssuers parameter
                    TokenValidationParameters = new TokenValidationParameters() { ValidateIssuer = false },
                    // OpenIdConnectAuthenticationNotifications configures OWIN to send notification of failed authentications to OnAuthenticationFailed method
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        RedirectToIdentityProvider = OnRedirectToIdentityProvider
                    }
                }
            );
        }

        private Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
        {
            context.ProtocolMessage.SetParameter(OpenIdConnectParameterNames.Prompt, OpenIdConnectPrompt.SelectAccount);
            return Task.FromResult(0);
        }
    }
}
0

Teraz na localhost działa, a na dev dla niektórych z nas kończy się odebraniem pustych claimów, a w logach na AAD siedzi wtedy błąd 16000 "This is an interrupt thrown by Azure AD, which results in UI that allows the user to select from among multiple valid SSO sessions. This error is fairly common and may be returned to the application". "Either multiple user identities are available for the current request or selected account is not supported for the scenario."
WTF? Ręce mi opadają jak można spieprzyć tak prostą sprawę, jak SSO.

1 użytkowników online, w tym zalogowanych: 0, gości: 1