#10 Remove the oboslete Google OpenId auth components.

This commit is contained in:
Chris R 2017-02-10 11:35:01 -08:00
Родитель 43a9bb509c
Коммит 6ee9653219
15 изменённых файлов: 3 добавлений и 1117 удалений

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

@ -1,56 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// OpenID is obsolete
#pragma warning disable 618
using System;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Google;
namespace Owin
{
/// <summary>
/// Extension methods for using <see cref="GoogleAuthenticationMiddleware"/>
/// Extension methods for using <see cref="GoogleOAuth2AuthenticationMiddleware"/>
/// </summary>
public static class GoogleAuthenticationExtensions
{
/// <summary>
/// Authenticate users using Google OpenId
/// </summary>
/// <param name="app">The <see cref="IAppBuilder"/> passed to the configuration method</param>
/// <param name="options">Middleware configuration options</param>
/// <returns>The updated <see cref="IAppBuilder"/></returns>
[Obsolete("Google is discontinuing support for the OpenId. Use OAuth2 instead.", error: false)]
public static IAppBuilder UseGoogleAuthentication(this IAppBuilder app, GoogleAuthenticationOptions options)
{
if (app == null)
{
throw new ArgumentNullException("app");
}
if (options == null)
{
throw new ArgumentNullException("options");
}
app.Use(typeof(GoogleAuthenticationMiddleware), app, options);
return app;
}
/// <summary>
/// Authenticate users using Google OpenId
/// </summary>
/// <param name="app">The <see cref="IAppBuilder"/> passed to the configuration method</param>
/// <returns>The updated <see cref="IAppBuilder"/></returns>
[Obsolete("Google is discontinuing support for the OpenId. Use OAuth2 instead.", error: false)]
public static IAppBuilder UseGoogleAuthentication(
this IAppBuilder app)
{
return UseGoogleAuthentication(
app,
new GoogleAuthenticationOptions());
}
/// <summary>
/// Authenticate users using Google OAuth 2.0
/// </summary>
@ -97,5 +57,4 @@ namespace Owin
});
}
}
}
#pragma warning restore 618
}

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

