mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 12:30:49 +08:00 
			
		
		
		
	Merge pull request #104 from juancash/checking-identity-server
Identity Server - Check's issues with Audience and AllowedScopes
This commit is contained in:
		@@ -7,7 +7,7 @@ namespace Ocelot.Authorisation
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    using Infrastructure.Claims.Parser;
 | 
					    using Infrastructure.Claims.Parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class ClaimsAuthoriser : IAuthoriser
 | 
					    public class ClaimsAuthoriser : IClaimsAuthoriser
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IClaimsParser _claimsParser;
 | 
					        private readonly IClaimsParser _claimsParser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,9 +5,8 @@ namespace Ocelot.Authorisation
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    using System.Collections.Generic;
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public interface IAuthoriser
 | 
					    public interface IClaimsAuthoriser
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Response<bool> Authorise(ClaimsPrincipal claimsPrincipal,
 | 
					        Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, Dictionary<string, string> routeClaimsRequirement);
 | 
				
			||||||
            Dictionary<string, string> routeClaimsRequirement);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/Ocelot/Authorisation/IScopesAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Ocelot/Authorisation/IScopesAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					using System.Security.Claims;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Authorisation
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public interface IScopesAuthoriser
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, List<string> routeAllowedScopes);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
using Ocelot.Infrastructure.RequestData;
 | 
					using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
using Ocelot.Logging;
 | 
					using Ocelot.Logging;
 | 
				
			||||||
