This commit is contained in:
Dave Tillman 2017-12-15 11:53:26 -07:00
Родитель d8f92cccee
Коммит c5af0cd93d
66 изменённых файлов: 972 добавлений и 856 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -153,7 +153,6 @@ AppPackages/
# Others
*.[Cc]ache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl

Просмотреть файл

@ -5,11 +5,11 @@ env:
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
- DOTNET_CLI_TELEMETRY_OPTOUT: 1
mono: none
dotnet: 2.0.0
dotnet: 2.0.3
os:
- linux
- osx
osx_image: xcode8.2
osx_image: xcode8.3
branches:
only:
- master

Просмотреть файл

@ -2,18 +2,19 @@
<PropertyGroup>
<SteeltoeVersion>$(STEELTOE_VERSION)</SteeltoeVersion>
<SteeltoeVersionSuffix>$(STEELTOE_DASH_VERSION_SUFFIX)</SteeltoeVersionSuffix>
<SteeltoeConnectorVersion>2.0.0-dev-00192</SteeltoeConnectorVersion>
<SteeltoeCommonVersion>2.0.0-dev-00022</SteeltoeCommonVersion>
<SteeltoeConnectorVersion>2.0.0-dev-00198</SteeltoeConnectorVersion>
<SteeltoeCommonVersion>2.0.0-dev-00040</SteeltoeCommonVersion>
<AspNetCoreVersion>2.0.0</AspNetCoreVersion>
<AspNetCoreDataProtectionRedisVersion>0.3.0</AspNetCoreDataProtectionRedisVersion>
<AspNetCoreTestVersion>2.0.0</AspNetCoreTestVersion>
<AspNetCoreMvcTestVersion>2.0.0</AspNetCoreMvcTestVersion>
<AspNetCoreDepTestVersion>2.0.0</AspNetCoreDepTestVersion>
<CoreFxVersion>4.4.0</CoreFxVersion>
<JsonNetVersion>10.0.1</JsonNetVersion>
<TestSdkVersion>15.3.0</TestSdkVersion>
<XunitVersion>2.3.0-beta4-build3742</XunitVersion>
<XunitStudioVersion>2.3.0-beta4-build3742</XunitStudioVersion>
<StyleCopVersion>1.0.2</StyleCopVersion>
<JsonNetVersion>10.0.3</JsonNetVersion>
<TestSdkVersion>15.5.0</TestSdkVersion>
<XunitVersion>2.3.1</XunitVersion>
<XunitStudioVersion>2.3.1</XunitStudioVersion>
<HttpClientVersion>4.3.3</HttpClientVersion>
<OwinOAuthVerions>3.1.0</OwinOAuthVerions>
<JwtTokensVerions>5.1.4</JwtTokensVerions>

Просмотреть файл

@ -2,17 +2,19 @@
<PropertyGroup>
<SteeltoeVersion>$(STEELTOE_VERSION)</SteeltoeVersion>
<SteeltoeVersionSuffix>$(STEELTOE_DASH_VERSION_SUFFIX)</SteeltoeVersionSuffix>
<SteeltoeConnectorVersion>2.0.0-master-00173</SteeltoeConnectorVersion>
<SteeltoeConnectorVersion>2.0.0-master-00199</SteeltoeConnectorVersion>
<SteeltoeCommonVersion>2.0.0-master-00041</SteeltoeCommonVersion>
<AspNetCoreVersion>2.0.0</AspNetCoreVersion>
<AspNetCoreDataProtectionRedisVersion>0.3.0</AspNetCoreDataProtectionRedisVersion>
<AspNetCoreTestVersion>2.0.0</AspNetCoreTestVersion>
<AspNetCoreMvcTestVersion>2.0.0</AspNetCoreMvcTestVersion>
<AspNetCoreDepTestVersion>2.0.0</AspNetCoreDepTestVersion>
<CoreFxVersion>4.4.0</CoreFxVersion>
<JsonNetVersion>10.0.1</JsonNetVersion>
<TestSdkVersion>15.3.0</TestSdkVersion>
<XunitVersion>2.3.0-beta4-build3742</XunitVersion>
<XunitStudioVersion>2.3.0-beta4-build3742</XunitStudioVersion>
<StyleCopVersion>1.0.2</StyleCopVersion>
<JsonNetVersion>10.0.3</JsonNetVersion>
<TestSdkVersion>15.5.0</TestSdkVersion>
<XunitVersion>2.3.1</XunitVersion>
<XunitStudioVersion>2.3.1</XunitStudioVersion>
<HttpClientVersion>4.3.3</HttpClientVersion>
<OwinOAuthVerions>3.1.0</OwinOAuthVerions>
<JwtTokensVerions>5.1.4</JwtTokensVerions>

Просмотреть файл