@ -1,360 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// OpenID is obsolete
#pragma warning disable 618
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security.Google.Infrastructure;
using Microsoft.Owin.Security.Infrastructure;
namespace Microsoft.Owin.Security.Google
{
internal class GoogleAuthenticationHandler : AuthenticationHandler<GoogleAuthenticationOptions>
{
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
public GoogleAuthenticationHandler(HttpClient httpClient, ILogger logger)
{
_httpClient = httpClient;
_logger = logger;
}
public override async Task<bool> InvokeAsync()
{
if (Options.CallbackPath.HasValue && Options.CallbackPath == Request.Path)
{
return await InvokeReturnPathAsync();
}
return false;
}
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
{
AuthenticationProperties properties = null;
try
{
IReadableStringCollection query = Request.Query;
properties = UnpackStateParameter(query);
if (properties == null)
{
_logger.WriteWarning("Invalid return state");
return null;
}
// Anti-CSRF
if (!ValidateCorrelationId(properties, _logger))
{
return new AuthenticationTicket(null, properties);
}
Message message = await ParseRequestMessageAsync(query);
bool messageValidated = false;
Property mode;
if (!message.Properties.TryGetValue("mode.http://specs.openid.net/auth/2.0", out mode))
{
_logger.WriteWarning("Missing mode parameter");
return new AuthenticationTicket(null, properties);
}
if (string.Equals("cancel", mode.Value, StringComparison.Ordinal))
{
_logger.WriteWarning("User cancelled signin request");
return new AuthenticationTicket(null, properties);
}
if (string.Equals("id_res", mode.Value, StringComparison.Ordinal))
{
mode.Value = "check_authentication";
var requestBody = new FormUrlEncodedContent(message.ToFormValues());
HttpResponseMessage response = await _httpClient.PostAsync("https://www.google.com/accounts/o8/ud", requestBody, Request.CallCancelled);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
var verifyBody = new Dictionary<string, string[]>();
foreach (var line in responseBody.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries))
{
int delimiter = line.IndexOf(':');
if (delimiter != -1)
{
verifyBody.Add("openid." + line.Substring(0, delimiter), new[] { line.Substring(delimiter + 1) });
}
}
var verifyMessage = new Message(new ReadableStringCollection(verifyBody), strict: false);
Property isValid;
if (verifyMessage.Properties.TryGetValue("is_valid.http://specs.openid.net/auth/2.0", out isValid))
{
if (string.Equals("true", isValid.Value, StringComparison.Ordinal))
{
messageValidated = true;
}
else
{
messageValidated = false;
}
}
}
// http://openid.net/specs/openid-authentication-2_0.html#verify_return_to
// To verify that the "openid.return_to" URL matches the URL that is processing this assertion:
// * The URL scheme, authority, and path MUST be the same between the two URLs.
// * Any query parameters that are present in the "openid.return_to" URL MUST also
// be present with the same values in the URL of the HTTP request the RP received.
if (messageValidated)
{
// locate the required return_to parameter
string actualReturnTo;
if (!message.TryGetValue("return_to.http://specs.openid.net/auth/2.0", out actualReturnTo))
{
_logger.WriteWarning("openid.return_to parameter missing at return address");
messageValidated = false;
}
else
{
// create the expected return_to parameter based on the URL that is processing
// the assertion, plus exactly and only the the query string parameter (state)
// that this RP must have received
string expectedReturnTo = BuildReturnTo(GetStateParameter(query));
if (!string.Equals(actualReturnTo, expectedReturnTo, StringComparison.Ordinal))
{
_logger.WriteWarning("openid.return_to parameter not equal to expected value based on return address");
messageValidated = false;
}
}
}
if (messageValidated)
{
IDictionary<string, string> attributeExchangeProperties = new Dictionary<string, string>();
foreach (var typeProperty in message.Properties.Values)
{
if (typeProperty.Namespace == "http://openid.net/srv/ax/1.0" &&
typeProperty.Name.StartsWith("type."))
{
string qname = "value." + typeProperty.Name.Substring("type.".Length) + "http://openid.net/srv/ax/1.0";
Property valueProperty;
if (message.Properties.TryGetValue(qname, out valueProperty))
{
attributeExchangeProperties.Add(typeProperty.Value, valueProperty.Value);
}
}
}
var responseNamespaces = new object[]
{
new XAttribute(XNamespace.Xmlns + "openid", "http://specs.openid.net/auth/2.0"),
new XAttribute(XNamespace.Xmlns + "openid.ax", "http://openid.net/srv/ax/1.0")
};
IEnumerable<object> responseProperties = message.Properties
.Where(p => p.Value.Namespace != null)
.Select(p => (object)new XElement(XName.Get(p.Value.Name.Substring(0, p.Value.Name.Length - 1), p.Value.Namespace), p.Value.Value));
var responseMessage = new XElement("response", responseNamespaces.Concat(responseProperties).ToArray());
var identity = new ClaimsIdentity(Options.AuthenticationType);
XElement claimedId = responseMessage.Element(XName.Get("claimed_id", "http://specs.openid.net/auth/2.0"));
if (claimedId != null)
{
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, claimedId.Value, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType));
}
string firstValue;
if (attributeExchangeProperties.TryGetValue("http://axschema.org/namePerson/first", out firstValue))
{
identity.AddClaim(new Claim(ClaimTypes.GivenName, firstValue, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType));
}
string lastValue;
if (attributeExchangeProperties.TryGetValue("http://axschema.org/namePerson/last", out lastValue))
{
identity.AddClaim(new Claim(ClaimTypes.Surname, lastValue, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType));
}
string nameValue;
if (attributeExchangeProperties.TryGetValue("http://axschema.org/namePerson", out nameValue))
{
identity.AddClaim(new Claim(ClaimTypes.Name, nameValue, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType));
}
else if (!string.IsNullOrEmpty(firstValue) && !string.IsNullOrEmpty(lastValue))
{
identity.AddClaim(new Claim(ClaimTypes.Name, firstValue + " " + lastValue, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType));
}
else if (!string.IsNullOrEmpty(firstValue))
{
identity.AddClaim(new Claim(ClaimTypes.Name, firstValue, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType));
}
else if (!string.IsNullOrEmpty(lastValue))
{
identity.AddClaim(new Claim(ClaimTypes.Name, lastValue, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType));
}
string emailValue;
if (attributeExchangeProperties.TryGetValue("http://axschema.org/contact/email", out emailValue))
{
identity.AddClaim(new Claim(ClaimTypes.Email, emailValue, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType));
}
var context = new GoogleAuthenticatedContext(
Context,
identity,
properties,
responseMessage,
attributeExchangeProperties);
await Options.Provider.Authenticated(context);
return new AuthenticationTicket(context.Identity, context.Properties);
}
return new AuthenticationTicket(null, properties);
}
catch (Exception ex)
{
_logger.WriteError("Authentication failed", ex);
return new AuthenticationTicket(null, properties);
}
}
private static string GetStateParameter(IReadableStringCollection query)
{
IList<string> values = query.GetValues("state");
if (values != null && values.Count == 1)
{
return values[0];
}
return null;
}
private AuthenticationProperties UnpackStateParameter(IReadableStringCollection query)
{
string state = GetStateParameter(query);
if (state != null)
{
return Options.StateDataFormat.Unprotect(state);
}
return null;
}
private string BuildReturnTo(string state)
{
return Request.Scheme + "://" + Request.Host +
RequestPathBase + Options.CallbackPath +
"?state=" + Uri.EscapeDataString(state);
}
private async Task<Message> ParseRequestMessageAsync(IReadableStringCollection query)
{
if (Request.Method == "POST")
{
IFormCollection form = await Request.ReadFormAsync();
return new Message(form, strict: true);
}
return new Message(query, strict: true);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "MemoryStream.Dispose is idempotent")]
protected override Task ApplyResponseChallengeAsync()
{
if (Response.StatusCode != 401)
{
return Task.FromResult<object>(null);
}
AuthenticationResponseChallenge challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
if (challenge != null)
{
string requestPrefix = Request.Scheme + Uri.SchemeDelimiter + Request.Host;
var state = challenge.Properties;
if (String.IsNullOrEmpty(state.RedirectUri))
{
state.RedirectUri = requestPrefix + Request.PathBase + Request.Path + Request.QueryString;
}
// Anti-CSRF
GenerateCorrelationId(state);
string returnTo = BuildReturnTo(Options.StateDataFormat.Protect(state));
string authorizationEndpoint =
"https://www.google.com/accounts/o8/ud" +
"?openid.ns=" + Uri.EscapeDataString("http://specs.openid.net/auth/2.0") +
"&openid.ns.ax=" + Uri.EscapeDataString("http://openid.net/srv/ax/1.0") +
"&openid.mode=" + Uri.EscapeDataString("checkid_setup") +
"&openid.claimed_id=" + Uri.EscapeDataString("http://specs.openid.net/auth/2.0/identifier_select") +
"&openid.identity=" + Uri.EscapeDataString("http://specs.openid.net/auth/2.0/identifier_select") +
"&openid.return_to=" + Uri.EscapeDataString(returnTo) +
"&openid.realm=" + Uri.EscapeDataString(requestPrefix) +
"&openid.ax.mode=" + Uri.EscapeDataString("fetch_request") +
"&openid.ax.type.email=" + Uri.EscapeDataString("http://axschema.org/contact/email") +
"&openid.ax.type.name=" + Uri.EscapeDataString("http://axschema.org/namePerson") +
"&openid.ax.type.first=" + Uri.EscapeDataString("http://axschema.org/namePerson/first") +
"&openid.ax.type.last=" + Uri.EscapeDataString("http://axschema.org/namePerson/last") +
"&openid.ax.required=" + Uri.EscapeDataString("email,name,first,last");
var redirectContext = new GoogleApplyRedirectContext(
Context, Options,
state, authorizationEndpoint);
Options.Provider.ApplyRedirect(redirectContext);
}
return Task.FromResult<object>(null);
}
public async Task<bool> InvokeReturnPathAsync()
{
AuthenticationTicket model = await AuthenticateAsync();
if (model == null)
{
_logger.WriteWarning("Invalid return state, unable to redirect.");
Response.StatusCode = 500;
return true;
}
var context = new GoogleReturnEndpointContext(Context, model);
context.SignInAsAuthenticationType = Options.SignInAsAuthenticationType;
context.RedirectUri = model.Properties.RedirectUri;
model.Properties.RedirectUri = null;
await Options.Provider.ReturnEndpoint(context);
if (context.SignInAsAuthenticationType != null && context.Identity != null)
{
ClaimsIdentity signInIdentity = context.Identity;
if (!string.Equals(signInIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal))
{
signInIdentity = new ClaimsIdentity(signInIdentity.Claims, context.SignInAsAuthenticationType, signInIdentity.NameClaimType, signInIdentity.RoleClaimType);
}
Context.Authentication.SignIn(context.Properties, signInIdentity);
}
if (!context.IsRequestCompleted && context.RedirectUri != null)
{
if (context.Identity == null)
{
// add a redirect hint that sign-in failed in some way
context.RedirectUri = WebUtilities.AddQueryString(context.RedirectUri, "error", "access_denied");
}
Response.Redirect(context.RedirectUri);
context.RequestCompleted();
}
return context.IsRequestCompleted;
}
}
}
#pragma warning restore 618

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