using Ocelot.Responses;
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Authorisation.Middleware
 | 
					namespace Ocelot.Authorisation.Middleware
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -13,17 +14,20 @@ namespace Ocelot.Authorisation.Middleware
 | 
				
			|||||||
    public class AuthorisationMiddleware : OcelotMiddleware
 | 
					    public class AuthorisationMiddleware : OcelotMiddleware
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly RequestDelegate _next;
 | 
					        private readonly RequestDelegate _next;
 | 
				
			||||||
        private readonly IAuthoriser _authoriser;
 | 
					        private readonly IClaimsAuthoriser _claimsAuthoriser;
 | 
				
			||||||
 | 
					        private readonly IScopesAuthoriser _scopesAuthoriser;
 | 
				
			||||||
        private readonly IOcelotLogger _logger;
 | 
					        private readonly IOcelotLogger _logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public AuthorisationMiddleware(RequestDelegate next,
 | 
					        public AuthorisationMiddleware(RequestDelegate next,
 | 
				
			||||||
            IRequestScopedDataRepository requestScopedDataRepository,
 | 
					            IRequestScopedDataRepository requestScopedDataRepository,
 | 
				
			||||||
            IAuthoriser authoriser,
 | 
					            IClaimsAuthoriser claimsAuthoriser,
 | 
				
			||||||
 | 
					            IScopesAuthoriser scopesAuthoriser,
 | 
				
			||||||
            IOcelotLoggerFactory loggerFactory)
 | 
					            IOcelotLoggerFactory loggerFactory)
 | 
				
			||||||
            : base(requestScopedDataRepository)
 | 
					            : base(requestScopedDataRepository)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _next = next;
 | 
					            _next = next;
 | 
				
			||||||
            _authoriser = authoriser;
 | 
					            _claimsAuthoriser = claimsAuthoriser;
 | 
				
			||||||
 | 
					            _scopesAuthoriser = scopesAuthoriser;
 | 
				
			||||||
            _logger = loggerFactory.CreateLogger<AuthorisationMiddleware>();
 | 
					            _logger = loggerFactory.CreateLogger<AuthorisationMiddleware>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,11 +35,41 @@ namespace Ocelot.Authorisation.Middleware
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            _logger.LogDebug("started authorisation");
 | 
					            _logger.LogDebug("started authorisation");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (DownstreamRoute.ReRoute.IsAuthorised)
 | 
					            if (IsAuthenticatedRoute(DownstreamRoute.ReRoute))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _logger.LogDebug("route is authenticated scopes must be checked");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var authorised = _scopesAuthoriser.Authorise(context.User, DownstreamRoute.ReRoute.AuthenticationOptions.AllowedScopes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (authorised.IsError)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _logger.LogDebug("error authorising user scopes");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    SetPipelineError(authorised.Errors);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (IsAuthorised(authorised))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _logger.LogDebug("user scopes is authorised calling next authorisation checks");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _logger.LogDebug("user scopes is not authorised setting pipeline error");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    SetPipelineError(new List<Error>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        new UnauthorisedError(
 | 
				
			||||||
 | 
					                            $"{context.User.Identity.Name} unable to access {DownstreamRoute.ReRoute.UpstreamPathTemplate.Value}")
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (IsAuthorisedRoute(DownstreamRoute.ReRoute))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _logger.LogDebug("route is authorised");
 | 
					                _logger.LogDebug("route is authorised");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var authorised = _authoriser.Authorise(context.User, DownstreamRoute.ReRoute.RouteClaimsRequirement);
 | 
					                var authorised = _claimsAuthoriser.Authorise(context.User, DownstreamRoute.ReRoute.RouteClaimsRequirement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (authorised.IsError)
 | 
					                if (authorised.IsError)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -78,5 +112,15 @@ namespace Ocelot.Authorisation.Middleware
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return authorised.Data;
 | 
					            return authorised.Data;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private static bool IsAuthenticatedRoute(ReRoute reRoute)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return reRoute.IsAuthenticated;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private static bool IsAuthorisedRoute(ReRoute reRoute)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return reRoute.IsAuthorised;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								src/Ocelot/Authorisation/ScopeNotAuthorisedError.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Ocelot/Authorisation/ScopeNotAuthorisedError.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					using Ocelot.Errors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Authorisation
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class ScopeNotAuthorisedError : Error
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public ScopeNotAuthorisedError(string message) 
 | 
				
			||||||
 | 
					            : base(message, OcelotErrorCode.ScopeNotAuthorisedError)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/Ocelot/Authorisation/ScopesAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/Ocelot/Authorisation/ScopesAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					using IdentityModel;
 | 
				
			||||||
 | 
					using Ocelot.Errors;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Security.Claims;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Authorisation
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using Infrastructure.Claims.Parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class ScopesAuthoriser : IScopesAuthoriser
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly IClaimsParser _claimsParser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public ScopesAuthoriser(IClaimsParser claimsParser)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _claimsParser = claimsParser;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, List<string> routeAllowedScopes)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (routeAllowedScopes == null || routeAllowedScopes.Count == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new OkResponse<bool>(true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var values = _claimsParser.GetValuesByClaimType(claimsPrincipal.Claims, JwtClaimTypes.Scope);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (values.IsError)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new ErrorResponse<bool>(values.Errors);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var userScopes = values.Data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            List<string> matchesScopes = routeAllowedScopes.Intersect(userScopes).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (matchesScopes == null || matchesScopes.Count == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new ErrorResponse<bool>(new List<Error>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                     new ScopeNotAuthorisedError(
 | 
				
			||||||
 | 
					                         $"no one user scope: '{string.Join(",", userScopes)}' match with some allowed scope: '{string.Join(",", routeAllowedScopes)}'")
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return new OkResponse<bool>(true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -144,7 +144,8 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
            services.TryAddSingleton<IRemoveOutputHeaders, RemoveOutputHeaders>();
 | 
					            services.TryAddSingleton<IRemoveOutputHeaders, RemoveOutputHeaders>();
 | 
				
			||||||
            services.TryAddSingleton<IOcelotConfigurationProvider, OcelotConfigurationProvider>();
 | 
					            services.TryAddSingleton<IOcelotConfigurationProvider, OcelotConfigurationProvider>();
 | 
				
			||||||
            services.TryAddSingleton<IClaimToThingConfigurationParser, ClaimToThingConfigurationParser>();
 | 
					            services.TryAddSingleton<IClaimToThingConfigurationParser, ClaimToThingConfigurationParser>();
 | 
				
			||||||
            services.TryAddSingleton<IAuthoriser, ClaimsAuthoriser>();
 | 
					            services.TryAddSingleton<IClaimsAuthoriser, ClaimsAuthoriser>();
 | 
				
			||||||
 | 
					            services.TryAddSingleton<IScopesAuthoriser, ScopesAuthoriser>();
 | 
				
			||||||
            services.TryAddSingleton<IAddClaimsToRequest, AddClaimsToRequest>();
 | 
					            services.TryAddSingleton<IAddClaimsToRequest, AddClaimsToRequest>();
 | 
				
			||||||
            services.TryAddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
 | 
					            services.TryAddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
 | 
				
			||||||
            services.TryAddSingleton<IAddQueriesToRequest, AddQueriesToRequest>();
 | 
					            services.TryAddSingleton<IAddQueriesToRequest, AddQueriesToRequest>();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
        InstructionNotForClaimsError,
 | 
					        InstructionNotForClaimsError,
 | 
				
			||||||
        UnauthorizedError,
 | 
					        UnauthorizedError,
 | 
				
			||||||
        ClaimValueNotAuthorisedError,
 | 
					        ClaimValueNotAuthorisedError,
 | 
				
			||||||
 | 
					        ScopeNotAuthorisedError,
 | 
				
			||||||
        UserDoesNotHaveClaimError,
 | 
					        UserDoesNotHaveClaimError,
 | 
				
			||||||
        DownstreamPathTemplateContainsSchemeError,
 | 
					        DownstreamPathTemplateContainsSchemeError,
 | 
				
			||||||
        DownstreamPathNullOrEmptyError,
 | 
					        DownstreamPathNullOrEmptyError,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
namespace Ocelot.Infrastructure.Claims.Parser
 | 
					namespace Ocelot.Infrastructure.Claims.Parser
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using Errors;
 | 
				
			||||||
 | 
					    using Responses;
 | 
				
			||||||
    using System.Collections.Generic;
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
    using System.Linq;
 | 
					    using System.Linq;
 | 
				
			||||||
    using System.Security.Claims;
 | 
					    using System.Security.Claims;
 | 
				
			||||||
    using Errors;
 | 
					 | 
				
			||||||
    using Responses;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class ClaimsParser : IClaimsParser
 | 
					    public class ClaimsParser : IClaimsParser
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -37,6 +37,17 @@
 | 
				
			|||||||
            return new OkResponse<string>(value);
 | 
					            return new OkResponse<string>(value);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Response<List<string>> GetValuesByClaimType(IEnumerable<Claim> claims, string claimType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            List<string> values = new List<string>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            values.AddRange(claims.Where(x => x.Type == claimType).Select(x => x.Value).ToList());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return new OkResponse<List<string>>(values);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private Response<string> GetValue(IEnumerable<Claim> claims, string key)
 | 
					        private Response<string> GetValue(IEnumerable<Claim> claims, string key)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var claim = claims.FirstOrDefault(c => c.Type == key);
 | 
					            var claim = claims.FirstOrDefault(c => c.Type == key);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,5 +7,6 @@
 | 
				
			|||||||
    public interface IClaimsParser
 | 
					    public interface IClaimsParser
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Response<string> GetValue(IEnumerable<Claim> claims, string key, string delimiter, int index);
 | 
					        Response<string> GetValue(IEnumerable<Claim> claims, string key, string delimiter, int index);
 | 
				
			||||||
 | 
					        Response<List<string>> GetValuesByClaimType(IEnumerable<Claim> claims, string claimType);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -40,7 +40,7 @@
 | 
				
			|||||||
    <PackageReference Include="Microsoft.AspNetCore.Authentication.Twitter" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Authentication.Twitter" Version="1.1.1" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="1.1.1" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Authentication" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Authentication" Version="1.1.1" />
 | 
				
			||||||
    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="1.0.2" />
 | 
					    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="1.2.0" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
 | 
				
			||||||
    <PackageReference Include="CacheManager.Core" Version="0.9.2" />
 | 
					    <PackageReference Include="CacheManager.Core" Version="0.9.2" />
 | 
				
			||||||
@@ -48,7 +48,7 @@
 | 
				
			|||||||
    <PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="0.9.2" />
 | 
					    <PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="0.9.2" />
 | 
				
			||||||
    <PackageReference Include="Consul" Version="0.7.2.1" />
 | 
					    <PackageReference Include="Consul" Version="0.7.2.1" />
 | 
				
			||||||
    <PackageReference Include="Polly" Version="5.0.3" />
 | 
					    <PackageReference Include="Polly" Version="5.0.3" />
 | 
				
			||||||
    <PackageReference Include="IdentityServer4" Version="1.0.1" />
 | 
					    <PackageReference Include="IdentityServer4" Version="1.5.1" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="1.1.1" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ namespace Ocelot.Responder
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (errors.Any(e => e.Code == OcelotErrorCode.UnauthorizedError 
 | 
					            if (errors.Any(e => e.Code == OcelotErrorCode.UnauthorizedError 
 | 
				
			||||||
                || e.Code == OcelotErrorCode.ClaimValueNotAuthorisedError
 | 
					                || e.Code == OcelotErrorCode.ClaimValueNotAuthorisedError
 | 
				
			||||||
 | 
					                || e.Code == OcelotErrorCode.ScopeNotAuthorisedError
 | 
				
			||||||
                || e.Code == OcelotErrorCode.UserDoesNotHaveClaimError
 | 
					                || e.Code == OcelotErrorCode.UserDoesNotHaveClaimError
 | 
				
			||||||
                || e.Code == OcelotErrorCode.CannotFindClaimError))
 | 
					                || e.Code == OcelotErrorCode.CannotFindClaimError))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,7 +62,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt))
 | 
					            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt))
 | 
				
			||||||
                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
 | 
					                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
 | 
				
			||||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
					                .And(x => _steps.GivenOcelotIsRunning())
 | 
				
			||||||
@@ -100,7 +100,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Reference))
 | 
					            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference))
 | 
				
			||||||
                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
 | 
					                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
 | 
				
			||||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
					                .And(x => _steps.GivenOcelotIsRunning())
 | 
				
			||||||