@ -9,10 +9,11 @@
<AspNetCoreMvcTestVersion>2.0.0</AspNetCoreMvcTestVersion>
<AspNetCoreDepTestVersion>2.0.0</AspNetCoreDepTestVersion>
<CoreFxVersion>4.4.0</CoreFxVersion>
<JsonNetVersion>10.0.1</JsonNetVersion>
<TestSdkVersion>15.3.0</TestSdkVersion>
<XunitVersion>2.3.0-beta4-build3742</XunitVersion>
<XunitStudioVersion>2.3.0-beta4-build3742</XunitStudioVersion>
<StyleCopVersion>1.0.2</StyleCopVersion>
<JsonNetVersion>10.0.3</JsonNetVersion>
<TestSdkVersion>15.5.0</TestSdkVersion>
<XunitVersion>2.3.1</XunitVersion>
<XunitStudioVersion>2.3.1</XunitStudioVersion>
<HttpClientVersion>4.3.3</HttpClientVersion>
<OwinOAuthVerions>3.1.0</OwinOAuthVerions>
<JwtTokensVerions>5.1.4</JwtTokensVerions>

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,25 +11,22 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
using System;
using System.Security.Claims;
namespace Steeltoe.Security.Authentication.CloudFoundry
{
public static class CloudFoundryClaimActionExtensions
{
public static void MapScopes(this ClaimActionCollection collection, string claimType = "scope")
{
if (collection == null)
{
throw new ArgumentNullException(nameof(collection));
}
collection.Add(new CloudFoundryScopeClaimAction(claimType, ClaimValueTypes.String));
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
namespace Steeltoe.Security.Authentication.CloudFoundry
{

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,12 +11,11 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Steeltoe.CloudFoundry.Connector;
using Steeltoe.CloudFoundry.Connector.Services;
using System;
@ -41,7 +39,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
SsoServiceInfo info = config.GetSingletonServiceInfo<SsoServiceInfo>();
CloudFoundryOAuthConfigurer.Configure(info, options);
});
return builder;
}
@ -77,7 +74,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
SsoServiceInfo info = config.GetSingletonServiceInfo<SsoServiceInfo>();
CloudFoundryJwtBearerConfigurer.Configure(info, options, cloudFoundryOptions);
});
return builder;
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,17 +11,15 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using Newtonsoft.Json.Linq;
using Steeltoe.Common;
using System;
using System.Collections.Generic;
using System.Net.Http;
using Steeltoe.Common;
namespace Steeltoe.Security.Authentication.CloudFoundry
{
public static class CloudFoundryHelper
{
public static DateTime GetIssueTime(JObject payload)
@ -31,6 +28,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
{
throw new ArgumentNullException(nameof(payload));
}
var time = payload.Value<long>("iat");
return ToAbsoluteUTC(time);
}
@ -41,17 +39,21 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
{
throw new ArgumentNullException(nameof(payload));
}
var time = payload.Value<long>("exp");
return ToAbsoluteUTC(time);
}
private static DateTime baseTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private static DateTime ToAbsoluteUTC(long secondsPastEpoch)
{
return baseTime.AddSeconds(secondsPastEpoch);
}
#pragma warning disable SA1202 // Elements must be ordered by access
public static List<string> GetScopes(JObject user)
#pragma warning restore SA1202 // Elements must be ordered by access
{
if (user == null)
{
@ -71,6 +73,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
result.Add(asValue.Value<string>());
return result;
}
var asArray = scopes as JArray;
if (asArray != null)
{
@ -79,12 +82,12 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
result.Add(s);
}
}
return result;
}
public static HttpMessageHandler GetBackChannelHandler(bool validateCertificates)
{
if (Platform.IsFullFramework)
{
return null;
@ -93,14 +96,15 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
{
if (!validateCertificates)
{
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
};
return handler;
}
return null;
}
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
@ -25,7 +23,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
{
internal static void Configure(SsoServiceInfo si, JwtBearerOptions jwtOptions, CloudFoundryJwtBearerOptions options)
{
if (jwtOptions == null || options == null)
{
return;
@ -33,21 +30,21 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
if (si != null)
{
options.JwtKeyUrl = si.AuthDomain + CloudFoundryDefaults.JwtTokenKey;
options.JwtKeyUrl = si.AuthDomain + CloudFoundryDefaults.JwtTokenKey;
}
jwtOptions.ClaimsIssuer = options.ClaimsIssuer;
jwtOptions.BackchannelHttpHandler = CloudFoundryHelper.GetBackChannelHandler(options.ValidateCertificates);
jwtOptions.TokenValidationParameters = GetTokenValidationParameters(jwtOptions.TokenValidationParameters, options.JwtKeyUrl, jwtOptions.BackchannelHttpHandler, options.ValidateCertificates);
jwtOptions.SaveToken = options.SaveToken;
}
internal static TokenValidationParameters GetTokenValidationParameters(TokenValidationParameters parameters, string keyUrl, HttpMessageHandler handler, bool validateCertificates)
{
if (parameters == null)
{
parameters = new TokenValidationParameters();
}
parameters.ValidateAudience = false;
parameters.ValidateIssuer = true;

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,26 +11,25 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication.JwtBearer;
namespace Steeltoe.Security.Authentication.CloudFoundry
{
public class CloudFoundryJwtBearerOptions : JwtBearerOptions
{
public string JwtKeyUrl { get; set; }
public bool Validate_Certificates { get; set; } = true;
public bool ValidateCertificates => Validate_Certificates;
public CloudFoundryJwtBearerOptions()
{
string authURL = "http://" + CloudFoundryDefaults.OAuthServiceUrl;
ClaimsIssuer = CloudFoundryDefaults.AuthenticationScheme;
ClaimsIssuer = CloudFoundryDefaults.AuthenticationScheme;
JwtKeyUrl = authURL + CloudFoundryDefaults.JwtTokenKey;
SaveToken = true;
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,12 +11,8 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Steeltoe.CloudFoundry.Connector.Services;
using Steeltoe.Common;
using System.Net.Http;
namespace Steeltoe.Security.Authentication.CloudFoundry
{
@ -29,6 +24,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
{
return;
}
if (si != null)
{
options.ClientId = si.ClientId;
@ -37,15 +33,9 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
options.TokenEndpoint = si.AuthDomain + CloudFoundryDefaults.AccessTokenUri;
options.UserInformationEndpoint = si.AuthDomain + CloudFoundryDefaults.UserInfoUri;
options.TokenInfoUrl = si.AuthDomain + CloudFoundryDefaults.CheckTokenUri;
}
options.BackchannelHttpHandler = CloudFoundryHelper.GetBackChannelHandler(options.ValidateCertificates);
}
}
}

Просмотреть файл

@ -1,4 +1,3 @@
//
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -12,51 +11,120 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using Steeltoe.Common.Http;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Microsoft.AspNetCore.WebUtilities;
using System.Net.Http.Headers;
using System.Text;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using System.Text.Encodings.Web;
using Steeltoe.Common.Http;
using System.Net.Security;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
namespace Steeltoe.Security.Authentication.CloudFoundry
{
public class CloudFoundryOAuthHandler : OAuthHandler<CloudFoundryOAuthOptions>
{
ILogger<CloudFoundryOAuthHandler> _logger;
private ILogger<CloudFoundryOAuthHandler> _logger;
public CloudFoundryOAuthHandler(
IOptionsMonitor<CloudFoundryOAuthOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock) : base(options, logger, encoder, clock)
ISystemClock clock)
: base(options, logger, encoder, clock)
{
_logger = logger?.CreateLogger<CloudFoundryOAuthHandler>();
}
protected internal virtual Dictionary<string, string> GetTokenInfoRequestParameters(OAuthTokenResponse tokens)
{
_logger?.LogDebug("GetTokenInfoRequestParameters() using token: {token}", tokens.AccessToken);
return new Dictionary<string, string>()
{
{ "token", tokens.AccessToken }
};
}
protected internal virtual HttpRequestMessage GetTokenInfoRequestMessage(OAuthTokenResponse tokens)
{
_logger?.LogDebug("GetTokenInfoRequestMessage({token}) with {clientId}", tokens.AccessToken, Options.ClientId);
var tokenRequestParameters = GetTokenInfoRequestParameters(tokens);
var requestContent = new FormUrlEncodedContent(tokenRequestParameters);
var request = new HttpRequestMessage(HttpMethod.Post, Options.TokenInfoUrl);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", GetEncoded(Options.ClientId, Options.ClientSecret));
request.Content = requestContent;
return request;
}
protected internal virtual Dictionary<string, string> GetTokenRequestParameters(string code, string redirectUri)
{
return new Dictionary<string, string>()
{
{ "client_id", Options.ClientId },
{ "redirect_uri", redirectUri },
{ "client_secret", Options.ClientSecret },
{ "code", code },
{ "grant_type", "authorization_code" },
};
}
protected internal virtual HttpRequestMessage GetTokenRequestMessage(string code, string redirectUri)
{
var tokenRequestParameters = GetTokenRequestParameters(code, redirectUri);
var requestContent = new FormUrlEncodedContent(tokenRequestParameters);
var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.TokenEndpoint);
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
requestMessage.Content = requestContent;
return requestMessage;
}
protected internal string GetEncoded(string user, string password)
{
if (user == null)
{
user = string.Empty;
}
if (password == null)
{
password = string.Empty;
}
return Convert.ToBase64String(Encoding.ASCII.GetBytes(user + ":" + password));
}
protected internal virtual HttpClient GetHttpClient()
{
return Backchannel;
}
protected override async Task<OAuthTokenResponse> ExchangeCodeAsync(string code, string redirectUri)
{
_logger?.LogDebug("ExchangeCodeAsync({code},{redirectUri})", code, redirectUri);
HttpRequestMessage requestMessage = GetTokenRequestMessage(code, redirectUri);
HttpClient client = GetHttpClient();
RemoteCertificateValidationCallback prevValidator = null;
SecurityProtocolType prevProtocols = (SecurityProtocolType)0;
HttpClientHelper.ConfigureCertificateValidatation(Options.ValidateCertificates, out prevProtocols, out prevValidator);
HttpClientHelper.ConfigureCertificateValidatation(
Options.ValidateCertificates,
out SecurityProtocolType prevProtocols,
out RemoteCertificateValidationCallback prevValidator);
HttpResponseMessage response = null;
try
@ -67,7 +135,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
{
HttpClientHelper.RestoreCertificateValidation(Options.ValidateCertificates, prevProtocols, prevValidator);
}
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
@ -85,7 +153,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
}
}
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
{
_logger?.LogDebug("CreateTicketAsync()");
@ -93,9 +160,10 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
HttpRequestMessage request = GetTokenInfoRequestMessage(tokens);
HttpClient client = GetHttpClient();
RemoteCertificateValidationCallback prevValidator = null;
SecurityProtocolType prevProtocols = (SecurityProtocolType)0;
HttpClientHelper.ConfigureCertificateValidatation(Options.ValidateCertificates, out prevProtocols, out prevValidator);
HttpClientHelper.ConfigureCertificateValidatation(
Options.ValidateCertificates,
out SecurityProtocolType prevProtocols,
out RemoteCertificateValidationCallback prevValidator);
HttpResponseMessage response = null;
try
@ -134,17 +202,18 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
return ticket;
}
protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
{
_logger?.LogDebug("BuildChallengeUrl({redirectUri}) with {clientId}", redirectUri, Options.ClientId);
var scope = FormatScope();
var queryStrings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
queryStrings.Add("response_type", "code");
queryStrings.Add("client_id", Options.ClientId);
queryStrings.Add("redirect_uri", redirectUri);
var queryStrings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "response_type", "code" },
{ "client_id", Options.ClientId },
{ "redirect_uri", redirectUri }
};
AddQueryString(queryStrings, properties, "scope", scope);
@ -158,73 +227,9 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
return authorizationEndpoint;
}
internal protected virtual Dictionary<string, string> GetTokenInfoRequestParameters(OAuthTokenResponse tokens)
{
_logger?.LogDebug("GetTokenInfoRequestParameters() using token: {token}", tokens.AccessToken);
return new Dictionary<string, string>()
{
{ "token", tokens.AccessToken }
};
}
internal protected virtual HttpRequestMessage GetTokenInfoRequestMessage(OAuthTokenResponse tokens)
{
_logger?.LogDebug("GetTokenInfoRequestMessage({token}) with {clientId}", tokens.AccessToken, Options.ClientId);
var tokenRequestParameters = GetTokenInfoRequestParameters(tokens);
var requestContent = new FormUrlEncodedContent(tokenRequestParameters);
var request = new HttpRequestMessage(HttpMethod.Post, Options.TokenInfoUrl);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", GetEncoded(Options.ClientId, Options.ClientSecret));
request.Content = requestContent;
return request;
}
internal protected virtual Dictionary<string, string> GetTokenRequestParameters(string code, string redirectUri)
{
return new Dictionary<string, string>()
{
{ "client_id", Options.ClientId },
{ "redirect_uri", redirectUri },
{ "client_secret", Options.ClientSecret },
{ "code", code },
{ "grant_type", "authorization_code" },
};
}
internal protected virtual HttpRequestMessage GetTokenRequestMessage(string code, string redirectUri)
{
var tokenRequestParameters = GetTokenRequestParameters(code, redirectUri);
var requestContent = new FormUrlEncodedContent(tokenRequestParameters);
var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.TokenEndpoint);
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
requestMessage.Content = requestContent;
return requestMessage;
}
internal protected string GetEncoded(string user, string password)
{
if (user == null)
user = string.Empty;
if (password == null)
password = string.Empty;
return Convert.ToBase64String(Encoding.ASCII.GetBytes(user + ":" + password));
}
internal protected virtual HttpClient GetHttpClient()
{
return Backchannel;
}
private static void AddQueryString(IDictionary<string, string> queryStrings, AuthenticationProperties properties, string name, string defaultValue = null)
{
string value;
if (!properties.Items.TryGetValue(name, out value))
if (!properties.Items.TryGetValue(name, out string value))
{
value = defaultValue;
}
@ -240,6 +245,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
queryStrings[name] = value;
}
private static async Task<string> Display(HttpResponseMessage response)
{
var output = new StringBuilder();
@ -248,6 +254,5 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
output.Append("Body: " + await response.Content.ReadAsStringAsync() + ";");
return output.ToString();
}
}
}

Просмотреть файл