@ -1,92 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// OpenID is obsolete
#pragma warning disable 618
using System;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security.DataHandler;
using Microsoft.Owin.Security.DataProtection;
using Microsoft.Owin.Security.Infrastructure;
using Owin;
namespace Microsoft.Owin.Security.Google
{
/// <summary>
/// OWIN middleware for authenticating users using Google OpenID
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Justification = "Middleware are not disposable.")]
public class GoogleAuthenticationMiddleware : AuthenticationMiddleware<GoogleAuthenticationOptions>
{
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
/// <summary>
/// Initializes a <see cref="GoogleAuthenticationMiddleware"/>
/// </summary>
/// <param name="next">The next middleware in the OWIN pipeline to invoke</param>
/// <param name="app">The OWIN application</param>
/// <param name="options">Configuration options for the middleware</param>
public GoogleAuthenticationMiddleware(
OwinMiddleware next,
IAppBuilder app,
GoogleAuthenticationOptions options)
: base(next, options)
{
_logger = app.CreateLogger<GoogleAuthenticationMiddleware>();
if (Options.Provider == null)
{
Options.Provider = new GoogleAuthenticationProvider();
}
if (Options.StateDataFormat == null)
{
IDataProtector dataProtecter = app.CreateDataProtector(
typeof(GoogleAuthenticationMiddleware).FullName,
Options.AuthenticationType, "v1");
Options.StateDataFormat = new PropertiesDataFormat(dataProtecter);
}
if (String.IsNullOrEmpty(Options.SignInAsAuthenticationType))
{
Options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType();
}
_httpClient = new HttpClient(ResolveHttpMessageHandler(Options));
_httpClient.Timeout = Options.BackchannelTimeout;
_httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
}
/// <summary>
/// Provides the <see cref="AuthenticationHandler"/> object for processing authentication-related requests.
/// </summary>
/// <returns>An <see cref="AuthenticationHandler"/> configured with the <see cref="GoogleAuthenticationOptions"/> supplied to the constructor.</returns>
protected override AuthenticationHandler<GoogleAuthenticationOptions> CreateHandler()
{
return new GoogleAuthenticationHandler(_httpClient, _logger);
}
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Managed by caller")]
private static HttpMessageHandler ResolveHttpMessageHandler(GoogleAuthenticationOptions options)
{
HttpMessageHandler handler = options.BackchannelHttpHandler ?? new WebRequestHandler();
// If they provided a validator, apply it or fail.
if (options.BackchannelCertificateValidator != null)
{
// Set the cert validate callback
var webRequestHandler = handler as WebRequestHandler;
if (webRequestHandler == null)
{
throw new InvalidOperationException(Resources.Exception_ValidatorHandlerMismatch);
}
webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate;
}
return handler;
}
}
}
#pragma warning restore 618

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