@@ -138,7 +138,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt))
 | 
					            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt))
 | 
				
			||||||
                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura"))
 | 
					                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura"))
 | 
				
			||||||
                .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
 | 
					                .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
 | 
				
			||||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
@@ -150,6 +150,45 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_response_401_using_identity_server_with_token_requested_for_other_api()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var configuration = new FileConfiguration
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ReRoutes = new List<FileReRoute>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        new FileReRoute
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            DownstreamPathTemplate = _downstreamServicePath,
 | 
				
			||||||
 | 
					                            DownstreamPort = _downstreamServicePort,
 | 
				
			||||||
 | 
					                            DownstreamHost = _downstreamServiceHost,
 | 
				
			||||||
 | 
					                            DownstreamScheme = _downstreamServiceScheme,
 | 
				
			||||||
 | 
					                            UpstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
				
			||||||
 | 
					                            AuthenticationOptions = new FileAuthenticationOptions
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                AllowedScopes =  new List<string>(),
 | 
				
			||||||
 | 
					                                Provider = "IdentityServer",
 | 
				
			||||||
 | 
					                                ProviderRootUrl = _identityServerRootUrl,
 | 
				
			||||||
 | 
					                                RequireHttps = false,
 | 
				
			||||||
 | 
					                                ApiName = "api",
 | 
				
			||||||
 | 
					                                ApiSecret = "secret"
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt))
 | 
				
			||||||
 | 
					                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura"))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenIHaveATokenForApi2(_identityServerRootUrl))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenOcelotIsRunning())
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
 | 
				
			||||||
 | 
					                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
				
			||||||
 | 
					                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_return_201_using_identity_server_access_token()
 | 
					        public void should_return_201_using_identity_server_access_token()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -179,7 +218,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt))
 | 
					            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt))
 | 
				
			||||||
                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
 | 
					                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
 | 
				
			||||||
                .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
 | 
					                .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
 | 
				
			||||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
