diff --git a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs index 910b99e4..b4c1503a 100644 --- a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs +++ b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs @@ -19,17 +19,31 @@ namespace Ocelot.Authentication.Handler.Creator { var builder = app.New(); - var authenticationConfig = authOptions.Config as IdentityServerConfig; - - builder.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions + if (authOptions.Provider.ToLower() == "jwt") { - Authority = authenticationConfig.ProviderRootUrl, - ApiName = authenticationConfig.ApiName, - RequireHttpsMetadata = authenticationConfig.RequireHttps, - AllowedScopes = authOptions.AllowedScopes, - SupportedTokens = SupportedTokens.Both, - ApiSecret = authenticationConfig.ApiSecret - }); + var authenticationConfig = authOptions.Config as JwtConfig; + + builder.UseJwtBearerAuthentication( + new JwtBearerOptions() + { + Authority = authenticationConfig.Authority, + Audience = authenticationConfig.Audience + }); + } + else + { + var authenticationConfig = authOptions.Config as IdentityServerConfig; + + builder.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions + { + Authority = authenticationConfig.ProviderRootUrl, + ApiName = authenticationConfig.ApiName, + RequireHttpsMetadata = authenticationConfig.RequireHttps, + AllowedScopes = authOptions.AllowedScopes, + SupportedTokens = SupportedTokens.Both, + ApiSecret = authenticationConfig.ApiSecret + }); + } var authenticationNext = builder.Build(); diff --git a/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs b/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs index 2a815ee0..5662fe40 100644 --- a/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs +++ b/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs @@ -2,6 +2,7 @@ { public enum SupportedAuthenticationProviders { - IdentityServer + IdentityServer, + Jwt } } diff --git a/src/Ocelot/Configuration/AuthenticationOptions.cs b/src/Ocelot/Configuration/AuthenticationOptions.cs index c4a49b7d..1c71d68b 100644 --- a/src/Ocelot/Configuration/AuthenticationOptions.cs +++ b/src/Ocelot/Configuration/AuthenticationOptions.cs @@ -36,5 +36,18 @@ namespace Ocelot.Configuration public bool RequireHttps { get; private set; } } + public class JwtConfig : IAuthenticationConfig + { + public JwtConfig(string authority, string audience) + { + Audience = audience; + Authority = authority; + } + + public string Audience { get; } + + public string Authority { get; } + } + public interface IAuthenticationConfig {} } diff --git a/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs b/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs index 3f83d3a3..ea43a23e 100644 --- a/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs +++ b/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs @@ -9,7 +9,7 @@ namespace Ocelot.Configuration.Builder private List _allowedScopes; - private IdentityServerConfig _identityServerConfig; + private IAuthenticationConfig _identityServerConfig; public AuthenticationOptionsBuilder WithProvider(string provider) { @@ -23,7 +23,7 @@ namespace Ocelot.Configuration.Builder return this; } - public AuthenticationOptionsBuilder WithIdntityServerConfigConfiguration(IdentityServerConfig config) + public AuthenticationOptionsBuilder WithConfig(IAuthenticationConfig config) { _identityServerConfig = config; return this; @@ -66,11 +66,33 @@ namespace Ocelot.Configuration.Builder return this; } - - public IdentityServerConfig Build() { return new IdentityServerConfig(_providerRootUrl, _apiName, _requireHttps, _apiSecret); } } + + public class JwtConfigBuilder + { + public string _authority; + + public string _audience; + + public JwtConfigBuilder WithAuthority(string authority) + { + _authority = authority; + return this; + } + + public JwtConfigBuilder WithAudience(string audience) + { + _audience = audience; + return this; + } + + public JwtConfig Build() + { + return new JwtConfig(_authority, _audience); + } + } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs index 7f3f34a3..d5be4eee 100644 --- a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs @@ -7,25 +7,13 @@ namespace Ocelot.Configuration.Creator { public AuthenticationOptions Create(FileReRoute fileReRoute) { - var authenticationConfig = new IdentityServerConfigCreator().Create(fileReRoute.AuthenticationOptions); + var authenticationConfig = new ConfigCreator().Create(fileReRoute.AuthenticationOptions); return new AuthenticationOptionsBuilder() .WithProvider(fileReRoute.AuthenticationOptions?.Provider) .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) - .WithIdntityServerConfigConfiguration(authenticationConfig) + .WithConfig(authenticationConfig) .Build(); } } - - public class IdentityServerConfigCreator - { - public IdentityServerConfig Create(FileAuthenticationOptions authenticationOptions) - { - return new IdentityServerConfigBuilder() - .WithApiName(authenticationOptions.IdentityServerConfig?.ApiName) - .WithApiSecret(authenticationOptions.IdentityServerConfig?.ApiSecret) - .WithProviderRootUrl(authenticationOptions.IdentityServerConfig?.ProviderRootUrl) - .WithRequireHttps(authenticationOptions.IdentityServerConfig.RequireHttps).Build(); - } - } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/ConfigCreator.cs b/src/Ocelot/Configuration/Creator/ConfigCreator.cs new file mode 100644 index 00000000..09c7ab16 --- /dev/null +++ b/src/Ocelot/Configuration/Creator/ConfigCreator.cs @@ -0,0 +1,35 @@ +namespace Ocelot.Configuration.Creator +{ + using Ocelot.Configuration.Builder; + using Ocelot.Configuration.File; + + public class ConfigCreator + { + public IAuthenticationConfig Create(FileAuthenticationOptions authenticationOptions) + { + if (authenticationOptions.Provider == "Jwt") + { + return CreateJwt(authenticationOptions); + } + + return CreateIdentityServer(authenticationOptions); + } + + private JwtConfig CreateJwt(FileAuthenticationOptions authenticationOptions) + { + return new JwtConfigBuilder() + .WithAudience(authenticationOptions.JwtConfig?.Audience) + .WithAuthority(authenticationOptions.JwtConfig?.Authority) + .Build(); + } + + private IdentityServerConfig CreateIdentityServer(FileAuthenticationOptions authenticationOptions) + { + return new IdentityServerConfigBuilder() + .WithApiName(authenticationOptions.IdentityServerConfig?.ApiName) + .WithApiSecret(authenticationOptions.IdentityServerConfig?.ApiSecret) + .WithProviderRootUrl(authenticationOptions.IdentityServerConfig?.ProviderRootUrl) + .WithRequireHttps(authenticationOptions.IdentityServerConfig.RequireHttps).Build(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs index 8216aa8d..31be2307 100644 --- a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs +++ b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs @@ -8,11 +8,13 @@ namespace Ocelot.Configuration.File { AllowedScopes = new List(); IdentityServerConfig = new FileIdentityServerConfig(); + JwtConfig = new FileJwtConfig(); } public string Provider { get; set; } public List AllowedScopes { get; set; } public FileIdentityServerConfig IdentityServerConfig { get; set; } + public FileJwtConfig JwtConfig { get; set; } } public class FileIdentityServerConfig @@ -22,4 +24,11 @@ namespace Ocelot.Configuration.File public bool RequireHttps { get; set; } public string ApiSecret { get; set; } } + + public class FileJwtConfig + { + public string Authority { get; set; } + + public string Audience { get; set; } + } } diff --git a/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs b/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs index e63b1fe6..06699c28 100644 --- a/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs +++ b/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs @@ -25,8 +25,12 @@ namespace Ocelot.AcceptanceTests { switch (jsonObject["Provider"].Value()) { - //case "Jwt": - // setting = new + case "Jwt": + setting = new JwtConfig( + jsonObject["Authority"].Value(), + jsonObject["Audience"].Value()); + break; + default: setting = new IdentityServerConfig( jsonObject["ProviderRootUrl"].Value(), diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs index 8bf53607..55e1a05c 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs @@ -31,17 +31,19 @@ namespace Ocelot.UnitTests.Authentication _authenticationHandlerFactory = new AuthenticationHandlerFactory(_creator.Object); } - [Fact] - public void should_return_identity_server_access_token_handler() + [Theory] + [InlineData("IdentityServer")] + [InlineData("Jwt")] + public void should_return_access_token_handler(string provider) { var authenticationOptions = new AuthenticationOptionsBuilder() - .WithProvider("IdentityServer") + .WithProvider(provider) .Build(); this.Given(x => x.GivenTheAuthenticationOptionsAre(authenticationOptions)) .And(x => x.GivenTheCreatorReturns()) .When(x => x.WhenIGetFromTheFactory()) - .Then(x => x.ThenTheHandlerIsReturned("IdentityServer")) + .Then(x => x.ThenTheHandlerIsReturned(provider)) .BDDfy(); } diff --git a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs index 575b62b7..85245207 100644 --- a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs @@ -20,36 +20,78 @@ namespace Ocelot.UnitTests.Configuration _authOptionsCreator = new AuthenticationOptionsCreator(); } - // [Fact] - // public void should_return_auth_options() - // { - // var fileReRoute = new FileReRoute() - // { - // AuthenticationOptions = new FileAuthenticationOptions - // { - // Provider = "Geoff", - // ProviderRootUrl = "http://www.bbc.co.uk/", - //ApiName = "Laura", - // RequireHttps = true, - //AllowedScopes = new List {"cheese"}, - // ApiSecret = "secret" - // } - // }; + [Fact] + public void should_return_auth_options() + { + var fileReRoute = new FileReRoute() + { + AuthenticationOptions = new FileAuthenticationOptions + { + Provider = "Geoff", + IdentityServerConfig = new FileIdentityServerConfig() + { + ProviderRootUrl = "http://www.bbc.co.uk/", + ApiName = "Laura", + RequireHttps = true, + ApiSecret = "secret" + }, + AllowedScopes = new List { "cheese" }, + + } + }; - // var expected = new AuthenticationOptionsBuilder() - // .WithProvider(fileReRoute.AuthenticationOptions?.Provider) - // .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.ProviderRootUrl) - // .WithApiName(fileReRoute.AuthenticationOptions?.ApiName) - // .WithRequireHttps(fileReRoute.AuthenticationOptions.RequireHttps) - // .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) - // .WithApiSecret(fileReRoute.AuthenticationOptions?.ApiSecret) - // .Build(); + var authenticationConfig = new IdentityServerConfigBuilder() + .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ProviderRootUrl) + .WithApiName(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ApiName) + .WithRequireHttps(fileReRoute.AuthenticationOptions.IdentityServerConfig.RequireHttps) + .WithApiSecret(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ApiSecret) + .Build(); - // this.Given(x => x.GivenTheFollowing(fileReRoute)) - // .When(x => x.WhenICreateTheAuthenticationOptions()) - // .Then(x => x.ThenTheFollowingIsReturned(expected)) - // .BDDfy(); - // } + var expected = new AuthenticationOptionsBuilder() + .WithProvider(fileReRoute.AuthenticationOptions?.Provider) + .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) + .WithConfig(authenticationConfig) + .Build(); + + this.Given(x => x.GivenTheFollowing(fileReRoute)) + .When(x => x.WhenICreateTheAuthenticationOptions()) + .Then(x => x.ThenTheFollowingIdentityServerConfigIsReturned(expected)) + .BDDfy(); + } + + [Fact] + public void should_return_Jwt_auth_options() + { + var fileReRoute = new FileReRoute() + { + AuthenticationOptions = new FileAuthenticationOptions + { + Provider = "Jwt", + JwtConfig = new FileJwtConfig() + { + Audience = "Audience", + Authority = "Authority" + }, + AllowedScopes = new List { "cheese" } + } + }; + + var authenticationConfig = new JwtConfigBuilder() + .WithAudience(fileReRoute.AuthenticationOptions?.JwtConfig?.Audience) + .WithAuthority(fileReRoute.AuthenticationOptions?.JwtConfig?.Authority) + .Build(); + + var expected = new AuthenticationOptionsBuilder() + .WithProvider(fileReRoute.AuthenticationOptions?.Provider) + .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) + .WithConfig(authenticationConfig) + .Build(); + + this.Given(x => x.GivenTheFollowing(fileReRoute)) + .When(x => x.WhenICreateTheAuthenticationOptions()) + .Then(x => x.ThenTheFollowingJwtConfigIsReturned(expected)) + .BDDfy(); + } private void GivenTheFollowing(FileReRoute fileReRoute) { @@ -61,14 +103,31 @@ namespace Ocelot.UnitTests.Configuration _result = _authOptionsCreator.Create(_fileReRoute); } - //private void ThenTheFollowingIsReturned(AuthenticationOptions expected) - //{ - // _result.AllowedScopes.ShouldBe(expected.AllowedScopes); - // _result.Provider.ShouldBe(expected.Provider); - // _result.ProviderRootUrl.ShouldBe(expected.ProviderRootUrl); - // _result.RequireHttps.ShouldBe(expected.RequireHttps); - // _result.ApiName.ShouldBe(expected.ApiName); - // _result.ApiSecret.ShouldBe(expected.ApiSecret); - //} + private void ThenTheFollowingJwtConfigIsReturned(AuthenticationOptions expected) + { + _result.AllowedScopes.ShouldBe(expected.AllowedScopes); + _result.Provider.ShouldBe(expected.Provider); + + var _resultSettings = _result.Config as JwtConfig; + var expectedSettngs = expected.Config as JwtConfig; + + _resultSettings.Audience.ShouldBe(expectedSettngs.Audience); + _resultSettings.Authority.ShouldBe(expectedSettngs.Authority); + + } + + private void ThenTheFollowingIdentityServerConfigIsReturned(AuthenticationOptions expected) + { + _result.AllowedScopes.ShouldBe(expected.AllowedScopes); + _result.Provider.ShouldBe(expected.Provider); + + var _resultSettings = _result.Config as IdentityServerConfig; + var expectedSettngs = expected.Config as IdentityServerConfig; + + _resultSettings.ProviderRootUrl.ShouldBe(expectedSettngs.ProviderRootUrl); + _resultSettings.RequireHttps.ShouldBe(expectedSettngs.RequireHttps); + _resultSettings.ApiName.ShouldBe(expectedSettngs.ApiName); + _resultSettings.ApiSecret.ShouldBe(expectedSettngs.ApiSecret); + } } } \ No newline at end of file