@ -1,87 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
namespace Microsoft.Owin.Security.Google
{
/// <summary>
/// Configuration options for <see cref="GoogleAuthenticationMiddleware"/>
/// </summary>
[Obsolete("Google is discontinuing support for the OpenId. Use OAuth2 instead.", error: false)]
public class GoogleAuthenticationOptions : AuthenticationOptions
{
/// <summary>
/// Initializes a new <see cref="GoogleAuthenticationOptions"/>
/// </summary>
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters",
MessageId = "Microsoft.Owin.Security.Google.GoogleAuthenticationOptions.set_Caption(System.String)", Justification = "Not localizable")]
public GoogleAuthenticationOptions()
: base(Constants.DefaultAuthenticationType)
{
Caption = Constants.DefaultAuthenticationType;
CallbackPath = new PathString("/signin-google");
AuthenticationMode = AuthenticationMode.Passive;
BackchannelTimeout = TimeSpan.FromSeconds(60);
}
/// <summary>
/// Gets or sets the a pinned certificate validator to use to validate the endpoints used
/// in back channel communications belong to Google.
/// </summary>
/// <value>
/// The pinned certificate validator.
/// </value>
/// <remarks>If this property is null then the default certificate checks are performed,
/// validating the subject name and if the signing chain is a trusted party.</remarks>
public ICertificateValidator BackchannelCertificateValidator { get; set; }
/// <summary>
/// Gets or sets timeout value in milliseconds for back channel communications with Google.
/// </summary>
/// <value>
/// The back channel timeout.
/// </value>
public TimeSpan BackchannelTimeout { get; set; }
/// <summary>
/// The HttpMessageHandler used to communicate with Google.
/// This cannot be set at the same time as BackchannelCertificateValidator unless the value
/// can be downcast to a WebRequestHandler.
/// </summary>
public HttpMessageHandler BackchannelHttpHandler { get; set; }
/// <summary>
/// Get or sets the text that the user can display on a sign in user interface.
/// </summary>
public string Caption
{
get { return Description.Caption; }
set { Description.Caption = value; }
}
/// <summary>
/// The request path within the application's base path where the user-agent will be returned.
/// The middleware will process this request when it arrives.
/// Default value is "/signin-google".
/// </summary>
public PathString CallbackPath { get; set; }
/// <summary>
/// Gets or sets the name of another authentication middleware which will be responsible for actually issuing a user <see cref="System.Security.Claims.ClaimsIdentity"/>.
/// </summary>
public string SignInAsAuthenticationType { get; set; }
/// <summary>
/// Gets or sets the <see cref="IGoogleAuthenticationProvider"/> used to handle authentication events.
/// </summary>
public IGoogleAuthenticationProvider Provider { get; set; }
/// <summary>
/// Gets or sets the type used to secure data handled by the middleware.
/// </summary>
public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; }
}
}

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