@@ -219,7 +258,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Reference))
 | 
					            this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference))
 | 
				
			||||||
                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
 | 
					                .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
 | 
				
			||||||
                .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
 | 
					                .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
 | 
				
			||||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
@@ -252,7 +291,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            _servicebuilder.Start();
 | 
					            _servicebuilder.Start();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void GivenThereIsAnIdentityServerOn(string url, string apiName, AccessTokenType tokenType)
 | 
					        private void GivenThereIsAnIdentityServerOn(string url, string apiName, string api2Name, AccessTokenType tokenType)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _identityServerBuilder = new WebHostBuilder()
 | 
					            _identityServerBuilder = new WebHostBuilder()
 | 
				
			||||||
                .UseUrls(url)
 | 
					                .UseUrls(url)
 | 
				
			||||||
@@ -276,6 +315,32 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                                Scopes = new List<Scope>()
 | 
					                                Scopes = new List<Scope>()
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    new Scope("api"),
 | 
					                                    new Scope("api"),
 | 
				
			||||||
 | 
					                                    new Scope("api.readOnly"),
 | 
				
			||||||
 | 
					                                    new Scope("openid"),
 | 
				
			||||||
 | 
					                                    new Scope("offline_access")
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                ApiSecrets = new List<Secret>()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    new Secret
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        Value = "secret".Sha256()
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                UserClaims = new List<string>()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    "CustomerId", "LocationId"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            new ApiResource
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                Name = api2Name,
 | 
				
			||||||
 | 
					                                Description = "My second API",
 | 
				
			||||||
 | 
					                                Enabled = true,
 | 
				
			||||||
 | 
					                                DisplayName = "second test",
 | 
				
			||||||
 | 
					                                Scopes = new List<Scope>()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    new Scope("api2"),
 | 
				
			||||||
 | 
					                                    new Scope("api2.readOnly"),
 | 
				
			||||||
                                    new Scope("openid"),
 | 
					                                    new Scope("openid"),
 | 
				
			||||||
                                    new Scope("offline_access")
 | 
					                                    new Scope("offline_access")
 | 
				
			||||||
                                },
 | 
					                                },
 | 
				
			||||||
