Пример #1
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext <WebClientContext>(options =>
                                                     options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddDistributedSqlServerCache(options =>
            {
                options.ConnectionString = Configuration.GetConnectionString("DefaultConnection");
                options.SchemaName       = "dbo";
                options.TableName        = "TokenCache";
            });

            services.Configure <CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded    = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
                // Handling SameSite cookie according to https://docs.microsoft.com/en-us/aspnet/core/security/samesite?view=aspnetcore-3.1
                options.HandleSameSiteCookieCompatibility();
            });

            services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
            .EnableTokenAcquisitionToCallDownstreamApi()
            .AddDistributedTokenCaches();

            services.Configure <MicrosoftIdentityOptions>(options =>
            {
                var existingOnTokenValidatedHandler = options.Events.OnTokenValidated;

                options.Events.OnTokenValidated = async context =>
                {
                    await existingOnTokenValidatedHandler(context);

                    //Allows us to add extra claims specific to our application

                    await PrincipalTransformer.Transform(context);
                };
            });

            services.AddHttpClient <IApi01Service, Api01Service>();
            services.AddHttpClient <IApi02Service, Api02Service>();

            //Allows us to use MicrosoftIdentityConsentAndConditionalAccessHandler in the Api services.
            //This in turn means we don't need AuthorizeForScope on each page and can trigger
            //a challenge in the service if the token can't be found or has expired.
            services.TryAddScoped <MicrosoftIdentityConsentAndConditionalAccessHandler>();

            services.AddControllersWithViews(options =>
            {
                var policy = new AuthorizationPolicyBuilder()
                             .RequireAuthenticatedUser()
                             .Build();
                options.Filters.Add(new AuthorizeFilter(policy));
            }).AddMicrosoftIdentityUI();

            services.AddRazorPages();
        }
        protected override Task <HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            var tokenStringFromHeader = GetTokenStringFromHeader(request);
            var tokenStringFromCookie = GetTokenStringFromCookie(CookieNameToCheckForToken);
            var tokenString           = tokenStringFromHeader ?? tokenStringFromCookie;

            if (!string.IsNullOrEmpty(tokenStringFromHeader) && !string.IsNullOrEmpty(tokenStringFromCookie))
            {
                _logger.DebugFormat(
                    "Both the Authorization header and {0} cookie contained tokens; header token was used",
                    CookieNameToCheckForToken);
            }

            if (string.IsNullOrEmpty(tokenString))
            {
                _logger.Debug("Token not found in authorization header or request cookie");
                return(BaseSendAsync(request, cancellationToken));
            }

            IJwtSecurityToken token;

            try
            {
                token = CreateToken(tokenString);
            }
            catch (Exception ex)
            {
                _logger.WarnFormat("Error converting token string to JWT: {0}", ex);
                return(BaseSendAsync(request, cancellationToken));
            }

            if (SigningToken != null && token.SignatureAlgorithm != null)
            {
                if (token.SignatureAlgorithm.StartsWith("RS") && !(SigningToken is X509SecurityToken))
                {
                    _logger.DebugFormat("Incoming token signature is X509, but token handler's signing token is not.");
                    return(BaseSendAsync(request, cancellationToken));
                }

                if (token.SignatureAlgorithm.StartsWith("HS") && !(SigningToken is BinarySecretSecurityToken))
                {
                    _logger.DebugFormat("Incoming token signature is SHA, but token handler's signing token is not.");
                    return(BaseSendAsync(request, cancellationToken));
                }
            }

            var parameters = new TokenValidationParameters
            {
                ValidAudience      = AllowedAudience,
                IssuerSigningToken = SigningToken,
                ValidIssuer        = Issuer,
                ValidAudiences     = AllowedAudiences
            };

            try
            {
                var        tokenHandler = CreateTokenHandler();
                IPrincipal principal    = tokenHandler.ValidateToken(token, parameters);

                if (PrincipalTransformer != null)
                {
                    principal = PrincipalTransformer.Transform((ClaimsPrincipal)principal);
                    CheckPrincipal(principal, PrincipalTransformer.GetType());
                }

                Thread.CurrentPrincipal = principal;
                _logger.DebugFormat("Thread principal set with identity '{0}'", principal.Identity.Name);

                if (HttpContext.Current != null)
                {
                    HttpContext.Current.User = principal;
                }
            }
            catch (SecurityTokenExpiredException e)
            {
                _logger.ErrorFormat("Security token expired: {0}", e);

                var response = new HttpResponseMessage((HttpStatusCode)440)
                {
                    Content = new StringContent("Security token expired exception")
                };

                var tsc = new TaskCompletionSource <HttpResponseMessage>();
                tsc.SetResult(response);
                return(tsc.Task);
            }
            catch (SecurityTokenSignatureKeyNotFoundException e)
            {
                _logger.ErrorFormat("Error during JWT validation: {0}", e);

                var response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
                {
                    Content = new StringContent("Untrusted signing cert")
                };

                var tsc = new TaskCompletionSource <HttpResponseMessage>();
                tsc.SetResult(response);
                return(tsc.Task);
            }
            catch (SecurityTokenInvalidAudienceException e)
            {
                _logger.ErrorFormat("Error during JWT validation: {0}", e);

                var response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
                {
                    Content = new StringContent("Invalid token audience")
                };

                var tsc = new TaskCompletionSource <HttpResponseMessage>();
                tsc.SetResult(response);
                return(tsc.Task);
            }
            catch (SecurityTokenValidationException e)
            {
                _logger.ErrorFormat("Error during JWT validation: {0}", e);

                var response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
                {
                    Content = new StringContent("Invalid token")
                };

                var tsc = new TaskCompletionSource <HttpResponseMessage>();
                tsc.SetResult(response);
                return(tsc.Task);
            }
            catch (SignatureVerificationFailedException e)
            {
                _logger.ErrorFormat("Error during JWT validation: {0}", e);

                var response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
                {
                    Content = new StringContent("Invalid token signature")
                };

                var tsc = new TaskCompletionSource <HttpResponseMessage>();
                tsc.SetResult(response);
                return(tsc.Task);
            }
            catch (Exception e)
            {
                _logger.ErrorFormat("Error during JWT validation: {0}", e);
                throw;
            }

            return(BaseSendAsync(request, cancellationToken));
        }