@ -1,152 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Owin.Security.Google.Infrastructure
{
internal class Message
{
public Message(IReadableStringCollection parameters, bool strict)
{
Namespaces = new Dictionary<string, Property>(StringComparer.Ordinal);
Properties = new Dictionary<string, Property>(parameters.Count(), StringComparer.Ordinal);
Add(parameters, strict);
}
public Dictionary<string, Property> Namespaces { get; private set; }
public Dictionary<string, Property> Properties { get; private set; }
/// <summary>
/// Adds the openid parameters from querystring or form body into Namespaces and Properties collections.
/// This normalizes the parameter name, by replacing the variable namespace alias with the
/// actual namespace in the collection's key, and will optionally skip any parameters that are
/// not signed if the strict argument is true.
/// </summary>
/// <param name="parameters">The keys and values of the incoming querystring or form body</param>
/// <param name="strict">True if keys that are not signed should be ignored</param>
private void Add(IReadableStringCollection parameters, bool strict)
{
IEnumerable<KeyValuePair<string, string[]>> addingParameters;
// strict is true if keys that are not signed should be strict
if (strict)
{
IList<string> signed = parameters.GetValues("openid.signed");
if (signed == null ||
signed.Count != 1)
{
// nothing is added if the signed parameter is not present
return;
}
// determine the set of keys that are signed, or which may be used without
// signing. ns, mode, signed, and sig each may be used without signing.
var strictKeys = new HashSet<string>(signed[0]
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(value => "openid." + value)
.Concat(new[] { "openid.ns", "openid.mode", "openid.signed", "openid.sig" }));
// the parameters to add are only the parameters what are in this set
addingParameters = parameters.Where(kv => strictKeys.Contains(kv.Key));
}
else
{
// when strict is false all of the incoming parameters are to be added
addingParameters = parameters;
}
// convert the incoming parameter strings into Property objects. the
// Key is the raw key name. The Name starts of being equal to Key with a
// trailing dot appended. The Value is the query or form value, with a comma delimiter
// inserted between multiply occuring values.
Property[] addingProperties = addingParameters.Select(kv => new Property
{
Key = kv.Key,
Name = kv.Key + ".",
Value = string.Join(",", kv.Value)
}).ToArray();
// first, recognize which parameters are namespace declarations
var namespacePrefixes = new Dictionary<string, Property>(StringComparer.Ordinal);
foreach (var item in addingProperties)
{
// namespaces appear as with "openid.ns" or "openid.ns.alias"
if (item.Name.StartsWith("openid.ns.", StringComparison.Ordinal))
{
// the value of the parameter is the uri of the namespace
item.Namespace = item.Value;
item.Name = "openid." + item.Name.Substring("openid.ns.".Length);
// the namespaces collection is keyed by the ns uri
Namespaces.Add(item.Namespace, item);
// and the prefixes collection is keyed by "openid.alias."
namespacePrefixes.Add(item.Name, item);
}
}
// second, recognize which parameters are property values
foreach (var item in addingProperties)
{
// anything with a namespace was already added to Namespaces
if (item.Namespace == null)
{
// look for the namespace match for this property.
Property match = null;
// try finding where openid.alias.arg2 matches openid.ns.alies namespace
if (item.Name.StartsWith("openid.", StringComparison.Ordinal))
{
int dotIndex = item.Name.IndexOf('.', "openid.".Length);
if (dotIndex != -1)
{
string namespacePrefix = item.Name.Substring(0, dotIndex + 1);
namespacePrefixes.TryGetValue(namespacePrefix, out match);
}
}
// then try finding where openid.arg1 should match openid.ns namespace
if (match == null)
{
namespacePrefixes.TryGetValue("openid.", out match);
}
// when a namespace is found
if (match != null)
{
// the property's namespace is defined, and the namespace's prefix is removed
item.Namespace = match.Namespace;
item.Name = item.Name.Substring(match.Name.Length);
}
// the resulting property key is keyed by the local name and namespace
// so "openid.arg1" becomes "arg1.namespace-uri-of-openid"
// and "openid.alias.arg2" becomes "arg2.namespace-uri-of-alias"
Properties.Add(item.Name + item.Namespace, item);
}
}
}
public bool TryGetValue(string key, out string value)
{
Property property;
if (Properties.TryGetValue(key, out property))
{
value = property.Value;
return true;
}
value = null;
return false;
}
public IEnumerable<KeyValuePair<string, string>> ToFormValues()
{
return Namespaces.Concat(Properties).Select(pair => new KeyValuePair<string, string>(pair.Value.Key, pair.Value.Value));
}
}
}

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

