Esempio n. 1
0
        private static void AddMicrosoftIdentityWebApiImplementation(
            AuthenticationBuilder builder,
            Action <JwtBearerOptions> configureJwtBearerOptions,
            Action <MicrosoftIdentityOptions> configureMicrosoftIdentityOptions,
            string jwtBearerScheme,
            bool subscribeToJwtBearerMiddlewareDiagnosticsEvents)
        {
            builder.AddJwtBearer(jwtBearerScheme, configureJwtBearerOptions);
            builder.Services.Configure(jwtBearerScheme, configureMicrosoftIdentityOptions);

            builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton <IValidateOptions <MicrosoftIdentityOptions>, MicrosoftIdentityOptionsValidation>());
            builder.Services.AddHttpContextAccessor();
            builder.Services.AddHttpClient();
            builder.Services.TryAddSingleton <MicrosoftIdentityIssuerValidatorFactory>();
            builder.Services.AddOptions <AadIssuerValidatorOptions>();

            if (subscribeToJwtBearerMiddlewareDiagnosticsEvents)
            {
                builder.Services.AddSingleton <IJwtBearerMiddlewareDiagnostics, JwtBearerMiddlewareDiagnostics>();
            }

            // Change the authentication configuration to accommodate the Microsoft identity platform endpoint (v2.0).
            builder.Services.AddOptions <JwtBearerOptions>(jwtBearerScheme)
            .Configure <IServiceProvider, IOptionsMonitor <MicrosoftIdentityOptions> >((options, serviceProvider, microsoftIdentityOptionsMonitor) =>
            {
                var microsoftIdentityOptions = microsoftIdentityOptionsMonitor.Get(jwtBearerScheme);

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

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

                if (options.TokenValidationParameters.AudienceValidator == null &&
                    options.TokenValidationParameters.ValidAudience == null &&
                    options.TokenValidationParameters.ValidAudiences == null)
                {
                    RegisterValidAudience registerAudience = new RegisterValidAudience();
                    registerAudience.RegisterAudienceValidation(
                        options.TokenValidationParameters,
                        microsoftIdentityOptions);
                }

                // If the developer registered an IssuerValidator, do not overwrite it
                if (options.TokenValidationParameters.ValidateIssuer && options.TokenValidationParameters.IssuerValidator == null)
                {
                    // Instead of using the default validation (validating against a single tenant, as we do in line of business apps),
                    // we inject our own multi-tenant validation logic (which even accepts both v1.0 and v2.0 tokens)
                    MicrosoftIdentityIssuerValidatorFactory microsoftIdentityIssuerValidatorFactory =
                        serviceProvider.GetRequiredService <MicrosoftIdentityIssuerValidatorFactory>();

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

                // If you provide a token decryption certificate, it will be used to decrypt the token
                if (microsoftIdentityOptions.TokenDecryptionCertificates != null)
                {
                    IEnumerable <X509Certificate2?> certificates          = DefaultCertificateLoader.LoadAllCertificates(microsoftIdentityOptions.TokenDecryptionCertificates);
                    IEnumerable <X509SecurityKey> keys                    = certificates.Select(c => new X509SecurityKey(c));
                    options.TokenValidationParameters.TokenDecryptionKeys = keys;
                }

                if (options.Events == null)
                {
                    options.Events = new JwtBearerEvents();
                }

                // When an access token for our own web API is validated, we add it to MSAL.NET's cache so that it can
                // be used from the controllers.
                var tokenValidatedHandler       = options.Events.OnTokenValidated;
                options.Events.OnTokenValidated = async context =>
                {
                    if (!microsoftIdentityOptions.AllowWebApiToBeAuthorizedByACL &&
                        !context !.Principal !.Claims.Any(x => x.Type == ClaimConstants.Scope ||
                                                          x.Type == ClaimConstants.Scp ||
                                                          x.Type == ClaimConstants.Roles ||
                                                          x.Type == ClaimConstants.Role))
                    {
                        throw new UnauthorizedAccessException(IDWebErrorMessage.NeitherScopeOrRolesClaimFoundInToken);
                    }

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

                if (subscribeToJwtBearerMiddlewareDiagnosticsEvents)
                {
                    var diagnostics = serviceProvider.GetRequiredService <IJwtBearerMiddlewareDiagnostics>();

                    diagnostics.Subscribe(options.Events);
                }
            });
        }
        private static void AddMicrosoftIdentityWebApiImplementation(
            AuthenticationBuilder builder,
            Action <JwtBearerOptions> configureJwtBearerOptions,
            Action <MicrosoftIdentityOptions> configureMicrosoftIdentityOptions,
            string jwtBearerScheme,
            bool subscribeToJwtBearerMiddlewareDiagnosticsEvents)
        {
            builder.AddJwtBearer(jwtBearerScheme, configureJwtBearerOptions);
            builder.Services.Configure(jwtBearerScheme, configureMicrosoftIdentityOptions);

            builder.Services.AddHttpContextAccessor();
            builder.Services.AddHttpClient();
            builder.Services.TryAddSingleton <MicrosoftIdentityIssuerValidatorFactory>();
            builder.Services.AddRequiredScopeAuthorization();
            builder.Services.AddRequiredScopeOrAppPermissionAuthorization();
            builder.Services.AddOptions <AadIssuerValidatorOptions>();

            if (subscribeToJwtBearerMiddlewareDiagnosticsEvents)
            {
                builder.Services.AddTransient <IJwtBearerMiddlewareDiagnostics, JwtBearerMiddlewareDiagnostics>();
            }

            // Change the authentication configuration to accommodate the Microsoft identity platform endpoint (v2.0).
            builder.Services.AddOptions <JwtBearerOptions>(jwtBearerScheme)
            .Configure <IServiceProvider, IOptionsMonitor <MergedOptions>, IOptionsMonitor <MicrosoftIdentityOptions>, IOptions <MicrosoftIdentityOptions> >((
                                                                                                                                                                 options,
                                                                                                                                                                 serviceProvider,
                                                                                                                                                                 mergedOptionsMonitor,
                                                                                                                                                                 msIdOptionsMonitor,
                                                                                                                                                                 msIdOptions) =>
            {
                MicrosoftIdentityBaseAuthenticationBuilder.SetIdentityModelLogger(serviceProvider);
                MergedOptions mergedOptions = mergedOptionsMonitor.Get(jwtBearerScheme);
                MergedOptions.UpdateMergedOptionsFromJwtBearerOptions(options, mergedOptions);
                MergedOptions.UpdateMergedOptionsFromMicrosoftIdentityOptions(msIdOptions.Value, mergedOptions);
                MergedOptions.UpdateMergedOptionsFromMicrosoftIdentityOptions(msIdOptionsMonitor.Get(jwtBearerScheme), mergedOptions);

                MergedOptionsValidation.Validate(mergedOptions);

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

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

                if (options.TokenValidationParameters.AudienceValidator == null &&
                    options.TokenValidationParameters.ValidAudience == null &&
                    options.TokenValidationParameters.ValidAudiences == null)
                {
                    RegisterValidAudience registerAudience = new RegisterValidAudience();
                    registerAudience.RegisterAudienceValidation(
                        options.TokenValidationParameters,
                        mergedOptions);
                }

                // If the developer registered an IssuerValidator, do not overwrite it
                if (options.TokenValidationParameters.ValidateIssuer && options.TokenValidationParameters.IssuerValidator == null)
                {
                    // Instead of using the default validation (validating against a single tenant, as we do in line of business apps),
                    // we inject our own multi-tenant validation logic (which even accepts both v1.0 and v2.0 tokens)
                    MicrosoftIdentityIssuerValidatorFactory microsoftIdentityIssuerValidatorFactory =
                        serviceProvider.GetRequiredService <MicrosoftIdentityIssuerValidatorFactory>();

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

                // If you provide a token decryption certificate, it will be used to decrypt the token
                if (mergedOptions.TokenDecryptionCertificates != null)
                {
                    DefaultCertificateLoader.UserAssignedManagedIdentityClientId = mergedOptions.UserAssignedManagedIdentityClientId;
                    IEnumerable <X509Certificate2?> certificates          = DefaultCertificateLoader.LoadAllCertificates(mergedOptions.TokenDecryptionCertificates);
                    IEnumerable <X509SecurityKey> keys                    = certificates.Select(c => new X509SecurityKey(c));
                    options.TokenValidationParameters.TokenDecryptionKeys = keys;
                }

                if (options.Events == null)
                {
                    options.Events = new JwtBearerEvents();
                }

                // When an access token for our own web API is validated, we add it to MSAL.NET's cache so that it can
                // be used from the controllers.

                if (!mergedOptions.AllowWebApiToBeAuthorizedByACL)
                {
                    ChainOnTokenValidatedEventForClaimsValidation(options.Events, jwtBearerScheme);
                }

                if (subscribeToJwtBearerMiddlewareDiagnosticsEvents)
                {
                    var diagnostics = serviceProvider.GetRequiredService <IJwtBearerMiddlewareDiagnostics>();

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