@@ -299,7 +364,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                                ClientId = "client",
 | 
					                                ClientId = "client",
 | 
				
			||||||
                                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
 | 
					                                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
 | 
				
			||||||
                                ClientSecrets = new List<Secret> {new Secret("secret".Sha256())},
 | 
					                                ClientSecrets = new List<Secret> {new Secret("secret".Sha256())},
 | 
				
			||||||
                                AllowedScopes = new List<string> { apiName, "openid", "offline_access" },
 | 
					                                AllowedScopes = new List<string> { apiName, api2Name, "api.readOnly", "openid", "offline_access" },
 | 
				
			||||||
                                AccessTokenType = tokenType,
 | 
					                                AccessTokenType = tokenType,
 | 
				
			||||||
                                Enabled = true,
 | 
					                                Enabled = true,
 | 
				
			||||||
                                RequireClientSecret = false
 | 
					                                RequireClientSecret = false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -140,6 +140,84 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_response_200_using_identity_server_with_allowed_scope()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var configuration = new FileConfiguration
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ReRoutes = new List<FileReRoute>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        new FileReRoute
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            DownstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                            DownstreamPort = 51876,
 | 
				
			||||||
 | 
					                            DownstreamHost = "localhost",
 | 
				
			||||||
 | 
					                            DownstreamScheme = "http",
 | 
				
			||||||
 | 
					                            UpstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
				
			||||||
 | 
					                            AuthenticationOptions = new FileAuthenticationOptions
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                AllowedScopes =  new List<string>{ "api", "api.readOnly", "openid", "offline_access" },
 | 
				
			||||||
 | 
					                                Provider = "IdentityServer",
 | 
				
			||||||
 | 
					                                ProviderRootUrl = "http://localhost:51888",
 | 
				
			||||||
 | 
					                                RequireHttps = false,
 | 
				
			||||||
 | 
					                                ApiName = "api",
 | 
				
			||||||
 | 
					                                ApiSecret = "secret"
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt))
 | 
				
			||||||
 | 
					                .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura"))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888"))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenOcelotIsRunning())
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
 | 
				
			||||||
 | 
					                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
				
			||||||
 | 
					                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_response_403_using_identity_server_with_scope_not_allowed()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var configuration = new FileConfiguration
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ReRoutes = new List<FileReRoute>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        new FileReRoute
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            DownstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                            DownstreamPort = 51876,
 | 
				
			||||||
 | 
					                            DownstreamHost = "localhost",
 | 
				
			||||||
 | 
					                            DownstreamScheme = "http",
 | 
				
			||||||
 | 
					                            UpstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
				
			||||||
 | 
					                            AuthenticationOptions = new FileAuthenticationOptions
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                AllowedScopes =  new List<string>{ "api", "openid", "offline_access" },
 | 
				
			||||||
 | 
					                                Provider = "IdentityServer",
 | 
				
			||||||
 | 
					                                ProviderRootUrl = "http://localhost:51888",
 | 
				
			||||||
 | 
					                                RequireHttps = false,
 | 
				
			||||||
 | 
					                                ApiName = "api",
 | 
				
			||||||
 | 
					                                ApiSecret = "secret"
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt))
 | 
				
			||||||
 | 
					                .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura"))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888"))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenOcelotIsRunning())
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
 | 
				
			||||||
 | 
					                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
				
			||||||
 | 
					                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody)
 | 
					        private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _servicebuilder = new WebHostBuilder()
 | 
					            _servicebuilder = new WebHostBuilder()
 | 
				
			||||||