@ -1,13 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.Owin.Security.Google.Infrastructure
{
internal class Property
{
public string Key { get; set; }
public string Namespace { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
}

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

@ -56,25 +56,15 @@
<Link>Properties\CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Constants.cs" />
<Compile Include="GoogleAuthenticationHandler.cs" />
<Compile Include="GoogleAuthenticationExtensions.cs" />
<Compile Include="GoogleOAuth2AuthenticationMiddleware.cs" />
<Compile Include="GoogleAuthenticationMiddleware.cs" />
<Compile Include="GoogleAuthenticationOptions.cs" />
<Compile Include="GoogleOAuth2AuthenticationHandler.cs" />
<Compile Include="GoogleOAuth2AuthenticationOptions.cs" />
<Compile Include="Infrastructure\Message.cs" />
<Compile Include="Infrastructure\Property.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Provider\GoogleAuthenticatedContext.cs" />
<Compile Include="Provider\GoogleAuthenticationProvider.cs" />
<Compile Include="Provider\GoogleApplyRedirectContext.cs" />
<Compile Include="Provider\GoogleOAuth2ApplyRedirectContext.cs" />
<Compile Include="Provider\GoogleOAuth2AuthenticatedContext.cs" />
<Compile Include="Provider\GoogleOAuth2AuthenticationProvider.cs" />
<Compile Include="Provider\GoogleOAuth2ReturnEndpointContext.cs" />
<Compile Include="Provider\GoogleReturnEndpointContext.cs" />
<Compile Include="Provider\IGoogleAuthenticationProvider.cs" />
<Compile Include="Provider\IGoogleOAuth2AuthenticationProvider.cs" />
<Compile Include="Resources.Designer.cs">
<DependentUpon>Resources.resx</DependentUpon>

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

@ -9,7 +9,7 @@
<projectUrl>$projectUrl$</projectUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<title>$title$</title>
<description>Contains middlewares to support Google's OpenId and OAuth 2.0 authentication workflows.</description>
<description>Contains middlewares to support Google's OAuth 2.0 authentication workflow.</description>
<tags>$tags$</tags>
<frameworkAssemblies>
<frameworkAssembly assemblyName="System.Net.Http" />

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

@ -1,45 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// OpenID is obsolete
#pragma warning disable 618
using Microsoft.Owin.Security.Provider;
namespace Microsoft.Owin.Security.Google
{
/// <summary>
/// Context passed when a Challenge causes a redirect to authorize endpoint in the Google OpenID middleware
/// </summary>
public class GoogleApplyRedirectContext : BaseContext<GoogleAuthenticationOptions>
{
/// <summary>
/// Creates a new context object.
/// </summary>
/// <param name="context">The OWIN request context</param>
/// <param name="options">The Google OpenID middleware options</param>
/// <param name="properties">The authentication properties of the challenge</param>
/// <param name="redirectUri">The initial redirect URI</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "3#",
Justification = "Represents header value")]
public GoogleApplyRedirectContext(IOwinContext context, GoogleAuthenticationOptions options,
AuthenticationProperties properties, string redirectUri)
: base(context, options)
{
RedirectUri = redirectUri;
Properties = properties;
}
/// <summary>
/// Gets the URI used for the redirect operation.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "Represents header value")]
public string RedirectUri { get; private set; }
/// <summary>
/// Gets the authentication properties of the challenge
/// </summary>
public AuthenticationProperties Properties { get; private set; }
}
}
#pragma warning restore 618

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

