示例#1
0
        private static void AddMicrosoftIdentityWebAppInternal(
            AuthenticationBuilder builder,
            Action <MicrosoftIdentityOptions> configureMicrosoftIdentityOptions,
            Action <CookieAuthenticationOptions>?configureCookieAuthenticationOptions,
            string openIdConnectScheme,
            string?cookieScheme,
            bool subscribeToOpenIdConnectMiddlewareDiagnosticsEvents)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (configureMicrosoftIdentityOptions == null)
            {
                throw new ArgumentNullException(nameof(configureMicrosoftIdentityOptions));
            }

            builder.Services.Configure(configureMicrosoftIdentityOptions);
            builder.Services.AddHttpClient();

            builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton <IValidateOptions <MicrosoftIdentityOptions>, MicrosoftIdentityOptionsValidation>());

            if (!string.IsNullOrEmpty(cookieScheme))
            {
                Action <CookieAuthenticationOptions> emptyOption = option => { };
                builder.AddCookie(cookieScheme, configureCookieAuthenticationOptions ?? emptyOption);
            }

            builder.Services.TryAddSingleton <MicrosoftIdentityIssuerValidatorFactory>();

            if (subscribeToOpenIdConnectMiddlewareDiagnosticsEvents)
            {
                builder.Services.AddSingleton <IOpenIdConnectMiddlewareDiagnostics, OpenIdConnectMiddlewareDiagnostics>();
            }

            if (AppServicesAuthenticationInformation.IsAppServicesAadAuthenticationEnabled)
            {
                builder.Services.AddAuthentication(AppServicesAuthenticationDefaults.AuthenticationScheme)
                .AddAppServicesAuthentication();
                return;
            }

            builder.AddOpenIdConnect(openIdConnectScheme, options => { });
            builder.Services.AddOptions <OpenIdConnectOptions>(openIdConnectScheme)
            .Configure <IServiceProvider, IOptions <MicrosoftIdentityOptions> >((options, serviceProvider, microsoftIdentityOptions) =>
            {
                PopulateOpenIdOptionsFromMicrosoftIdentityOptions(options, microsoftIdentityOptions.Value);
                var b2cOidcHandlers = new AzureADB2COpenIDConnectEventHandlers(openIdConnectScheme, microsoftIdentityOptions.Value);

                if (!string.IsNullOrEmpty(cookieScheme))
                {
                    options.SignInScheme = cookieScheme;
                }

                if (string.IsNullOrWhiteSpace(options.Authority))
                {
                    options.Authority = AuthorityHelpers.BuildAuthority(microsoftIdentityOptions.Value);
                }

                // This is a Microsoft identity platform web app
                options.Authority = AuthorityHelpers.EnsureAuthorityIsV2(options.Authority);

                // B2C doesn't have preferred_username claims
                if (microsoftIdentityOptions.Value.IsB2C)
                {
                    options.TokenValidationParameters.NameClaimType = ClaimConstants.Name;
                }
                else
                {
                    options.TokenValidationParameters.NameClaimType = ClaimConstants.PreferredUserName;
                }

                // If the developer registered an IssuerValidator, do not overwrite it
                if (options.TokenValidationParameters.ValidateIssuer && options.TokenValidationParameters.IssuerValidator == null)
                {
                    // If you want to restrict the users that can sign-in to several organizations
                    // Set the tenant value in the appsettings.json file to 'organizations', and add the
                    // issuers you want to accept to options.TokenValidationParameters.ValidIssuers collection
                    MicrosoftIdentityIssuerValidatorFactory microsoftIdentityIssuerValidatorFactory =
                        serviceProvider.GetRequiredService <MicrosoftIdentityIssuerValidatorFactory>();

                    options.TokenValidationParameters.IssuerValidator =
                        microsoftIdentityIssuerValidatorFactory.GetAadIssuerValidator(options.Authority).Validate;
                }

                // Avoids having users being presented the select account dialog when they are already signed-in
                // for instance when going through incremental consent
                var redirectToIdpHandler = options.Events.OnRedirectToIdentityProvider;
                options.Events.OnRedirectToIdentityProvider = async context =>
                {
                    var login = context.Properties.GetParameter <string>(OpenIdConnectParameterNames.LoginHint);
                    if (!string.IsNullOrWhiteSpace(login))
                    {
                        context.ProtocolMessage.LoginHint = login;

                        // delete the login_hint from the Properties when we are done otherwise
                        // it will take up extra space in the cookie.
                        context.Properties.Parameters.Remove(OpenIdConnectParameterNames.LoginHint);
                    }

                    var domainHint = context.Properties.GetParameter <string>(OpenIdConnectParameterNames.DomainHint);
                    if (!string.IsNullOrWhiteSpace(domainHint))
                    {
                        context.ProtocolMessage.DomainHint = domainHint;

                        // delete the domain_hint from the Properties when we are done otherwise
                        // it will take up extra space in the cookie.
                        context.Properties.Parameters.Remove(OpenIdConnectParameterNames.DomainHint);
                    }

                    context.ProtocolMessage.SetParameter(Constants.ClientInfo, Constants.One);
                    context.ProtocolMessage.SetParameter(Constants.TelemetryHeaderKey, IdHelper.CreateTelemetryInfo());

                    // Additional claims
                    if (context.Properties.Items.ContainsKey(OidcConstants.AdditionalClaims))
                    {
                        context.ProtocolMessage.SetParameter(
                            OidcConstants.AdditionalClaims,
                            context.Properties.Items[OidcConstants.AdditionalClaims]);
                    }

                    if (microsoftIdentityOptions.Value.IsB2C)
                    {
                        // When a new Challenge is returned using any B2C user flow different than susi, we must change
                        // the ProtocolMessage.IssuerAddress to the desired user flow otherwise the redirect would use the susi user flow
                        await b2cOidcHandlers.OnRedirectToIdentityProvider(context).ConfigureAwait(false);
                    }

                    await redirectToIdpHandler(context).ConfigureAwait(false);
                };

                if (microsoftIdentityOptions.Value.IsB2C)
                {
                    var remoteFailureHandler       = options.Events.OnRemoteFailure;
                    options.Events.OnRemoteFailure = async context =>
                    {
                        // Handles the error when a user cancels an action on the Azure Active Directory B2C UI.
                        // Handle the error code that Azure Active Directory B2C throws when trying to reset a password from the login page
                        // because password reset is not supported by a "sign-up or sign-in user flow".
                        await b2cOidcHandlers.OnRemoteFailure(context).ConfigureAwait(false);

                        await remoteFailureHandler(context).ConfigureAwait(false);
                    };
                }

                if (subscribeToOpenIdConnectMiddlewareDiagnosticsEvents)
                {
                    var diagnostics = serviceProvider.GetRequiredService <IOpenIdConnectMiddlewareDiagnostics>();

                    diagnostics.Subscribe(options.Events);
                }
            });
        }