@ -1,4 +1,3 @@
//
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -12,23 +11,23 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Authentication;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
namespace Steeltoe.Security.Authentication.CloudFoundry
{
public class CloudFoundryOAuthOptions : OAuthOptions
{
public string TokenInfoUrl { get; set; }
public bool Validate_Certificates { get; set; } = true;
public bool ValidateCertificates => Validate_Certificates;
public bool UseTokenLifetime { get; set; } = true;
public CloudFoundryOAuthOptions()
@ -44,7 +43,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
TokenInfoUrl = authURL + CloudFoundryDefaults.CheckTokenUri;
SaveTokens = true;
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "user_id");
ClaimActions.MapJsonKey(ClaimTypes.Name, "user_name");
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name");
@ -54,6 +52,5 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
using Newtonsoft.Json.Linq;
@ -22,7 +20,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
{
public class CloudFoundryScopeClaimAction : ClaimAction
{
public CloudFoundryScopeClaimAction(string claimType, string valueType)
public CloudFoundryScopeClaimAction(string claimType, string valueType)
: base(claimType, valueType)
{
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.IdentityModel.Tokens;
using Steeltoe.Common;
@ -30,7 +28,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
{
public class CloudFoundryTokenKeyResolver
{
internal static ConcurrentDictionary<string, SecurityKey> Resolved { get; set; } = new ConcurrentDictionary<string, SecurityKey>();
private string _jwtKeyUrl;
@ -39,7 +36,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
public CloudFoundryTokenKeyResolver(string jwtKeyUrl, HttpMessageHandler httpHandler, bool validateCertificates)
{
if (string.IsNullOrEmpty(jwtKeyUrl ))
if (string.IsNullOrEmpty(jwtKeyUrl))
{
throw new ArgumentException(nameof(jwtKeyUrl));
}
@ -51,8 +48,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
public virtual IEnumerable<SecurityKey> ResolveSigningKey(string token, SecurityToken securityToken, string kid, TokenValidationParameters validationParameters)
{
SecurityKey resolved = null;
if (Resolved.TryGetValue(kid, out resolved))
if (Resolved.TryGetValue(kid, out SecurityKey resolved))
{
return new List<SecurityKey> { resolved };
}
@ -66,34 +62,26 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
Resolved[key.Kid] = key;
}
}
if (Resolved.TryGetValue(kid, out resolved))
{
return new List<SecurityKey> { resolved };
}
return null;
}
public JsonWebKey FixupKey(JsonWebKey key)
{
if (Platform.IsFullFramework)
{
byte[] existing = Base64UrlEncoder.DecodeBytes(key.N);
TrimKey(key, existing);
}
return key;
}
private void TrimKey(JsonWebKey key, byte[] existing)
{
byte[] signRemoved = new byte[existing.Length -1];
Buffer.BlockCopy(existing, 1, signRemoved, 0, existing.Length - 1);
string withSignRemoved = Base64UrlEncoder.Encode(signRemoved);
key.N = withSignRemoved;
}
public virtual async Task<JsonWebKeySet> FetchKeySet()
{
var requestMessage = new HttpRequestMessage(HttpMethod.Get, _jwtKeyUrl);
@ -101,9 +89,10 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
HttpClient client = GetHttpClient();
RemoteCertificateValidationCallback prevValidator = null;
SecurityProtocolType prevProtocols = (SecurityProtocolType)0;
HttpClientHelper.ConfigureCertificateValidatation(_validateCertificates, out prevProtocols, out prevValidator);
HttpClientHelper.ConfigureCertificateValidatation(
_validateCertificates,
out SecurityProtocolType prevProtocols,
out RemoteCertificateValidationCallback prevValidator);
HttpResponseMessage response = null;
try
@ -120,6 +109,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
var result = await response.Content.ReadAsStringAsync();
return GetJsonWebKeySet(result);
}
return null;
}
@ -134,7 +124,16 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
{
return new HttpClient(_httpHandler);
}
return new HttpClient();
}
private void TrimKey(JsonWebKey key, byte[] existing)
{
byte[] signRemoved = new byte[existing.Length - 1];
Buffer.BlockCopy(existing, 1, signRemoved, 0, existing.Length - 1);
string withSignRemoved = Base64UrlEncoder.Encode(signRemoved);
key.N = withSignRemoved;
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,12 +11,9 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.IdentityModel.Tokens;
namespace Steeltoe.Security.Authentication.CloudFoundry
{
public static class CloudFoundryTokenValidator
@ -28,8 +24,8 @@ namespace Steeltoe.Security.Authentication.CloudFoundry
{
return issuer;
}
return null;
}
}
}

Просмотреть файл

@ -1,6 +1,17 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Steeltoe.Security.Authentication.CloudFoundryCore.Test")]

Просмотреть файл

@ -16,7 +16,7 @@
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
</PropertyGroup>
<ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OAuth" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(AspNetCoreVersion)" />
@ -24,6 +24,17 @@
<PackageReference Include="Steeltoe.CloudFoundry.Connector" Version="$(SteeltoeConnectorVersion)" />
<PackageReference Include="Steeltoe.Common.Http" Version="$(SteeltoeCommonVersion)" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="StyleCop.Analyzers" Version="$(StyleCopVersion)">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<NoWarn>SA1101;SA1124;SA1201;SA1309;SA1310;SA1401;SA1600;SA1652;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json">
<Link>stylecop.json</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AdditionalFiles>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
{

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Security;
@ -22,21 +20,45 @@ using System.Threading.Tasks;
namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
{
class OpenIDConnectAuthenticationHandler : AuthenticationHandler<OpenIDConnectOptions>
public class OpenIDConnectAuthenticationHandler : AuthenticationHandler<OpenIDConnectOptions>
{
/*
* Invoked for every request. As this is passive middleware, we only want to branch off
* the authentication flow if the request being invoked is the callback path we gave as a redirect
* uri to the auth flow when invoking the IDP
*/
public override async Task<bool> InvokeAsync()
{
if (Options.CallbackPath.HasValue && Options.CallbackPath == Request.Path)
{
var ticket = await AuthenticateAsync();
if (ticket != null)
{
Context.Authentication.SignIn(ticket.Properties, ticket.Identity);
Response.Redirect(ticket.Properties.RedirectUri);
// Short-circuit, stopping rest of owin pipeline.
return true;
}
}
// Nothing to see here, please disperse.
return false;
}
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
{
var code = Request.Query["code"];
Debug.WriteLine("Received an authorization code from IDP: " + code);
Debug.WriteLine("== exchanging for token ==");
// ASP.Net Identity requires the NameIdentitifer field to be set or it won't
// ASP.Net Identity requires the NameIdentitifer field to be set or it won't
// accept the external login (AuthenticationManagerExtensions.GetExternalLoginInfo)
var identity = await TokenExchanger.ExchangeCodeForToken(code, Options);
var properties = Options.StateDataFormat.Unprotect(Request.Query["state"]);
//return Task.FromResult(new AuthenticationTicket(identity, properties));
// return Task.FromResult(new AuthenticationTicket(identity, properties));
var ticket = new AuthenticationTicket(identity, properties);
return ticket;
}
@ -69,33 +91,9 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
return Task.FromResult<object>(null);
}
protected override Task InitializeCoreAsync()
{
return base.InitializeCoreAsync();
}
/*
* Invoked for every request. As this is passive middleware, we only want to branch off
* the authentication flow if the request being invoked is the callback path we gave as a redirect
* uri to the auth flow when invoking the IDP
*/
public override async Task<bool> InvokeAsync()
{
if (Options.CallbackPath.HasValue && Options.CallbackPath == Request.Path)
{
var ticket = await AuthenticateAsync();
if (ticket != null)
{
Context.Authentication.SignIn(ticket.Properties, ticket.Identity);
Response.Redirect(ticket.Properties.RedirectUri);
// Short-circuit, stopping rest of owin pipeline.
return true;
}
}
// Nothing to see here, please disperse.
return false;
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.Owin;
using Microsoft.Owin.Security;
@ -32,9 +30,11 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
{
options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType();
}
if (options.StateDataFormat == null)
{
var dataProtector = app.CreateDataProtector(typeof(OpenIDConnectAuthenticationMiddleware).FullName,
var dataProtector = app.CreateDataProtector(
typeof(OpenIDConnectAuthenticationMiddleware).FullName,
options.AuthenticationType);
options.StateDataFormat = new PropertiesDataFormat(dataProtector);
@ -47,4 +47,3 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Owin;
using System.Net;

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.Owin;
using Microsoft.Owin.Security;
@ -21,7 +19,8 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
{
public class OpenIDConnectOptions : AuthenticationOptions
{
public OpenIDConnectOptions() : base(Constants.DefaultAuthenticationType)
public OpenIDConnectOptions()
: base(Constants.DefaultAuthenticationType)
{
Description.Caption = Constants.DefaultAuthenticationType;
CallbackPath = new PathString("/signin-oidc");

Просмотреть файл

@ -21,7 +21,18 @@
<PackageReference Include="Microsoft.Owin.Security.OAuth" Version="$(OwinOAuthVerions)" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="$(JwtTokensVerions)" />
<PackageReference Include="System.Net.Http" Version="$(HttpClientVersion)" />
<PackageReference Include="StyleCop.Analyzers" Version="$(StyleCopVersion)">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<NoWarn>SA1101;SA1124;SA1201;SA1309;SA1310;SA1401;SA1600;SA1652;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json">
<Link>stylecop.json</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AdditionalFiles>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Newtonsoft.Json.Linq;
using System;
@ -30,9 +31,13 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
{
string redirect_url = "https://" + options.AppHost;
if (options.AppPort != 0)
{
redirect_url = redirect_url + ":" + options.AppPort + options.CallbackPath;
}
else
{
redirect_url = redirect_url + options.CallbackPath;
}
var hostName = options.AuthDomain;
var pairs = new[]
@ -55,11 +60,9 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
using (var client = new HttpClient())
{
var byteArray = Encoding.ASCII.GetBytes(options.ClientID + ":" + options.ClientSecret);
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
var response = await client.PostAsync(targetUrl, content);
if (response.IsSuccessStatusCode)
{
@ -76,7 +79,8 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
foreach (var claim in securityToken.Claims)
{
Debug.WriteLine(claim.Type + " : " + claim.Value);
// claimsId.AddClaim(claim);
// claimsId.AddClaim(claim);
}
claimsId.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId));
@ -96,4 +100,3 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,17 +11,15 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.Owin.Infrastructure;
using System;
namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
{
internal static class UriUtility
{
internal static String CalculateFullRedirectUri(OpenIDConnectOptions options)
internal static string CalculateFullRedirectUri(OpenIDConnectOptions options)
{
var uri = options.AuthDomain + "/" + Constants.EndPointOAuthAuthorize;
@ -39,8 +39,8 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Owin
{
uri = uri + ":" + options.AppPort.ToString();
}
return uri + options.CallbackPath;
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Newtonsoft.Json.Linq;
using System;
@ -29,18 +30,13 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
public CloudFoundryClientTokenResolver(CloudFoundryOptions options)
{
if (options == null)
{
throw new ArgumentNullException("options null");
}
Options = options;
Options = options ?? throw new ArgumentNullException("options null");
}
public virtual async Task<string> GetAccessToken()
{
HttpRequestMessage requestMessage = GetTokenRequestMessage();
RemoteCertificateValidationCallback prevValidator = ServicePointManager.ServerCertificateValidationCallback;
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
@ -74,8 +70,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
}
}
internal protected virtual HttpRequestMessage GetTokenRequestMessage()
protected internal virtual HttpRequestMessage GetTokenRequestMessage()
{
var tokenRequestParameters = GetTokenRequestParameters();
@ -88,8 +83,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
return requestMessage;
}
internal protected virtual Dictionary<string, string> GetTokenRequestParameters()
protected internal virtual Dictionary<string, string> GetTokenRequestParameters()
{
return new Dictionary<string, string>()
{
@ -97,17 +91,25 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{ "client_secret", Options.ClientSecret },
{ "response_type", "token" },
{ "grant_type", "client_credentials" },
{ "scope", Options.RequiredScopes == null ? "openid" :
string.Join(" ",Options.RequiredScopes) },
{
"scope", Options.RequiredScopes == null ? "openid" :
string.Join(" ", Options.RequiredScopes)
},
};
}
internal protected string GetEncoded(string user, string password)
protected internal string GetEncoded(string user, string password)
{
if (user == null)
{
user = string.Empty;
}
if (password == null)
{
password = string.Empty;
}
return Convert.ToBase64String(Encoding.ASCII.GetBytes(user + ":" + password));
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
@ -17,15 +18,12 @@ using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
public class CloudFoundryJwt
{
public static void OnTokenValidatedAddClaims(ClaimsIdentity identity,JwtSecurityToken jwt)
public static void OnTokenValidatedAddClaims(ClaimsIdentity identity, JwtSecurityToken jwt)
{
var identifier = GetId(identity);
if (!string.IsNullOrEmpty(identifier))
{
@ -58,13 +56,9 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
else
{
identity.AddClaim(new Claim(ClaimTypes.Name, GetClientId(identity), ClaimValueTypes.String, jwt.Issuer));
}
}
private static string GetGivenName(IIdentity identity)
{
return GetClaim(identity, "given_name");
@ -79,10 +73,12 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
return GetClaim(identity, "email");
}
private static string GetName(IIdentity identity)
{
return GetClaim(identity, "user_name");
}
private static string GetId(IIdentity identity)
{
return GetClaim(identity, "user_id");
@ -93,8 +89,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
return GetClaim(identity, "client_id");
}
private static string GetClaim(IIdentity identity, string claim)
{
var claims = identity as ClaimsIdentity;
@ -102,11 +96,13 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
return null;
}
var idClaim = claims.FindFirst(claim);
if (idClaim == null)
{
return null;
}
return idClaim.Value;
}
@ -117,11 +113,13 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
return null;
}
var idClaims = claims.FindAll(claim);
if (idClaims == null)
{
return null;
}
return idClaims.ToArray<Claim>();
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,60 +11,75 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.IdentityModel.Tokens;
namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
public class CloudFoundryOptions //: OAuthOptions
public class CloudFoundryOptions
{
public const string AUTHENTICATION_SCHEME = "CloudFoundry";
public const string OAUTH_AUTHENTICATION_SCHEME = "CloudFoundry.OAuth";
internal const string Default_AuthorizationUri = "/oauth/authorize";
internal const string Default_AccessTokenUri = "/oauth/token";
internal const string Default_UserInfoUri = "/userinfo";
internal const string Default_CheckTokenUri = "/check_token";
internal const string Default_JwtTokenKey = "/token_key";
public const string AUTHENTICATION_SCHEME = "CloudFoundry";
public const string OAUTH_AUTHENTICATION_SCHEME = "CloudFoundry.OAuth";
public string TokenInfoUrl { get; set; }
public bool ValidateCertificates { get; set; }
public bool ValidateAudience { get; set; }
public bool ValidateIssuer { get; set; }
public bool ValidateLifetime { get; set; }
public string OAuthServiceUrl { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string AuthorizationEndpoint { get; set; }
public string AccessTokenEndpoint { get; set; }
public string UserInformationEndpoint { get; set; }
public string TokenInfoEndpoint { get; set; }
public string JwtKeyEndpoint { get; set; }
public string[] RequiredScopes { get; set; }
public string[] AdditionalAudiences { get; set; }
public TokenValidationParameters TokenValidationParameters { get; set; }
internal CloudFoundryTokenKeyResolver TokenKeyResolver { get; set; }
internal CloudFoundryTokenValidator TokenValidator { get; set; }
public CloudFoundryOptions() :this ( System.Environment.GetEnvironmentVariable("sso_auth_domain") )
public CloudFoundryOptions()
: this(System.Environment.GetEnvironmentVariable("sso_auth_domain"))
{
ClientId = System.Environment.GetEnvironmentVariable("sso_client_id");
ClientSecret = System.Environment.GetEnvironmentVariable("sso_client_secret");
ClientId = System.Environment.GetEnvironmentVariable("sso_client_id");
ClientSecret = System.Environment.GetEnvironmentVariable("sso_client_secret");
}
public CloudFoundryOptions(string authDomain, string clientId, string clientSecret) : this(authDomain)
public CloudFoundryOptions(string authDomain, string clientId, string clientSecret)
: this(authDomain)
{
ClientId = clientId;
ClientSecret = clientSecret;
}
public CloudFoundryOptions(string authUrl)
{
//CallbackPath = new PathString("/signin-cloudfoundry");
// CallbackPath = new PathString("/signin-cloudfoundry");
OAuthServiceUrl = authUrl;
AuthorizationEndpoint = authUrl + Default_AuthorizationUri;
AccessTokenEndpoint = authUrl + Default_AccessTokenUri;
@ -79,7 +96,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
TokenValidationParameters = GetTokenValidationParameters(this);
}
internal static TokenValidationParameters GetTokenValidationParameters(CloudFoundryOptions options)
{
if (options.TokenValidationParameters != null)
@ -88,7 +104,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
}
var parameters = new TokenValidationParameters();
options.TokenKeyResolver = options.TokenKeyResolver ?? new CloudFoundryTokenKeyResolver(options);
options.TokenKeyResolver = options.TokenKeyResolver ?? new CloudFoundryTokenKeyResolver(options);
options.TokenValidator = options.TokenValidator ?? new CloudFoundryTokenValidator(options);
options.TokenValidationParameters = parameters;
@ -96,14 +112,11 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
parameters.ValidateIssuer = options.ValidateIssuer;
parameters.ValidateLifetime = options.ValidateLifetime;
parameters.IssuerSigningKeyResolver = options.TokenKeyResolver.ResolveSigningKey;
parameters.IssuerValidator = options.TokenValidator.ValidateIssuer;
parameters.AudienceValidator = options.TokenValidator.ValidateAudience;
return parameters;
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.IdentityModel.Tokens;
using System;
@ -31,18 +32,13 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
public CloudFoundryTokenKeyResolver(CloudFoundryOptions options)
{
if (options == null)
{
throw new ArgumentNullException("options null");
}
Options = options;
Options = options ?? throw new ArgumentNullException("options null");
Resolved = new Dictionary<string, SecurityKey>();
}
public virtual IEnumerable<SecurityKey> ResolveSigningKey(string token, SecurityToken securityToken, string kid, TokenValidationParameters validationParameters)
{
SecurityKey resolved = null;
if (Resolved.TryGetValue(kid, out resolved))
if (Resolved.TryGetValue(kid, out SecurityKey resolved))
{
return new List<SecurityKey> { resolved };
}
@ -56,37 +52,27 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
Resolved[key.Kid] = key;
}
}
if (Resolved.TryGetValue(kid, out resolved))
{
return new List<SecurityKey> { resolved };
}
return null;
}
public JsonWebKey FixupKey(JsonWebKey key)
{
byte[] existing = Base64UrlEncoder.DecodeBytes(key.N);
TrimKey(key, existing);
return key;
}
private void TrimKey(JsonWebKey key, byte[] existing)
{
byte[] signRemoved = new byte[existing.Length -1];
Buffer.BlockCopy(existing, 1, signRemoved, 0, existing.Length - 1);
string withSignRemoved = Base64UrlEncoder.Encode(signRemoved);
key.N = withSignRemoved;
}
public virtual async Task<JsonWebKeySet> FetchKeySet()
{
var requestMessage = new HttpRequestMessage(HttpMethod.Get, Options.JwtKeyEndpoint);
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
RemoteCertificateValidationCallback prevValidator = null;
using (var handler = new HttpClientHandler())
@ -101,9 +87,9 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
response = await client.SendAsync(requestMessage);
}
catch (Exception ex)
catch (Exception ex)
{
throw new Exception("Error getting keys to validate token:" + ex.Message );
throw new Exception("Error getting keys to validate token:" + ex.Message);
}
finally
{
@ -117,16 +103,20 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
}
}
return null;
}
public virtual JsonWebKeySet GetJsonWebKeySet(string json)
{
return new JsonWebKeySetEx(json);
return new JsonWebKeySetEx(json);
}
private void TrimKey(JsonWebKey key, byte[] existing)
{
byte[] signRemoved = new byte[existing.Length - 1];
Buffer.BlockCopy(existing, 1, signRemoved, 0, existing.Length - 1);
string withSignRemoved = Base64UrlEncoder.Encode(signRemoved);
key.N = withSignRemoved;
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.IdentityModel.Tokens;
using System;
@ -25,19 +26,37 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
public class CloudFoundryTokenValidator
{
public CloudFoundryOptions Options { get; internal protected set; }
private JwtSecurityTokenHandler _handler = new JwtSecurityTokenHandler();
public CloudFoundryTokenValidator(CloudFoundryOptions options)
{
if (options == null)
{
throw new ArgumentNullException("options null");
}
Options = options;
Options = options ?? throw new ArgumentNullException("options null");
}
public static void ThrowJwtException(string exeptionMessage, string message)
{
Console.Out.WriteLine("error: " + exeptionMessage + " " + message);
if (WebOperationContext.Current != null)
{
var headers = WebOperationContext.Current.OutgoingResponse.Headers;
// https://tools.ietf.org/html/rfc6750 - "WWW-Authenticate", "Bearer error=\"insufficient_scope\"");
if (string.IsNullOrEmpty(message))
{
message = "invalid_token";
}
if (string.IsNullOrEmpty(exeptionMessage))
{
exeptionMessage = message;
}
headers.Add(HttpResponseHeader.WwwAuthenticate, string.Format("Bearer realm=\"default\",error=\"{0}\",error_description=\"{1}\"", message, Regex.Replace(exeptionMessage, @"\s+", " ")));
}
throw new WebFaultException<string>(exeptionMessage ?? message, HttpStatusCode.Unauthorized);
}
public virtual string ValidateIssuer(string issuer, SecurityToken securityToken, TokenValidationParameters validationParameters)
@ -46,6 +65,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
return issuer;
}
return null;
}
@ -62,42 +82,21 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
bool found = Options.AdditionalAudiences.Any(x => x.Equals(audience));
if (found)
{
return true;
}
}
}
return false;
}
/// <summary>
/// This method validate scopes provided in configuration,
/// to perform scope based Authorization
/// </summary>
/// <param name="validJwt"></param>
/// <returns></returns>
protected virtual bool ValidateScopes(JwtSecurityToken validJwt)
{
if (Options.RequiredScopes == null || Options.RequiredScopes.Count<string>() == 0)
return true; // nocheck
if (!validJwt.Claims.Any(x => x.Type.Equals("scope") || x.Type.Equals("authorities")))
return false;// no scopes at all
bool found = false;
foreach (Claim claim in validJwt.Claims)
{
if (claim.Type.Equals("scope") || claim.Type.Equals("authorities")
&& Options.RequiredScopes.Any(x => x.Equals(claim.Value)))
return true;
}
return found;
}
public virtual ClaimsPrincipal ValidateToken(string token)
public virtual ClaimsPrincipal ValidateToken(string token)
{
if (string.IsNullOrEmpty(token))
{
return null;
}
SecurityToken validatedToken = null;
ClaimsPrincipal principal = null;
@ -111,41 +110,54 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
catch (Exception ex)
{
Console.WriteLine("ValidateToken fails:" + ex.Message);
throwJwtException(ex.Message, "invalid_token");
ThrowJwtException(ex.Message, "invalid_token");
}
if (validJwt == null || principal == null)
{
ThrowJwtException(null, "invalid_token");
}
if (validJwt == null || principal == null )
throwJwtException(null, "invalid_token");
CloudFoundryJwt.OnTokenValidatedAddClaims((ClaimsIdentity)principal.Identity, validJwt);
bool validScopes = ValidateScopes(validJwt);
if ( !validScopes)
throwJwtException(null, "insufficient_scope");
if (!validScopes)
{
ThrowJwtException(null, "insufficient_scope");
}
return principal;
}
public static void throwJwtException (string exeptionMessage, string message)
/// <summary>
/// This method validate scopes provided in configuration,
/// to perform scope based Authorization
/// </summary>
/// <param name="validJwt">JSON Web token</param>
/// <returns>true if scopes validated</returns>
protected virtual bool ValidateScopes(JwtSecurityToken validJwt)
{
Console.Out.WriteLine("error: " + exeptionMessage + " " + message );
if (WebOperationContext.Current != null)
if (Options.RequiredScopes == null || Options.RequiredScopes.Count<string>() == 0)
{
var headers = WebOperationContext.Current.OutgoingResponse.Headers;
//https://tools.ietf.org/html/rfc6750 - "WWW-Authenticate", "Bearer error=\"insufficient_scope\"");
if (string.IsNullOrEmpty(message))
message = "invalid_token";
if (string.IsNullOrEmpty(exeptionMessage))
exeptionMessage = message;
headers.Add(HttpResponseHeader.WwwAuthenticate, string.Format("Bearer realm=\"default\",error=\"{0}\",error_description=\"{1}\"", message, Regex.Replace(exeptionMessage, @"\s+", " ")));
return true; // nocheck
}
throw new WebFaultException<string>(exeptionMessage == null ? message : exeptionMessage, HttpStatusCode.Unauthorized);
}
if (!validJwt.Claims.Any(x => x.Type.Equals("scope") || x.Type.Equals("authorities")))
{
return false; // no scopes at all
}
bool found = false;
foreach (Claim claim in validJwt.Claims)
{
if (claim.Type.Equals("scope") || (claim.Type.Equals("authorities")
&& Options.RequiredScopes.Any(x => x.Equals(claim.Value))))
{
return true;
}
}
return found;
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.IdentityModel.Tokens;
@ -17,14 +18,17 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
public class JsonWebKeySetEx : JsonWebKeySet
{
public JsonWebKeySetEx(string json) : base(json)
public JsonWebKeySetEx(string json)
: base(json)
{
// try to see if its just one key not the set
if (Keys == null || Keys.Count == 0)
if (Keys == null || Keys.Count == 0)
{
JsonWebKey key = new JsonWebKey(json);
if (key != null)
{
Keys.Add(key);
}
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,73 +11,76 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System.Security.Claims;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Web.Hosting;
using System.Web;
using System.Web.Hosting;
namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
public class JwtAuthorizationManager : ServiceAuthorizationManager
{
public CloudFoundryOptions Options { get; internal protected set; }
public JwtAuthorizationManager() : base()
{
public JwtAuthorizationManager()
: base()
{
}
protected override bool CheckAccessCore(OperationContext operationContext)
{
HttpRequestMessageProperty httpRequestMessage;
object httpRequestMessageObject;
if (operationContext.RequestContext.RequestMessage.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
if (operationContext.RequestContext.RequestMessage.Properties.TryGetValue(HttpRequestMessageProperty.Name, out object httpRequestMessageObject))
{
httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
if (string.IsNullOrEmpty(httpRequestMessage.Headers["Authorization"]))
CloudFoundryTokenValidator.throwJwtException("No Authorization header",null);
{
CloudFoundryTokenValidator.ThrowJwtException("No Authorization header", null);
}
// Get Bearer token
if (!httpRequestMessage.Headers["Authorization"].StartsWith("Bearer "))
CloudFoundryTokenValidator.throwJwtException("No Token", null);
{
CloudFoundryTokenValidator.ThrowJwtException("No Token", null);
}
string jwt = httpRequestMessage.Headers["Authorization"].Split(' ')[1];
if (string.IsNullOrEmpty(jwt))
CloudFoundryTokenValidator.throwJwtException("Wrong Token Format", null);
{
CloudFoundryTokenValidator.ThrowJwtException("Wrong Token Format", null);
}
// Get SSO Config
Options = (Options != null) ? Options : new CloudFoundryOptions();
if (Options.OAuthServiceUrl == null || Options.OAuthServiceUrl.Length == 0)
CloudFoundryTokenValidator.throwJwtException("SSO Configuration is missing", null);
Options = Options ?? new CloudFoundryOptions();
if (Options.OAuthServiceUrl == null || Options.OAuthServiceUrl.Length == 0)
{
CloudFoundryTokenValidator.ThrowJwtException("SSO Configuration is missing", null);
}
// Validate Token
ClaimsPrincipal claimsPrincipal = Options.TokenValidator.ValidateToken(jwt);
// Validate Token
ClaimsPrincipal claimsPrincipal = Options.TokenValidator.ValidateToken(jwt);
if (claimsPrincipal == null)
{
return false;
}
// Set the Principal created from token
SetPrincipal(operationContext, claimsPrincipal);
return true;
}
return false;
}
protected ClaimsPrincipal GetPrincipal(OperationContext operationContext)
{
var properties = operationContext.ServiceSecurityContext.AuthorizationContext.Properties;
return properties["Principal"] as ClaimsPrincipal;
}
private void SetPrincipal(OperationContext operationContext, ClaimsPrincipal principal)
{
@ -94,20 +99,12 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
HttpContext cur = HttpContext.Current;
if (cur != null)
{
cur.User = principal;
}
}
//Thread.CurrentPrincipal = principal;
// Thread.CurrentPrincipal = principal;
}
protected ClaimsPrincipal GetPrincipal(OperationContext operationContext)
{
var properties = operationContext.ServiceSecurityContext.AuthorizationContext.Properties;
return properties["Principal"] as ClaimsPrincipal;
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Configuration;
@ -20,18 +21,19 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
public class JwtHeaderEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
{
const string SSOPropertyName = "ssoName";
private const string SSOPropertyName = "ssoName";
[ConfigurationProperty(SSOPropertyName)]
public string SsoName
public string SsoName
{
get
{
return (string)base[SSOPropertyName];
return (string)this[SSOPropertyName];
}
set
{
base[SSOPropertyName] = value;
this[SSOPropertyName] = value;
}
}
@ -40,37 +42,28 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
get { return typeof(JwtHeaderEndpointBehavior); }
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new JwtHeaderMessageInspector());
}
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
protected override object CreateBehavior()
{
// Create the endpoint behavior that will insert the message
// inspector into the client runtime
return new JwtHeaderEndpointBehavior();
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new JwtHeaderMessageInspector());
}
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.ServiceModel.Channels;
@ -17,10 +18,9 @@ using System.ServiceModel.Dispatcher;
namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
public class JwtHeaderMessageInspector : IClientMessageInspector
{
private string _token;
private string _token;
public JwtHeaderMessageInspector()
{
@ -28,14 +28,13 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
if (_token == null)
{
_token = GetAccessToken();
}
HttpRequestMessageProperty httpRequestMessage;
object httpRequestMessageObject;
if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out object httpRequestMessageObject))
{
httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
}
@ -46,12 +45,13 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
}
if (httpRequestMessage != null)
{
httpRequestMessage.Headers.Add("Authorization", string.Format("Bearer {0}", _token));
}
return null;
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
HttpResponseMessageProperty httpResponse;
@ -59,34 +59,27 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
httpResponse = reply.Properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty;
}
//could get here refreshed token
// could get here refreshed token
}
private string GetAccessToken()
private string GetAccessToken()
{
CloudFoundryOptions options = new CloudFoundryOptions();
CloudFoundryOptions options = new CloudFoundryOptions();
CloudFoundryClientTokenResolver tokenResolver = new CloudFoundryClientTokenResolver(options);
CloudFoundryClientTokenResolver tokenResolver = new CloudFoundryClientTokenResolver(options);
try
{
string accessToken = tokenResolver.GetAccessToken().GetAwaiter().GetResult();
return accessToken;
}
catch (Exception ex)
{
Console.Out.WriteLine(ex.Message + ex.StackTrace);
throw new Exception("Cannont obtain the Access Token" + ex.Message);
}
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,19 +11,15 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Security;
using System.Security.Permissions;
using System;
using System.Threading;
using System.Security.Principal;
using System.Net;
using System.ServiceModel.Web;
using System.Threading;
namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
[Serializable]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class PrincipalPermissionEnvAttribute : CodeAccessSecurityAttribute
@ -38,27 +36,29 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
_authenticated = true;
}
public override IPermission CreatePermission()
{
if (Unrestricted)
{
return new PrincipalPermission(PermissionState.Unrestricted);
}
string matchACL = Environment.GetEnvironmentVariable(Role);
if (String.IsNullOrEmpty(matchACL))
CloudFoundryTokenValidator.throwJwtException("Configuration for not provided for Role: " + Role, "insufficient_scope");
if (string.IsNullOrEmpty(matchACL))
{
CloudFoundryTokenValidator.ThrowJwtException("Configuration for not provided for Role: " + Role, "insufficient_scope");
}
IPrincipal principal = Thread.CurrentPrincipal;
if (principal.IsInRole(matchACL))
{
return new PrincipalPermission(principal.Identity.Name, matchACL, _authenticated);
}
else
else
{
Console.Out.WriteLine("Access denied user is not in Role: " + Role);
CloudFoundryTokenValidator.throwJwtException("Access denied user is not in Role: " + Role, "insufficient_scope");
CloudFoundryTokenValidator.ThrowJwtException("Access denied user is not in Role: " + Role, "insufficient_scope");
return null;
}
}

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Security;
@ -24,11 +25,11 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
public string Scope { get; set; }
public ScopePermission(string name, string scope)
public ScopePermission(string name, string scope)
{
Scope = scope;
}
public bool IsUnrestricted()
{
return true;
@ -41,15 +42,16 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
if (principal == null || !principal.HasClaim("scope", this.Scope))
{
Console.Out.WriteLine("Access denied token is not in Scope: " + Scope);
CloudFoundryTokenValidator.throwJwtException("Access denied token does not have Scope: " + Scope,"insufficient_scope");
CloudFoundryTokenValidator.ThrowJwtException("Access denied token does not have Scope: " + Scope, "insufficient_scope");
}
}
public IPermission Intersect(IPermission target)
{
if (target == null)
{
return null;
}
return new ScopePermission(null, Scope);
}
@ -57,19 +59,23 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
public bool IsSubsetOf(IPermission target)
{
if (target == null)
{
return false;
}
return true;
}
public IPermission Union(IPermission target)
{
if (target == null)
{
return null;
}
return new ScopePermission(null, Scope);
}
public void FromXml(SecurityElement e)
{
throw new NotImplementedException();

Просмотреть файл

@ -1,4 +1,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -9,22 +11,18 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Security;
using System.Security.Permissions;
using System;
using System.Threading;
namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
[Serializable]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class ScopePermissionAttribute : CodeAccessSecurityAttribute
{
public string ConfigurationName { get; set; }
public string Scope { get; set; }
@ -34,7 +32,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
{
}
public override IPermission CreatePermission()
{
string scope = null;
@ -45,7 +42,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Wcf
scope = scope ?? Scope;
return new ScopePermission(Thread.CurrentPrincipal.Identity.Name, scope);
return new ScopePermission(Thread.CurrentPrincipal.Identity.Name, scope);
}
}
}

Просмотреть файл

@ -19,6 +19,9 @@
<ItemGroup>
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="$(JwtTokensVerions)" />
<PackageReference Include="System.Net.Http" Version="$(HttpClientVersion)" />
<PackageReference Include="StyleCop.Analyzers" Version="$(StyleCopVersion)">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
@ -28,6 +31,14 @@
<Reference Include="System.ServiceModel.Web" />
<Reference Include="System.Web" />
</ItemGroup>
<PropertyGroup>
<NoWarn>SA1101;SA1124;SA1201;SA1309;SA1310;SA1401;SA1600;SA1652;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json">
<Link>stylecop.json</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AdditionalFiles>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2015 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.DataProtection;
using StackExchange.Redis;
@ -22,7 +20,9 @@ namespace Steeltoe.Security.DataProtection.Redis
public class CloudFoundryRedisXmlRepository : RedisXmlRepository
{
private const string DataProtectionKeysName = "DataProtection-Keys";
public CloudFoundryRedisXmlRepository(IConnectionMultiplexer redis) : base( () => redis.GetDatabase(), DataProtectionKeysName)
public CloudFoundryRedisXmlRepository(IConnectionMultiplexer redis)
: base(() => redis.GetDatabase(), DataProtectionKeysName)
{
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2015 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
@ -25,16 +23,15 @@ using System;
namespace Steeltoe.Security.DataProtection
{
public static class RedisDataProtectionBuilderExtensions
{
public static IDataProtectionBuilder PersistKeysToRedis(this IDataProtectionBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.Services.TryAddSingleton<IXmlRepository, CloudFoundryRedisXmlRepository>();
builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>((p) =>

Просмотреть файл

@ -16,9 +16,20 @@
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
</PropertyGroup>
<ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="$(AspNetCoreDataProtectionRedisVersion)" />
<PackageReference Include="StyleCop.Analyzers" Version="$(StyleCopVersion)">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<NoWarn>SA1101;SA1124;SA1201;SA1309;SA1310;SA1401;SA1600;SA1652;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json">
<Link>stylecop.json</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AdditionalFiles>
</ItemGroup>
</Project>

27
stylecop.json Normal file
Просмотреть файл

@ -0,0 +1,27 @@
{
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"documentationRules": {
"copyrightText": "Copyright {copyrightYear} the original author or authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.",
"xmlHeader": false,
"variables": {
"copyrightYear": "2017"
},
"documentExposedElements": false,
"documentInternalElements": false,
"documentPrivateElements": false
},
"indentation": {
"useTabs": false,
"indentationSize": 4
},
"namingRules": {
},
"orderingRules": {
"usingDirectivesPlacement": "outsideNamespace",
"systemUsingDirectivesFirst": false
},
"readabilityRules": {
}
}
}

Просмотреть файл

@ -11,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
using System.Linq;

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,14 +11,12 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Xunit;
using System;
using System.Net;
using Xunit;
namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
@ -28,7 +25,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
[Fact]
public async void AddCloudFoundryOAuthAuthentication_AddsIntoPipeline()
{
var builder = new WebHostBuilder().UseStartup<TestServerStartup>().UseEnvironment("development");
using (var server = new TestServer(builder))
{
@ -36,14 +32,13 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
var result = await client.GetAsync("http://localhost/");
Assert.Equal(HttpStatusCode.Redirect, result.StatusCode);
var location = result.Headers.Location.ToString();
Assert.StartsWith( "http://default_oauthserviceurl/oauth/authorize", location);
Assert.StartsWith("http://default_oauthserviceurl/oauth/authorize", location);
}
}
[Fact]
public async void AddCloudFoundryJwtBearerAuthentication_AddsIntoPipeline()
{
var builder = new WebHostBuilder().UseStartup<TestServerJwtStartup>().UseEnvironment("development");
using (var server = new TestServer(builder))
{
@ -51,14 +46,11 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
var result = await client.GetAsync("http://localhost/");
Assert.Equal(HttpStatusCode.Unauthorized, result.StatusCode);
}
}
[Fact]
public async void AddCloudFoundryOAuthAuthentication_AddsIntoPipeline_UsesSSOInfo()
{
var app = @"
{
'cf_api': 'https://api.system.testcloud.com',
@ -105,7 +97,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Environment.SetEnvironmentVariable("VCAP_APPLICATION", app);
Environment.SetEnvironmentVariable("VCAP_SERVICES", services);
var builder = new WebHostBuilder().UseStartup<TestServerStartup>().UseEnvironment("development");
using (var server = new TestServer(builder))
{
@ -118,11 +109,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Environment.SetEnvironmentVariable("VCAP_APPLICATION", null);
Environment.SetEnvironmentVariable("VCAP_SERVICES", null);
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Newtonsoft.Json.Linq;
using Steeltoe.Common;
@ -30,10 +28,12 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
if (Platform.IsFullFramework)
{
Assert.Null(result1);
} else
}
else
{
Assert.NotNull(result1);
}
var result2 = CloudFoundryHelper.GetBackChannelHandler(true);
Assert.Null(result2);
}
@ -41,7 +41,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
[Fact]
public void GetExpTime_FindsTime()
{
var info =TestHelpers.GetValidTokenInfoRequestResponse();
var info = TestHelpers.GetValidTokenInfoRequestResponse();
var payload = JObject.Parse(info);
var dateTime = CloudFoundryHelper.GetExpTime(payload);
Assert.Equal(new DateTime(2016, 9, 2, 8, 04, 23, DateTimeKind.Utc), dateTime);
@ -55,6 +55,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
var dateTime = CloudFoundryHelper.GetIssueTime(payload);
Assert.Equal(new DateTime(2016, 9, 1, 20, 04, 23, DateTimeKind.Utc), dateTime);
}
[Fact]
public void GetScopes_FindsScopes()
{

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Steeltoe.CloudFoundry.Connector.Services;
@ -23,7 +21,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class CloudFoundryJwtBearerConfigurerTest
{
[Fact]
public void Configure_NoServiceInfo_ReturnsExpected()
{
@ -36,7 +33,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Assert.Null(jwtOpts.BackchannelHttpHandler);
Assert.NotNull(jwtOpts.TokenValidationParameters);
Assert.Equal(opts.SaveToken, jwtOpts.SaveToken);
}
[Fact]
@ -53,8 +49,8 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Assert.Null(jwtOpts.BackchannelHttpHandler);
Assert.NotNull(jwtOpts.TokenValidationParameters);
Assert.Equal(opts.SaveToken, jwtOpts.SaveToken);
}
[Fact]
public void GetTokenValidationParameters_ReturnsExpected()
{
@ -65,8 +61,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Assert.Equal(CloudFoundryTokenValidator.ValidateIssuer, parameters.IssuerValidator);
Assert.True(parameters.ValidateLifetime);
Assert.NotNull(parameters.IssuerSigningKeyResolver);
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Xunit;
@ -20,7 +18,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class CloudFoundryJwtBearerOptionsTest
{
[Fact]
public void DefaultConstructor_SetsupDefaultOptions()
{
@ -30,7 +27,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Assert.Equal(CloudFoundryDefaults.AuthenticationScheme, opts.ClaimsIssuer);
Assert.Equal(authURL + CloudFoundryDefaults.JwtTokenKey, opts.JwtKeyUrl);
Assert.True(opts.SaveToken);
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,65 +11,46 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.OAuth;
using Xunit;
using Microsoft.AspNetCore.Http;
using System.Text.Encodings.Web;
using System.Net.Http.Headers;
using Microsoft.AspNetCore.Http.Features;
using System.IO;
using Microsoft.Extensions.Logging;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Xunit;
namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class CloudFoundryOAuthHandlerTest
{
private MyTestCloudFoundryHandler GetTestHandler(CloudFoundryOAuthOptions options)
{
LoggerFactory loggerFactory = new LoggerFactory();
IOptionsMonitor<CloudFoundryOAuthOptions> monitor = new MonitorWrapper<CloudFoundryOAuthOptions>(options);
UrlEncoder encoder = UrlEncoder.Default;
TestClock clock = new TestClock();
MyTestCloudFoundryHandler testHandler = new MyTestCloudFoundryHandler(monitor, loggerFactory, encoder, clock);
testHandler.InitializeAsync(
new AuthenticationScheme(CloudFoundryDefaults.AuthenticationScheme, CloudFoundryDefaults.AuthenticationScheme, typeof(CloudFoundryOAuthHandler)),
new DefaultHttpContext()).Wait();
return testHandler;
}
[Fact]
public void GetTokenRequestParameters_ReturnsCorrectly()
{
var opts = new CloudFoundryOAuthOptions()
{
Backchannel = new HttpClient(new TestMessageHandler())
};
MyTestCloudFoundryHandler testHandler = GetTestHandler(opts);
var parameters = testHandler.GetTokenRequestParameters("code", "redirectUri");
Assert.NotNull(parameters);
Assert.Equal(parameters["client_id"], opts.ClientId);
Assert.Equal( "redirectUri", parameters["redirect_uri"]);
Assert.Equal("redirectUri", parameters["redirect_uri"]);
Assert.Equal(parameters["client_secret"], opts.ClientSecret);
Assert.Equal( "code", parameters["code"]);
Assert.Equal( "authorization_code",parameters["grant_type"]);
Assert.Equal("code", parameters["code"]);
Assert.Equal("authorization_code", parameters["grant_type"]);
}
[Fact]
@ -90,15 +70,16 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Assert.Equal(HttpMethod.Post, message.Method);
message.Headers.Accept.Contains(new MediaTypeWithQualityHeaderValue("application/json"));
}
[Fact]
public async void ExchangeCodeAsync_SendsTokenRequest_ReturnsValidTokenInfo()
{
TestMessageHandler handler = new TestMessageHandler();
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = new StringContent(TestHelpers.GetValidTokenRequestResponse());
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(TestHelpers.GetValidTokenRequestResponse())
};
handler.Response = response;
HttpClient client = new HttpClient(handler);
@ -115,7 +96,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Assert.Equal(HttpMethod.Post, handler.LastRequest.Method);
Assert.Equal(opts.TokenEndpoint.ToLowerInvariant(), handler.LastRequest.RequestUri.ToString().ToLowerInvariant());
Assert.NotNull(resp);
Assert.NotNull(resp.Response);
Assert.Equal("bearer", resp.TokenType);
@ -127,8 +107,10 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
public async void ExchangeCodeAsync_SendsTokenRequest_ReturnsErrorResponse()
{
TestMessageHandler handler = new TestMessageHandler();
var response = new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest);
response.Content = new StringContent("");
var response = new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest)
{
Content = new StringContent(string.Empty)
};
handler.Response = response;
HttpClient client = new HttpClient(handler);
@ -145,7 +127,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Assert.Equal(HttpMethod.Post, handler.LastRequest.Method);
Assert.Equal(opts.TokenEndpoint.ToLowerInvariant(), handler.LastRequest.RequestUri.ToString().ToLowerInvariant());
Assert.NotNull(resp);
Assert.NotNull(resp.Error);
Assert.Contains("OAuth token endpoint failure", resp.Error.Message);
@ -155,8 +136,10 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
public void BuildChallengeUrl_CreatesCorrectUrl()
{
TestMessageHandler handler = new TestMessageHandler();
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = new StringContent(TestHelpers.GetValidTokenRequestResponse());
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(TestHelpers.GetValidTokenRequestResponse())
};
handler.Response = response;
HttpClient client = new HttpClient(handler);
@ -191,9 +174,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
var parameters = testHandler.GetTokenInfoRequestParameters(tokens);
Assert.NotNull(parameters);
Assert.Equal(parameters["token"], tokens.AccessToken);
}
[Fact]
@ -216,15 +197,16 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Assert.Equal(HttpMethod.Post, message.Method);
message.Headers.Accept.Contains(new MediaTypeWithQualityHeaderValue("application/json"));
}
[Fact]
public async void CreateTicketAsync_SendsTokenInfoRequest_ReturnsValidTokenInfo()
{
TestMessageHandler handler = new TestMessageHandler();
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = new StringContent(TestHelpers.GetValidTokenInfoRequestResponse());
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(TestHelpers.GetValidTokenInfoRequestResponse())
};
handler.Response = response;
HttpClient client = new HttpClient(handler);
@ -234,7 +216,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
};
MyTestCloudFoundryHandler testHandler = GetTestHandler(opts);
var logger = new LoggerFactory().CreateLogger("CreateTicketAsync_SendsTokenRequest");
ClaimsIdentity identity = new ClaimsIdentity();
@ -253,107 +234,19 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
identity.HasClaim(ClaimTypes.NameIdentifier, "13bb6841-e4d6-4a9a-876c-9ef13aa61cc7");
identity.HasClaim(ClaimTypes.Name, "testssouser");
identity.HasClaim("openid", string.Empty);
}
}
class MyTestCloudFoundryHandler : CloudFoundryOAuthHandler
{
public MyTestCloudFoundryHandler(
IOptionsMonitor<CloudFoundryOAuthOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock) : base(options, logger, encoder, clock)
private MyTestCloudFoundryHandler GetTestHandler(CloudFoundryOAuthOptions options)
{
}
public async Task<AuthenticationTicket> TestCreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
{
return await base.CreateTicketAsync(identity, properties, tokens);
}
public async Task<OAuthTokenResponse> TestExchangeCodeAsync(string code, string redirectUri)
{
return await base.ExchangeCodeAsync(code, redirectUri);
}
public string TestBuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
{
return base.BuildChallengeUrl(properties, redirectUri);
LoggerFactory loggerFactory = new LoggerFactory();
IOptionsMonitor<CloudFoundryOAuthOptions> monitor = new MonitorWrapper<CloudFoundryOAuthOptions>(options);
UrlEncoder encoder = UrlEncoder.Default;
TestClock clock = new TestClock();
MyTestCloudFoundryHandler testHandler = new MyTestCloudFoundryHandler(monitor, loggerFactory, encoder, clock);
testHandler.InitializeAsync(
new AuthenticationScheme(CloudFoundryDefaults.AuthenticationScheme, CloudFoundryDefaults.AuthenticationScheme, typeof(CloudFoundryOAuthHandler)),
new DefaultHttpContext()).Wait();
return testHandler;
}
}
class TestResponse : IHttpResponseFeature
{
public Stream Body
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public bool HasStarted
{
get
{
throw new NotImplementedException();
}
}
public IHeaderDictionary Headers
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public string ReasonPhrase
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public int StatusCode
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public void OnCompleted(Func<object, Task> callback, object state)
{
}
public void OnStarting(Func<object, Task> callback, object state)
{
}
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
@ -24,7 +22,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class CloudFoundryOAuthOptionsTest
{
[Fact]
public void DefaultConstructor_SetsupDefaultOptions()
{
@ -32,19 +29,17 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
string authURL = "http://" + CloudFoundryDefaults.OAuthServiceUrl;
Assert.Equal(CloudFoundryDefaults.AuthenticationScheme, opts.ClaimsIssuer);
Assert.Equal(CloudFoundryDefaults.ClientId, opts.ClientId );
Assert.Equal(CloudFoundryDefaults.ClientSecret, opts.ClientSecret );
Assert.Equal(new PathString("/signin-cloudfoundry"), opts.CallbackPath );
Assert.Equal(authURL + CloudFoundryDefaults.AuthorizationUri, opts.AuthorizationEndpoint );
Assert.Equal(authURL + CloudFoundryDefaults.AccessTokenUri, opts.TokenEndpoint ) ;
Assert.Equal(authURL + CloudFoundryDefaults.UserInfoUri, opts.UserInformationEndpoint );
Assert.Equal(authURL + CloudFoundryDefaults.CheckTokenUri, opts.TokenInfoUrl) ;
Assert.Equal(CloudFoundryDefaults.ClientId, opts.ClientId);
Assert.Equal(CloudFoundryDefaults.ClientSecret, opts.ClientSecret);
Assert.Equal(new PathString("/signin-cloudfoundry"), opts.CallbackPath);
Assert.Equal(authURL + CloudFoundryDefaults.AuthorizationUri, opts.AuthorizationEndpoint);
Assert.Equal(authURL + CloudFoundryDefaults.AccessTokenUri, opts.TokenEndpoint);
Assert.Equal(authURL + CloudFoundryDefaults.UserInfoUri, opts.UserInformationEndpoint);
Assert.Equal(authURL + CloudFoundryDefaults.CheckTokenUri, opts.TokenInfoUrl);
Assert.True(opts.ValidateCertificates);
Assert.Equal(6, opts.ClaimActions.Count());
Assert.Equal(CookieAuthenticationDefaults.AuthenticationScheme, opts.SignInScheme);
Assert.True(opts.SaveTokens);
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Newtonsoft.Json.Linq;
using System.Security.Claims;

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.IdentityModel.Tokens;
using System;
@ -27,11 +25,10 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
[Fact]
public void Constructor_ThrowsIfOptionsNull()
{
// Act and Assert
var ex = Assert.Throws<ArgumentException>(() => new CloudFoundryTokenKeyResolver(null, null, false));
}
[Fact]
public void ResolveSigningKey_FindsExistingKey()
{
@ -55,8 +52,10 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
string token = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiI0YjM2NmY4MDdlMjU0MzlmYmRkOTEwZDc4ZjcwYzlhMSIsInN1YiI6ImZlNmExYmUyLWM5MTEtNDM3OC05Y2MxLTVhY2Y1NjA1Y2ZjMiIsInNjb3BlIjpbImNsb3VkX2NvbnRyb2xsZXIucmVhZCIsImNsb3VkX2NvbnRyb2xsZXJfc2VydmljZV9wZXJtaXNzaW9ucy5yZWFkIiwidGVzdGdyb3VwIiwib3BlbmlkIl0sImNsaWVudF9pZCI6Im15VGVzdEFwcCIsImNpZCI6Im15VGVzdEFwcCIsImF6cCI6Im15VGVzdEFwcCIsImdyYW50X3R5cGUiOiJhdXRob3JpemF0aW9uX2NvZGUiLCJ1c2VyX2lkIjoiZmU2YTFiZTItYzkxMS00Mzc4LTljYzEtNWFjZjU2MDVjZmMyIiwib3JpZ2luIjoidWFhIiwidXNlcl9uYW1lIjoiZGF2ZSIsImVtYWlsIjoiZGF2ZSIsImF1dGhfdGltZSI6MTQ3MzYxNTU0MSwicmV2X3NpZyI6IjEwZDM1NzEyIiwiaWF0IjoxNDczNjI0MjU1LCJleHAiOjE0NzM2Njc0NTUsImlzcyI6Imh0dHBzOi8vdWFhLnN5c3RlbS50ZXN0Y2xvdWQuY29tL29hdXRoL3Rva2VuIiwiemlkIjoidWFhIiwiYXVkIjpbImNsb3VkX2NvbnRyb2xsZXIiLCJteVRlc3RBcHAiLCJvcGVuaWQiLCJjbG91ZF9jb250cm9sbGVyX3NlcnZpY2VfcGVybWlzc2lvbnMiXX0.Hth_SXpMAyiTf--U75r40qODlSUr60U730IW28K2VidEltW3lN3_CE7HkSjolRGr-DYuWHRvy3i_EwBfj1WTkBaXL373UzPVvNBnat9Gi-vjz07LwmBohk3baG1mmlL8IoGbQwtsmfUPhmO5C6_M4s9wKmTf9XIZPVo_w7zPJadrXfHLfx6iQob7CYpTTix2VBWya29iL7kmD1J1UDT5YRg2J9XT30iFuL6BvPQTkuGnX3ivDuUOSdxM8Z451i0VJmc0LYFBCLJ-Tz6bJ2d0wrtfsbCfuNtxjmGJevcL2jKQbEoiliYj60qNtZdT-ijGUdZjE9caxQ2nOkDkowacpw";
string keyset = "{ 'keys':[{'kid':'legacy-token-key','alg':'SHA256withRSA','value':'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk+7xH35bYBppsn54cBW+\nFlrveTe+3L4xl7ix13XK8eBcCmNOyBhNzhks6toDiRjrgw5QW76cFirVRFIVQkiZ\nsUwDyGOax3q8NOJyBFXiplIUScrx8aI0jkY/Yd6ixAc5yBSBfXThy4EF9T0xCyt4\nxWLYNXMRwe88Y+i+MEoLNXWRbhjJm76LN7rsdIxALbS0vJNWUDALWjtE6FeYX6uU\nL9msAzlCQkdnSvwMmr8Ij2O3IVMxHDJXOZinFqt9zVfXwO11o7ZmiskZnRz1/V0f\nvbUQAadkcDEUt1gk9cbrAhiipg8VWDMsC7VUXuekJZjme5f8oWTwpsgP6cTUzwSS\n6wIDAQAB\n-----END PUBLIC KEY-----','kty':'RSA','use':'sig','n':'AJPu8R9+W2AaabJ+eHAVvhZa73k3vty+MZe4sdd1yvHgXApjTsgYTc4ZLOraA4kY64MOUFu+nBYq1URSFUJImbFMA8hjmsd6vDTicgRV4qZSFEnK8fGiNI5GP2HeosQHOcgUgX104cuBBfU9MQsreMVi2DVzEcHvPGPovjBKCzV1kW4YyZu+ize67HSMQC20tLyTVlAwC1o7ROhXmF+rlC/ZrAM5QkJHZ0r8DJq/CI9jtyFTMRwyVzmYpxarfc1X18DtdaO2ZorJGZ0c9f1dH721EAGnZHAxFLdYJPXG6wIYoqYPFVgzLAu1VF7npCWY5nuX/KFk8KbID+nE1M8Ekus=','e':'AQAB'}]}";
TestMessageHandler handler = new TestMessageHandler();
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = new StringContent(keyset);
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(keyset)
};
handler.Response = response;
CloudFoundryTokenKeyResolver.Resolved.Clear();
@ -74,8 +73,10 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
string token = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiI0YjM2NmY4MDdlMjU0MzlmYmRkOTEwZDc4ZjcwYzlhMSIsInN1YiI6ImZlNmExYmUyLWM5MTEtNDM3OC05Y2MxLTVhY2Y1NjA1Y2ZjMiIsInNjb3BlIjpbImNsb3VkX2NvbnRyb2xsZXIucmVhZCIsImNsb3VkX2NvbnRyb2xsZXJfc2VydmljZV9wZXJtaXNzaW9ucy5yZWFkIiwidGVzdGdyb3VwIiwib3BlbmlkIl0sImNsaWVudF9pZCI6Im15VGVzdEFwcCIsImNpZCI6Im15VGVzdEFwcCIsImF6cCI6Im15VGVzdEFwcCIsImdyYW50X3R5cGUiOiJhdXRob3JpemF0aW9uX2NvZGUiLCJ1c2VyX2lkIjoiZmU2YTFiZTItYzkxMS00Mzc4LTljYzEtNWFjZjU2MDVjZmMyIiwib3JpZ2luIjoidWFhIiwidXNlcl9uYW1lIjoiZGF2ZSIsImVtYWlsIjoiZGF2ZSIsImF1dGhfdGltZSI6MTQ3MzYxNTU0MSwicmV2X3NpZyI6IjEwZDM1NzEyIiwiaWF0IjoxNDczNjI0MjU1LCJleHAiOjE0NzM2Njc0NTUsImlzcyI6Imh0dHBzOi8vdWFhLnN5c3RlbS50ZXN0Y2xvdWQuY29tL29hdXRoL3Rva2VuIiwiemlkIjoidWFhIiwiYXVkIjpbImNsb3VkX2NvbnRyb2xsZXIiLCJteVRlc3RBcHAiLCJvcGVuaWQiLCJjbG91ZF9jb250cm9sbGVyX3NlcnZpY2VfcGVybWlzc2lvbnMiXX0.Hth_SXpMAyiTf--U75r40qODlSUr60U730IW28K2VidEltW3lN3_CE7HkSjolRGr-DYuWHRvy3i_EwBfj1WTkBaXL373UzPVvNBnat9Gi-vjz07LwmBohk3baG1mmlL8IoGbQwtsmfUPhmO5C6_M4s9wKmTf9XIZPVo_w7zPJadrXfHLfx6iQob7CYpTTix2VBWya29iL7kmD1J1UDT5YRg2J9XT30iFuL6BvPQTkuGnX3ivDuUOSdxM8Z451i0VJmc0LYFBCLJ-Tz6bJ2d0wrtfsbCfuNtxjmGJevcL2jKQbEoiliYj60qNtZdT-ijGUdZjE9caxQ2nOkDkowacpw";
string keyset = "{ 'keys':[{'kid':'foobar','alg':'SHA256withRSA','value':'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk+7xH35bYBppsn54cBW+\nFlrveTe+3L4xl7ix13XK8eBcCmNOyBhNzhks6toDiRjrgw5QW76cFirVRFIVQkiZ\nsUwDyGOax3q8NOJyBFXiplIUScrx8aI0jkY/Yd6ixAc5yBSBfXThy4EF9T0xCyt4\nxWLYNXMRwe88Y+i+MEoLNXWRbhjJm76LN7rsdIxALbS0vJNWUDALWjtE6FeYX6uU\nL9msAzlCQkdnSvwMmr8Ij2O3IVMxHDJXOZinFqt9zVfXwO11o7ZmiskZnRz1/V0f\nvbUQAadkcDEUt1gk9cbrAhiipg8VWDMsC7VUXuekJZjme5f8oWTwpsgP6cTUzwSS\n6wIDAQAB\n-----END PUBLIC KEY-----','kty':'RSA','use':'sig','n':'AJPu8R9+W2AaabJ+eHAVvhZa73k3vty+MZe4sdd1yvHgXApjTsgYTc4ZLOraA4kY64MOUFu+nBYq1URSFUJImbFMA8hjmsd6vDTicgRV4qZSFEnK8fGiNI5GP2HeosQHOcgUgX104cuBBfU9MQsreMVi2DVzEcHvPGPovjBKCzV1kW4YyZu+ize67HSMQC20tLyTVlAwC1o7ROhXmF+rlC/ZrAM5QkJHZ0r8DJq/CI9jtyFTMRwyVzmYpxarfc1X18DtdaO2ZorJGZ0c9f1dH721EAGnZHAxFLdYJPXG6wIYoqYPFVgzLAu1VF7npCWY5nuX/KFk8KbID+nE1M8Ekus=','e':'AQAB'}]}";
TestMessageHandler handler = new TestMessageHandler();
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = new StringContent(keyset);
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(keyset)
};
handler.Response = response;
CloudFoundryTokenKeyResolver.Resolved.Clear();
@ -92,8 +93,10 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
string keyset = "{ 'keys':[{'kid':'legacy-token-key','alg':'SHA256withRSA','value':'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk+7xH35bYBppsn54cBW+\nFlrveTe+3L4xl7ix13XK8eBcCmNOyBhNzhks6toDiRjrgw5QW76cFirVRFIVQkiZ\nsUwDyGOax3q8NOJyBFXiplIUScrx8aI0jkY/Yd6ixAc5yBSBfXThy4EF9T0xCyt4\nxWLYNXMRwe88Y+i+MEoLNXWRbhjJm76LN7rsdIxALbS0vJNWUDALWjtE6FeYX6uU\nL9msAzlCQkdnSvwMmr8Ij2O3IVMxHDJXOZinFqt9zVfXwO11o7ZmiskZnRz1/V0f\nvbUQAadkcDEUt1gk9cbrAhiipg8VWDMsC7VUXuekJZjme5f8oWTwpsgP6cTUzwSS\n6wIDAQAB\n-----END PUBLIC KEY-----','kty':'RSA','use':'sig','n':'AJPu8R9+W2AaabJ+eHAVvhZa73k3vty+MZe4sdd1yvHgXApjTsgYTc4ZLOraA4kY64MOUFu+nBYq1URSFUJImbFMA8hjmsd6vDTicgRV4qZSFEnK8fGiNI5GP2HeosQHOcgUgX104cuBBfU9MQsreMVi2DVzEcHvPGPovjBKCzV1kW4YyZu+ize67HSMQC20tLyTVlAwC1o7ROhXmF+rlC/ZrAM5QkJHZ0r8DJq/CI9jtyFTMRwyVzmYpxarfc1X18DtdaO2ZorJGZ0c9f1dH721EAGnZHAxFLdYJPXG6wIYoqYPFVgzLAu1VF7npCWY5nuX/KFk8KbID+nE1M8Ekus=','e':'AQAB'}]}";
TestMessageHandler handler = new TestMessageHandler();
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = new StringContent(keyset);
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(keyset)
};
handler.Response = response;
CloudFoundryTokenKeyResolver.Resolved.Clear();
@ -127,6 +130,4 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
Assert.NotNull(handler.LastRequest);
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Xunit;
@ -20,14 +18,11 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class CloudFoundryTokenValidatorTest
{
[Fact]
public void ValidateIssuer_ValidatesCorrectly()
{
Assert.NotNull(CloudFoundryTokenValidator.ValidateIssuer("https://uaa.system.testcloud.com/", null, null));
Assert.Null(CloudFoundryTokenValidator.ValidateIssuer("https://foobar.system.testcloud.com/", null, null));
}
}
}

Просмотреть файл

@ -0,0 +1,47 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.Extensions.Options;
using System;
namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class MonitorWrapper<T> : IOptionsMonitor<T>
{
private T _options;
public MonitorWrapper(T options)
{
_options = options;
}
public T CurrentValue
{
get
{
return _options;
}
}
public T Get(string name)
{
return _options;
}
public IDisposable OnChange(Action<T, string> listener)
{
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class MyTestCloudFoundryHandler : CloudFoundryOAuthHandler
{
public MyTestCloudFoundryHandler(
IOptionsMonitor<CloudFoundryOAuthOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
public async Task<AuthenticationTicket> TestCreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
{
return await CreateTicketAsync(identity, properties, tokens);
}
public async Task<OAuthTokenResponse> TestExchangeCodeAsync(string code, string redirectUri)
{
return await this.ExchangeCodeAsync(code, redirectUri);
}
public string TestBuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
{
return BuildChallengeUrl(properties, redirectUri);
}
}
}

Просмотреть файл

@ -4,9 +4,7 @@
<PropertyGroup>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<!-- Next two lines needed due to https://github.com/aspnet/Hosting/issues/926 -->
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">2.0.3</RuntimeFrameworkVersion>
</PropertyGroup>
<ItemGroup>
@ -28,7 +26,19 @@
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="$(AspNetCoreTestVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(AspNetCoreTestVersion)" />
<PackageReference Include="StyleCop.Analyzers" Version="$(StyleCopVersion)">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<NoWarn>SA1101;SA1124;SA1201;SA1309;SA1310;SA1401;SA1600;SA1652;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json">
<Link>stylecop.json</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AdditionalFiles>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,34 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.AspNetCore.Authentication;
using System;
namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class TestClock : ISystemClock
{
public TestClock()
{
UtcNow = new DateTimeOffset(2013, 6, 11, 12, 34, 56, 789, TimeSpan.Zero);
}
public DateTimeOffset UtcNow { get; set; }
public void Add(TimeSpan timeSpan)
{
UtcNow = UtcNow + timeSpan;
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;
@ -31,8 +29,8 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
var tempFile = Path.GetTempFileName();
File.WriteAllText(tempFile, contents);
return tempFile;
}
public static Stream StringToStream(string str)
{
var memStream = new MemoryStream();
@ -62,56 +60,4 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
return @"{'user_id':'13bb6841-e4d6-4a9a-876c-9ef13aa61cc7','user_name':'testssouser','email':'testssouser@testcloud.com','client_id':'44f854fd-49fe-4102-b0d1-a526dbff93d9','exp':1472803463,'scope':['openid'],'jti':'cc956120c52a431fbbb8945ac42872fd','aud':['44f854fd-49fe-4102-b0d1-a526dbff93d9','openid'],'sub':'13bb6841-e4d6-4a9a-876c-9ef13aa61cc7','iss':'https://testsso.uaa.system.testcloud.com/oauth/token','iat':1472760263,'cid':'44f854fd-49fe-4102-b0d1-a526dbff93d9','grant_type':'authorization_code','azp':'44f854fd-49fe-4102-b0d1-a526dbff93d9','auth_time':1472760254,'zid':'ef304ed0-3a5a-442e-9ad8-e4ca3ad5120e','rev_sig':'51135842','origin':'uaa','revocable':false}";
}
}
class TestMessageHandler : HttpMessageHandler
{
public HttpRequestMessage LastRequest { get; set; }
public HttpResponseMessage Response { get; set; } = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
LastRequest = request;
return Task.FromResult<HttpResponseMessage>(Response);
}
}
class TestClock : ISystemClock
{
public TestClock()
{
UtcNow = new DateTimeOffset(2013, 6, 11, 12, 34, 56, 789, TimeSpan.Zero);
}
public DateTimeOffset UtcNow { get; set; }
public void Add(TimeSpan timeSpan)
{
UtcNow = UtcNow + timeSpan;
}
}
class MonitorWrapper<T> : IOptionsMonitor<T>
{
private T _options;
public MonitorWrapper(T options)
{
_options = options;
}
public T CurrentValue
{
get
{
return _options;
}
}
public T Get(string name)
{
return _options;
}
public IDisposable OnChange(Action<T, string> listener)
{
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class TestMessageHandler : HttpMessageHandler
{
public HttpRequestMessage LastRequest { get; set; }
public HttpResponseMessage Response { get; set; } = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
LastRequest = request;
return Task.FromResult<HttpResponseMessage>(Response);
}
}
}

Просмотреть файл

@ -0,0 +1,93 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using System;
using System.IO;
using System.Threading.Tasks;
namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class TestResponse : IHttpResponseFeature
{
public Stream Body
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public bool HasStarted
{
get
{
throw new NotImplementedException();
}
}
public IHeaderDictionary Headers
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public string ReasonPhrase
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public int StatusCode
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public void OnCompleted(Func<object, Task> callback, object state)
{
}
public void OnStarting(Func<object, Task> callback, object state)
{
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
@ -25,12 +23,10 @@ using Microsoft.Extensions.Logging;
using Steeltoe.Extensions.Configuration.CloudFoundry;
using System;
namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class TestServerJwtStartup
{
public static CloudFoundryJwtBearerOptions CloudFoundryOptions { get; set; }
public IConfigurationRoot Configuration { get; }
@ -52,8 +48,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddCloudFoundryJwtBearer(Configuration);
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
@ -83,12 +77,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
await context.ChallengeAsync();
return;
});
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2017 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
@ -29,7 +27,6 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
public class TestServerStartup
{
public IConfigurationRoot Configuration { get; }
public TestServerStartup(IHostingEnvironment env)
@ -39,7 +36,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddCloudFoundry()
.AddEnvironmentVariables();
Configuration = builder.Build();
}
@ -50,16 +47,12 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CloudFoundryDefaults.AuthenticationScheme;
})
.AddCookie((options) =>
{
options.AccessDeniedPath = new PathString("/Home/AccessDenied");
})
.AddCloudFoundryOAuth(Configuration);
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
@ -89,11 +82,7 @@ namespace Steeltoe.Security.Authentication.CloudFoundry.Test
{
await context.ChallengeAsync();
return;
});
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
//
// Copyright 2015 the original author or authors.
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,11 +11,9 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.AspNetCore.DataProtection;
using System;
using System.Linq;
using Xunit;
namespace Steeltoe.Security.DataProtection.Redis.Test

Просмотреть файл

@ -4,6 +4,7 @@
<PropertyGroup>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">2.0.3</RuntimeFrameworkVersion>
</PropertyGroup>
<ItemGroup>
@ -22,7 +23,18 @@
<PackageReference Include="xunit" Version="$(XunitVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitStudioVersion)" />
<DotNetCliToolReference Include="dotnet-xunit" Version="$(XunitVersion)" />
<PackageReference Include="StyleCop.Analyzers" Version="$(StyleCopVersion)">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<NoWarn>SA1101;SA1124;SA1201;SA1309;SA1310;SA1401;SA1600;SA1652;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json">
<Link>stylecop.json</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AdditionalFiles>
</ItemGroup>
</Project>