@ -1,58 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Security.Claims;
using System.Xml.Linq;
using Microsoft.Owin.Security.Provider;
namespace Microsoft.Owin.Security.Google
{
/// <summary>
/// Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.
/// </summary>
public class GoogleAuthenticatedContext : BaseContext
{
/// <summary>
/// Initializes a <see cref="GoogleAuthenticatedContext"/>
/// </summary>
/// <param name="context">The OWIN environment</param>
/// <param name="identity">The <see cref="ClaimsIdentity"/> representing the user</param>
/// <param name="properties">A property bag for common authentication properties</param>
/// <param name="responseMessage"></param>
/// <param name="attributeExchangeProperties"></param>
public GoogleAuthenticatedContext(
IOwinContext context,
ClaimsIdentity identity,
AuthenticationProperties properties,
XElement responseMessage,
IDictionary<string, string> attributeExchangeProperties)
: base(context)
{
Identity = identity;
Properties = properties;
ResponseMessage = responseMessage;
AttributeExchangeProperties = attributeExchangeProperties;
}
/// <summary>
/// Gets or sets the <see cref="ClaimsIdentity"/> representing the user
/// </summary>
public ClaimsIdentity Identity { get; set; }
/// <summary>
/// Gets or sets a property bag for common authentication properties
/// </summary>
public AuthenticationProperties Properties { get; set; }
/// <summary>
/// Gets or sets parsed response message from openid query string
/// </summary>
public XElement ResponseMessage { get; set; }
/// <summary>
/// Gets the key-value dictinary of message properties
/// </summary>
public IDictionary<string, string> AttributeExchangeProperties { get; private set; }
}
}

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

@ -1,69 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
namespace Microsoft.Owin.Security.Google
{
/// <summary>
/// Default <see cref="IGoogleAuthenticationProvider"/> implementation.
/// </summary>
public class GoogleAuthenticationProvider : IGoogleAuthenticationProvider
{
/// <summary>
/// Initializes a <see cref="GoogleAuthenticationProvider"/>
/// </summary>
public GoogleAuthenticationProvider()
{
OnAuthenticated = context => Task.FromResult<object>(null);
OnReturnEndpoint = context => Task.FromResult<object>(null);
OnApplyRedirect = context =>
context.Response.Redirect(context.RedirectUri);
}
/// <summary>
/// Gets or sets the function that is invoked when the Authenticated method is invoked.
/// </summary>
public Func<GoogleAuthenticatedContext, Task> OnAuthenticated { get; set; }
/// <summary>
/// Gets or sets the function that is invoked when the ReturnEndpoint method is invoked.
/// </summary>
public Func<GoogleReturnEndpointContext, Task> OnReturnEndpoint { get; set; }
/// <summary>
/// Gets or sets the delegate that is invoked when the ApplyRedirect method is invoked.
/// </summary>
public Action<GoogleApplyRedirectContext> OnApplyRedirect { get; set; }
/// <summary>
/// Invoked whenever Google successfully authenticates a user
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
public virtual Task Authenticated(GoogleAuthenticatedContext context)
{
return OnAuthenticated(context);
}
/// <summary>
/// Invoked prior to the <see cref="System.Security.Claims.ClaimsIdentity"/> being saved in a local cookie and the browser being redirected to the originally requested URL.
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
public virtual Task ReturnEndpoint(GoogleReturnEndpointContext context)
{
return OnReturnEndpoint(context);
}
/// <summary>
/// Called when a Challenge causes a redirect to authorize endpoint in the Google OpenID middleware
/// </summary>
/// <param name="context">Contains redirect URI and <see cref="AuthenticationProperties"/> of the challenge </param>
public virtual void ApplyRedirect(GoogleApplyRedirectContext context)
{
OnApplyRedirect(context);
}
}
}

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

@ -1,25 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Owin.Security.Provider;
namespace Microsoft.Owin.Security.Google
{
/// <summary>
/// Provides context information to middleware providers.
/// </summary>
public class GoogleReturnEndpointContext : ReturnEndpointContext
{
/// <summary>
///
/// </summary>
/// <param name="context">OWIN environment</param>
/// <param name="ticket">The authentication ticket</param>
public GoogleReturnEndpointContext(
IOwinContext context,
AuthenticationTicket ticket)
: base(context, ticket)
{
}
}
}

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