@@ -185,6 +263,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                                Scopes = new List<Scope>()
 | 
					                                Scopes = new List<Scope>()
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    new Scope("api"),
 | 
					                                    new Scope("api"),
 | 
				
			||||||
 | 
					                                    new Scope("api.readOnly"),
 | 
				
			||||||
                                    new Scope("openid"),
 | 
					                                    new Scope("openid"),
 | 
				
			||||||
                                    new Scope("offline_access")
 | 
					                                    new Scope("offline_access")
 | 
				
			||||||
                                },
 | 
					                                },
 | 
				
			||||||
@@ -209,7 +288,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                                ClientId = "client",
 | 
					                                ClientId = "client",
 | 
				
			||||||
                                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
 | 
					                                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
 | 
				
			||||||
                                ClientSecrets = new List<Secret> {new Secret("secret".Sha256())},
 | 
					                                ClientSecrets = new List<Secret> {new Secret("secret".Sha256())},
 | 
				
			||||||
                                AllowedScopes = new List<string> { apiName, "openid", "offline_access" },
 | 
					                                AllowedScopes = new List<string> { apiName, "api.readOnly", "openid", "offline_access" },
 | 
				
			||||||
                                AccessTokenType = tokenType,
 | 
					                                AccessTokenType = tokenType,
 | 
				
			||||||
                                Enabled = true,
 | 
					                                Enabled = true,
 | 
				
			||||||
                                RequireClientSecret = false
 | 
					                                RequireClientSecret = false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,7 +61,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                            {
 | 
					                            {
 | 
				
			||||||
								AllowedScopes = new List<string>
 | 
													AllowedScopes = new List<string>
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    "openid", "offline_access"
 | 
					                                    "openid", "offline_access", "api"
 | 
				
			||||||
                                },
 | 
					                                },
 | 
				
			||||||
                                Provider = "IdentityServer",
 | 
					                                Provider = "IdentityServer",
 | 
				
			||||||
                                ProviderRootUrl = "http://localhost:52888",
 | 
					                                ProviderRootUrl = "http://localhost:52888",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,7 +61,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                            {
 | 
					                            {
 | 
				
			||||||
								AllowedScopes = new List<string>
 | 
													AllowedScopes = new List<string>
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    "openid", "offline_access"
 | 
					                                    "openid", "offline_access", "api"
 | 
				
			||||||
                                },
 | 
					                                },
 | 
				
			||||||
                                Provider = "IdentityServer",
 | 
					                                Provider = "IdentityServer",
 | 
				
			||||||
                                ProviderRootUrl = "http://localhost:57888",
 | 
					                                ProviderRootUrl = "http://localhost:57888",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,7 +43,6 @@
 | 
				
			|||||||
    <PackageReference Include="Microsoft.AspNetCore.Http" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Http" Version="1.1.1" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" />
 | 
					    <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="1.1.1" />
 | 
				
			||||||
    <PackageReference Include="IdentityServer4" Version="1.0.1" />
 | 
					 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="1.1.1" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -199,6 +199,52 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void GivenIHaveATokenForApiReadOnlyScope(string url)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var tokenUrl = $"{url}/connect/token";
 | 
				
			||||||
 | 
					            var formData = new List<KeyValuePair<string, string>>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("client_id", "client"),
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("client_secret", "secret"),
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("scope", "api.readOnly"),
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("username", "test"),
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("password", "test"),
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("grant_type", "password")
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            var content = new FormUrlEncodedContent(formData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            using (var httpClient = new HttpClient())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var response = httpClient.PostAsync(tokenUrl, content).Result;
 | 
				
			||||||
 | 
					                var responseContent = response.Content.ReadAsStringAsync().Result;
 | 
				
			||||||
 | 
					                response.EnsureSuccessStatusCode();
 | 
				
			||||||
 | 
					                _token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void GivenIHaveATokenForApi2(string url)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var tokenUrl = $"{url}/connect/token";
 | 
				
			||||||
 | 
					            var formData = new List<KeyValuePair<string, string>>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("client_id", "client"),
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("client_secret", "secret"),
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("scope", "api2"),
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("username", "test"),
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("password", "test"),
 | 
				
			||||||
 | 
					                new KeyValuePair<string, string>("grant_type", "password")
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            var content = new FormUrlEncodedContent(formData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            using (var httpClient = new HttpClient())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var response = httpClient.PostAsync(tokenUrl, content).Result;
 | 
				
			||||||
 | 
					                var responseContent = response.Content.ReadAsStringAsync().Result;
 | 
				
			||||||
 | 
					                response.EnsureSuccessStatusCode();
 | 
				
			||||||
 | 
					                _token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void GivenIHaveAnOcelotToken(string adminPath)
 | 
					        public void GivenIHaveAnOcelotToken(string adminPath)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var tokenUrl = $"{adminPath}/connect/token";
 | 
					            var tokenUrl = $"{adminPath}/connect/token";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,7 @@
 | 
				
			|||||||
    <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" />
 | 
					    <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" />
 | 
				
			||||||
    <PackageReference Include="xunit" Version="2.2.0-beta5-build3474" />
 | 
					    <PackageReference Include="xunit" Version="2.2.0-beta5-build3474" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="1.1.1" />
 | 
				
			||||||
    <PackageReference Include="IdentityServer4" Version="1.0.1" />
 | 
					    <PackageReference Include="IdentityServer4" Version="1.5.1" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
 | 
				
			||||||
    <PackageReference Include="Shouldly" Version="2.8.2" />
 | 
					    <PackageReference Include="Shouldly" Version="2.8.2" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,8 @@ namespace Ocelot.UnitTests.Authorization
 | 
				
			|||||||
    public class AuthorisationMiddlewareTests : IDisposable
 | 
					    public class AuthorisationMiddlewareTests : IDisposable
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly Mock<IRequestScopedDataRepository> _scopedRepository;
 | 
					        private readonly Mock<IRequestScopedDataRepository> _scopedRepository;
 | 
				
			||||||
        private readonly Mock<IAuthoriser> _authService;
 | 
					        private readonly Mock<IClaimsAuthoriser> _authService;
 | 
				
			||||||
 | 
					        private readonly Mock<IScopesAuthoriser> _authScopesService;
 | 
				
			||||||
        private readonly string _url;
 | 
					        private readonly string _url;
 | 
				
			||||||
        private readonly TestServer _server;
 | 
					        private readonly TestServer _server;
 | 
				
			||||||
        private readonly HttpClient _client;
 | 
					        private readonly HttpClient _client;
 | 
				
			||||||
@@ -36,7 +37,8 @@ namespace Ocelot.UnitTests.Authorization
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            _url = "http://localhost:51879";
 | 
					            _url = "http://localhost:51879";
 | 
				
			||||||
            _scopedRepository = new Mock<IRequestScopedDataRepository>();
 | 
					            _scopedRepository = new Mock<IRequestScopedDataRepository>();
 | 
				
			||||||
            _authService = new Mock<IAuthoriser>();
 | 
					            _authService = new Mock<IClaimsAuthoriser>();
 | 
				
			||||||
 | 
					            _authScopesService = new Mock<IScopesAuthoriser>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var builder = new WebHostBuilder()
 | 
					            var builder = new WebHostBuilder()
 | 
				
			||||||
              .ConfigureServices(x =>
 | 
					              .ConfigureServices(x =>
 | 
				
			||||||
@@ -44,6 +46,7 @@ namespace Ocelot.UnitTests.Authorization
 | 
				
			|||||||
                  x.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
					                  x.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
				
			||||||
                  x.AddLogging();
 | 
					                  x.AddLogging();
 | 
				
			||||||
                  x.AddSingleton(_authService.Object);
 | 
					                  x.AddSingleton(_authService.Object);
 | 
				
			||||||
 | 
					                  x.AddSingleton(_authScopesService.Object);
 | 
				
			||||||
                  x.AddSingleton(_scopedRepository.Object);
 | 
					                  x.AddSingleton(_scopedRepository.Object);
 | 
				
			||||||
              })
 | 
					              })
 | 
				
			||||||
              .UseUrls(_url)
 | 
					              .UseUrls(_url)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user