@ -1,33 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
namespace Microsoft.Owin.Security.Google
{
/// <summary>
/// Specifies callback methods which the <see cref="GoogleAuthenticationMiddleware"></see> invokes to enable developer control over the authentication process. />
/// </summary>
public interface IGoogleAuthenticationProvider
{
/// <summary>
/// Invoked whenever Google succesfully authenticates a user
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
Task Authenticated(GoogleAuthenticatedContext context);
/// <summary>
/// Invoked prior to the <see cref="System.Security.Claims.ClaimsIdentity"/> being saved in a local cookie and the browser being redirected to the originally requested URL.
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
Task ReturnEndpoint(GoogleReturnEndpointContext context);
/// <summary>
/// Called when a Challenge causes a redirect to authorize endpoint in the Google OpenID middleware
/// </summary>
/// <param name="context">Contains redirect URI and <see cref="AuthenticationProperties"/> of the challenge </param>
void ApplyRedirect(GoogleApplyRedirectContext context);
}
}

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

@ -1,128 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// OpenID is obsolete
#pragma warning disable 618
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Google;
using Microsoft.Owin.Testing;
using Owin;
using Shouldly;
using Xunit;
namespace Microsoft.Owin.Security.Tests.Google
{
public class GoogleOpenIDMiddlewareTests
{
[Fact]
public async Task ChallengeWillTriggerApplyRedirectEvent()
{
var options = new GoogleAuthenticationOptions()
{
Provider = new GoogleAuthenticationProvider
{
OnApplyRedirect = context =>
{
context.Response.Redirect(context.RedirectUri + "&custom=test");
}
}
};
var server = CreateServer(
app => app.UseGoogleAuthentication(options),
context =>
{
context.Authentication.Challenge("Google");
return true;
});
var transaction = await SendAsync(server, "http://example.com/challenge");
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
var query = transaction.Response.Headers.Location.Query;
query.ShouldContain("custom=test");
}
[Fact]
public async Task ChallengeWillTriggerRedirection()
{
var server = CreateServer(
app => app.UseGoogleAuthentication(),
context =>
{
context.Authentication.Challenge("Google");
return true;
});
var transaction = await SendAsync(server, "http://example.com/challenge");
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
var location = transaction.Response.Headers.Location.AbsoluteUri;
location.ShouldContain("https://www.google.com/accounts/o8/ud");
location.ShouldContain("?openid.ns=");
location.ShouldContain("&openid.ns.ax=");
location.ShouldContain("&openid.mode=");
location.ShouldContain("&openid.claimed_id=");
location.ShouldContain("&openid.identity=");
location.ShouldContain("&openid.return_to=");
location.ShouldContain("&openid.realm=");
location.ShouldContain("&openid.ax.mode=");
}
private static TestServer CreateServer(Action<IAppBuilder> configure, Func<IOwinContext, bool> handler)
{
return TestServer.Create(app =>
{
app.Properties["host.AppName"] = "Microsoft.Owin.Security.Tests";
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "External"
});
app.SetDefaultSignInAsAuthenticationType("External");
if (configure != null)
{
configure(app);
}
app.Use(async (context, next) =>
{
if (handler == null || !handler(context))
{
await next();
}
});
});
}
private static async Task<Transaction> SendAsync(TestServer server, string uri, string cookieHeader = null)
{
var request = new HttpRequestMessage(HttpMethod.Get, uri);
if (!string.IsNullOrEmpty(cookieHeader))
{
request.Headers.Add("Cookie", cookieHeader);
}
var transaction = new Transaction
{
Request = request,
Response = await server.HttpClient.SendAsync(request),
};
if (transaction.Response.Headers.Contains("Set-Cookie"))
{
transaction.SetCookie = transaction.Response.Headers.GetValues("Set-Cookie").ToList();
}
transaction.ResponseText = await transaction.Response.Content.ReadAsStringAsync();
return transaction;
}
private class Transaction
{
public HttpRequestMessage Request { get; set; }
public HttpResponseMessage Response { get; set; }
public IList<string> SetCookie { get; set; }
public string ResponseText { get; set; }
}
}
}
#pragma warning restore 618

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

@ -75,7 +75,6 @@
<Compile Include="DataHandler\Base64UrlTextEncoderTests.cs" />
<Compile Include="Facebook\FacebookMiddlewareTests.cs" />
<Compile Include="Google\GoogleOAuth2MiddlewareTests.cs" />
<Compile Include="Google\GoogleOpenIDMiddlewareTests.cs" />
<Compile Include="MicrosoftAccount\MicrosoftAccountMiddlewareTests.cs" />
<Compile Include="OAuth\OAuth2AuthorizationCustomGrantTests.cs" />
<Compile Include="OAuth\OAuth2BearerTokenTests.cs" />