Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Web.Helpers.AntiXsrf;
using System.Web.Mvc;
using System.Web.WebPages.Resources;
namespace System.Web.Helpers
{
/// <summary>
/// Provides access to the anti-forgery system, which provides protection against
/// Cross-site Request Forgery (XSRF, also called CSRF) attacks.
/// </summary>
public static class AntiForgery
{
private static readonly AntiForgeryWorker _worker = new AntiForgeryWorker();
/// <summary>
/// Generates an anti-forgery token for this request. This token can
/// be validated by calling the Validate() method.
/// </summary>
/// <returns>An HTML string corresponding to an &lt;input type="hidden"&gt;
/// element. This element should be put inside a &lt;form&gt;.</returns>
/// <remarks>
/// This method has a side effect: it may set a response cookie.
/// </remarks>
public static HtmlString GetHtml()
{
if (HttpContext.Current == null)
{
throw new ArgumentException(WebPageResources.HttpContextUnavailable);
}
TagBuilder retVal = _worker.GetFormInputElement(new HttpContextWrapper(HttpContext.Current));
return retVal.ToHtmlString(TagRenderMode.SelfClosing);
}
/// <summary>
/// Generates an anti-forgery token pair (cookie and form token) for this request.
/// This method is similar to GetHtml(), but this method gives the caller control
/// over how to persist the returned values. To validate these tokens, call the
/// appropriate overload of Validate.
/// </summary>
/// <param name="oldCookieToken">The anti-forgery token - if any - that already existed
/// for this request. May be null. The anti-forgery system will try to reuse this cookie
/// value when generating a matching form token.</param>
/// <param name="newCookieToken">Will contain a new cookie value if the old cookie token
/// was null or invalid. If this value is non-null when the method completes, the caller
/// must persist this value in the form of a response cookie, and the existing cookie value
/// should be discarded. If this value is null when the method completes, the existing
/// cookie value was valid and needn't be modified.</param>
/// <param name="formToken">The value that should be stored in the &lt;form&gt;. The caller
/// should take care not to accidentally swap the cookie and form tokens.</param>
/// <remarks>
/// Unlike the GetHtml() method, this method has no side effect. The caller
/// is responsible for setting the response cookie and injecting the returned
/// form token as appropriate.
/// </remarks>
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Method is intended for advanced audiences.")]
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "Method is intended for advanced audiences.")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static void GetTokens(string oldCookieToken, out string newCookieToken, out string formToken)
{
if (HttpContext.Current == null)
{
throw new ArgumentException(WebPageResources.HttpContextUnavailable);
}
_worker.GetTokens(new HttpContextWrapper(HttpContext.Current), oldCookieToken, out newCookieToken, out formToken);
}
[SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "AdditionalDataProvider", Justification = "API name.")]
[SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "AntiForgeryConfig", Justification = "API name.")]
[SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GetHtml", Justification = "API name.")]
[SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "httpCookies", Justification = "API name.")]
[Obsolete("This method is deprecated. Use the GetHtml() method instead. To specify a custom domain for the generated cookie, use the <httpCookies> configuration element. To specify custom data to be embedded within the token, use the static AntiForgeryConfig.AdditionalDataProvider property.", error: true)]
[EditorBrowsable(EditorBrowsableState.Never)]
public static HtmlString GetHtml(HttpContextBase httpContext, string salt, string domain, string path)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
if (!String.IsNullOrEmpty(salt) || !String.IsNullOrEmpty(domain) || !String.IsNullOrEmpty(path))
{
throw new NotSupportedException("This method is deprecated. Use the GetHtml() method instead. To specify a custom domain for the generated cookie, use the <httpCookies> configuration element. To specify custom data to be embedded within the token, use the static AntiForgeryConfig.AdditionalDataProvider property.");
}
TagBuilder retVal = _worker.GetFormInputElement(httpContext);
return retVal.ToHtmlString(TagRenderMode.SelfClosing);
}
/// <summary>
/// Validates an anti-forgery token that was supplied for this request.
/// The anti-forgery token may be generated by calling GetHtml().
/// </summary>
/// <remarks>
/// Throws an HttpAntiForgeryException if validation fails.
/// </remarks>
public static void Validate()
{
if (HttpContext.Current == null)
{
throw new ArgumentException(WebPageResources.HttpContextUnavailable);
}
_worker.Validate(new HttpContextWrapper(HttpContext.Current));
}
/// <summary>
/// Validates an anti-forgery token pair that was generated by the GetTokens method.
/// </summary>
/// <param name="cookieToken">The token that was supplied in the request cookie.</param>
/// <param name="formToken">The token that was supplied in the request form body.</param>
/// <remarks>
/// Throws an HttpAntiForgeryException if validation fails.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static void Validate(string cookieToken, string formToken)
{
if (HttpContext.Current == null)
{
throw new ArgumentException(WebPageResources.HttpContextUnavailable);
}
_worker.Validate(new HttpContextWrapper(HttpContext.Current), cookieToken, formToken);
}
[Obsolete("This method is deprecated. Use the Validate() method instead.", error: true)]
[EditorBrowsable(EditorBrowsableState.Never)]
public static void Validate(HttpContextBase httpContext, string salt)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
if (!String.IsNullOrEmpty(salt))
{
throw new NotSupportedException("This method is deprecated. Use the Validate() method instead.");
}
_worker.Validate(httpContext);
}
}
}

View File

@@ -0,0 +1,126 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel;
using System.Text;
namespace System.Web.Helpers
{
/// <summary>
/// Provides programmatic configuration for the anti-forgery token system.
/// </summary>
public static class AntiForgeryConfig
{
internal const string AntiForgeryTokenFieldName = "__RequestVerificationToken";
private static string _cookieName;
private static string _uniqueClaimTypeIdentifier;
/// <summary>
/// Specifies an object that can provide additional data to put into all
/// generated tokens and that can validate additional data in incoming
/// tokens.
/// </summary>
public static IAntiForgeryAdditionalDataProvider AdditionalDataProvider
{
get;
set;
}
/// <summary>
/// Specifies the name of the cookie that is used by the anti-forgery
/// system.
/// </summary>
/// <remarks>
/// If an explicit name is not provided, the system will automatically
/// generate a name.
/// </remarks>
public static string CookieName
{
get
{
if (_cookieName == null)
{
_cookieName = GetAntiForgeryCookieName();
}
return _cookieName;
}
set
{
_cookieName = value;
}
}
/// <summary>
/// Specifies whether SSL is required for the anti-forgery system
/// to operate. If this setting is 'true' and a non-SSL request
/// comes into the system, all anti-forgery APIs will fail.
/// </summary>
public static bool RequireSsl
{
get;
set;
}
/// <summary>
/// Specifies whether the anti-forgery system should skip checking
/// for conditions that might indicate misuse of the system. Please
/// use caution when setting this switch, as improper use could open
/// security holes in the application.
/// </summary>
/// <remarks>
/// Setting this switch will disable several checks, including:
/// - Identity.IsAuthenticated = true without Identity.Name being set
/// - special-casing claims-based identities
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public static bool SuppressIdentityHeuristicChecks
{
get;
set;
}
/// <summary>
/// If claims-based authorization is in use, specifies the claim
/// type from the identity that is used to uniquely identify the
/// user. If this property is set, all claims-based identities
/// <em>must</em> return unique values for this claim type.
/// </summary>
/// <remarks>
/// If claims-based authorization is in use and this property has
/// not been set, the anti-forgery system will automatically look
/// for claim types "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"
/// and "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider".
/// </remarks>
public static string UniqueClaimTypeIdentifier
{
get
{
return _uniqueClaimTypeIdentifier ?? String.Empty;
}
set
{
_uniqueClaimTypeIdentifier = value;
}
}
private static string GetAntiForgeryCookieName()
{
return GetAntiForgeryCookieName(HttpRuntime.AppDomainAppVirtualPath);
}
// If the app path is provided, we're generating a cookie name rather than a field name, and the cookie names should
// be unique so that a development server cookie and an IIS cookie - both running on localhost - don't stomp on
// each other.
internal static string GetAntiForgeryCookieName(string appPath)
{
if (String.IsNullOrEmpty(appPath) || appPath == "/")
{
return AntiForgeryTokenFieldName;
}
else
{
return AntiForgeryTokenFieldName + "_" + HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(appPath));
}
}
}
}

View File

@@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.Helpers.AntiXsrf
{
internal sealed class AntiForgeryConfigWrapper : IAntiForgeryConfig
{
public IAntiForgeryAdditionalDataProvider AdditionalDataProvider
{
get
{
return AntiForgeryConfig.AdditionalDataProvider;
}
}
public string CookieName
{
get { return AntiForgeryConfig.CookieName; }
}
public string FormFieldName
{
get { return AntiForgeryConfig.AntiForgeryTokenFieldName; }
}
public bool RequireSSL
{
get { return AntiForgeryConfig.RequireSsl; }
}
public bool SuppressIdentityHeuristicChecks
{
get { return AntiForgeryConfig.SuppressIdentityHeuristicChecks; }
}
public string UniqueClaimTypeIdentifier
{
get { return AntiForgeryConfig.UniqueClaimTypeIdentifier; }
}
}
}

View File

@@ -0,0 +1,60 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.Helpers.AntiXsrf
{
// Represents the security token for the Anti-XSRF system.
// The token is a random 128-bit value that correlates the session with the request body.
internal sealed class AntiForgeryToken
{
internal const int SecurityTokenBitLength = 128;
internal const int ClaimUidBitLength = 256;
private string _additionalData;
private BinaryBlob _securityToken;
private string _username;
public string AdditionalData
{
get
{
return _additionalData ?? String.Empty;
}
set
{
_additionalData = value;
}
}
public BinaryBlob ClaimUid { get; set; }
public bool IsSessionToken { get; set; }
public BinaryBlob SecurityToken
{
get
{
if (_securityToken == null)
{
_securityToken = new BinaryBlob(SecurityTokenBitLength);
}
return _securityToken;
}
set
{
_securityToken = value;
}
}
public string Username
{
get
{
return _username ?? String.Empty;
}
set
{
_username = value;
}
}
}
}

View File

@@ -0,0 +1,140 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.IO;
using System.Web.Mvc;
namespace System.Web.Helpers.AntiXsrf
{
internal sealed class AntiForgeryTokenSerializer : IAntiForgeryTokenSerializer
{
private const byte TokenVersion = 0x01;
private readonly ICryptoSystem _cryptoSystem;
public AntiForgeryTokenSerializer()
: this(new MachineKeyCryptoSystem())
{
}
// for unit testing
internal AntiForgeryTokenSerializer(ICryptoSystem cryptoSystem)
{
_cryptoSystem = cryptoSystem;
}
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Failures are homogenized; caller handles appropriately.")]
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "MemoryStream is safe for multi-dispose.")]
public AntiForgeryToken Deserialize(string serializedToken)
{
try
{
using (MemoryStream stream = new MemoryStream(_cryptoSystem.Unprotect(serializedToken)))
{
using (BinaryReader reader = new BinaryReader(stream))
{
AntiForgeryToken token = DeserializeImpl(reader);
if (token != null)
{
return token;
}
}
}
}
catch
{
// swallow all exceptions - homogenize error if something went wrong
}
// if we reached this point, something went wrong deserializing
throw HttpAntiForgeryException.CreateDeserializationFailedException();
}
/* The serialized format of the anti-XSRF token is as follows:
* Version: 1 byte integer
* SecurityToken: 16 byte binary blob
* IsSessionToken: 1 byte Boolean
* [if IsSessionToken = true]
* +- IsClaimsBased: 1 byte Boolean
* | [if IsClaimsBased = true]
* | `- ClaimUid: 32 byte binary blob
* | [if IsClaimsBased = false]
* | `- Username: UTF-8 string with 7-bit integer length prefix
* `- AdditionalData: UTF-8 string with 7-bit integer length prefix
*/
private static AntiForgeryToken DeserializeImpl(BinaryReader reader)
{
// we can only consume tokens of the same serialized version that we generate
byte embeddedVersion = reader.ReadByte();
if (embeddedVersion != TokenVersion)
{
return null;
}
AntiForgeryToken deserializedToken = new AntiForgeryToken();
byte[] securityTokenBytes = reader.ReadBytes(AntiForgeryToken.SecurityTokenBitLength / 8);
deserializedToken.SecurityToken = new BinaryBlob(AntiForgeryToken.SecurityTokenBitLength, securityTokenBytes);
deserializedToken.IsSessionToken = reader.ReadBoolean();
if (!deserializedToken.IsSessionToken)
{
bool isClaimsBased = reader.ReadBoolean();
if (isClaimsBased)
{
byte[] claimUidBytes = reader.ReadBytes(AntiForgeryToken.ClaimUidBitLength / 8);
deserializedToken.ClaimUid = new BinaryBlob(AntiForgeryToken.ClaimUidBitLength, claimUidBytes);
}
else
{
deserializedToken.Username = reader.ReadString();
}
deserializedToken.AdditionalData = reader.ReadString();
}
// if there's still unconsumed data in the stream, fail
if (reader.BaseStream.ReadByte() != -1)
{
return null;
}
// success
return deserializedToken;
}
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "MemoryStream is safe for multi-dispose.")]
public string Serialize(AntiForgeryToken token)
{
Contract.Assert(token != null);
using (MemoryStream stream = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(TokenVersion);
writer.Write(token.SecurityToken.GetData());
writer.Write(token.IsSessionToken);
if (!token.IsSessionToken)
{
if (token.ClaimUid != null)
{
writer.Write(true /* isClaimsBased */);
writer.Write(token.ClaimUid.GetData());
}
else
{
writer.Write(false /* isClaimsBased */);
writer.Write(token.Username);
}
writer.Write(token.AdditionalData);
}
writer.Flush();
return _cryptoSystem.Protect(stream.ToArray());
}
}
}
}
}

View File

@@ -0,0 +1,70 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Web.Mvc;
namespace System.Web.Helpers.AntiXsrf
{
// Saves anti-XSRF tokens split between HttpRequest.Cookies and HttpRequest.Form
internal sealed class AntiForgeryTokenStore : ITokenStore
{
private readonly IAntiForgeryConfig _config;
private readonly IAntiForgeryTokenSerializer _serializer;
public AntiForgeryTokenStore()
: this(new AntiForgeryConfigWrapper(), new AntiForgeryTokenSerializer())
{
}
// for unit testing
internal AntiForgeryTokenStore(IAntiForgeryConfig config, IAntiForgeryTokenSerializer serializer)
{
_config = config;
_serializer = serializer;
}
public AntiForgeryToken GetCookieToken(HttpContextBase httpContext)
{
HttpCookie cookie = httpContext.Request.Cookies[_config.CookieName];
if (cookie == null || String.IsNullOrEmpty(cookie.Value))
{
// did not exist
return null;
}
return _serializer.Deserialize(cookie.Value);
}
public AntiForgeryToken GetFormToken(HttpContextBase httpContext)
{
string value = httpContext.Request.Form[_config.FormFieldName];
if (String.IsNullOrEmpty(value))
{
// did not exist
return null;
}
return _serializer.Deserialize(value);
}
public void SaveCookieToken(HttpContextBase httpContext, AntiForgeryToken token)
{
string serializedToken = _serializer.Serialize(token);
HttpCookie newCookie = new HttpCookie(_config.CookieName, serializedToken)
{
HttpOnly = true
};
// Note: don't use "newCookie.Secure = _config.RequireSSL;" since the default
// value of newCookie.Secure is automatically populated from the <httpCookies>
// config element.
if (_config.RequireSSL)
{
newCookie.Secure = true;
}
httpContext.Response.Cookies.Set(newCookie);
}
}
}

View File

@@ -0,0 +1,181 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Security.Principal;
using System.Web.Mvc;
using System.Web.WebPages.Resources;
namespace System.Web.Helpers.AntiXsrf
{
internal sealed class AntiForgeryWorker
{
private readonly IAntiForgeryConfig _config;
private readonly IAntiForgeryTokenSerializer _serializer;
private readonly ITokenStore _tokenStore;
private readonly ITokenValidator _validator;
public AntiForgeryWorker()
: this(new AntiForgeryTokenSerializer(), new AntiForgeryConfigWrapper(), new AntiForgeryTokenStore(), new TokenValidator())
{
}
// for unit testing
internal AntiForgeryWorker(IAntiForgeryTokenSerializer serializer, IAntiForgeryConfig config, ITokenStore tokenStore, ITokenValidator validator)
{
_serializer = serializer;
_config = config;
_tokenStore = tokenStore;
_validator = validator;
}
private void CheckSSLConfig(HttpContextBase httpContext)
{
if (_config.RequireSSL && !httpContext.Request.IsSecureConnection)
{
throw new InvalidOperationException(WebPageResources.AntiForgeryWorker_RequireSSL);
}
}
private AntiForgeryToken DeserializeToken(string serializedToken)
{
return (!String.IsNullOrEmpty(serializedToken))
? _serializer.Deserialize(serializedToken)
: null;
}
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Caller will just regenerate token in case of failure.")]
private AntiForgeryToken DeserializeTokenNoThrow(string serializedToken)
{
try
{
return DeserializeToken(serializedToken);
}
catch
{
// ignore failures since we'll just generate a new token
return null;
}
}
private static IIdentity ExtractIdentity(HttpContextBase httpContext)
{
if (httpContext != null)
{
IPrincipal user = httpContext.User;
if (user != null)
{
return user.Identity;
}
}
return null;
}
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Caller will just regenerate token in case of failure.")]
private AntiForgeryToken GetCookieTokenNoThrow(HttpContextBase httpContext)
{
try
{
return _tokenStore.GetCookieToken(httpContext);
}
catch
{
// ignore failures since we'll just generate a new token
return null;
}
}
// [ ENTRY POINT ]
// Generates an anti-XSRF token pair for the current user. The return
// value is the hidden input form element that should be rendered in
// the <form>. This method has a side effect: it may set a response
// cookie.
public TagBuilder GetFormInputElement(HttpContextBase httpContext)
{
CheckSSLConfig(httpContext);
AntiForgeryToken oldCookieToken = GetCookieTokenNoThrow(httpContext);
AntiForgeryToken newCookieToken, formToken;
GetTokens(httpContext, oldCookieToken, out newCookieToken, out formToken);
if (newCookieToken != null)
{
// If a new cookie was generated, persist it.
_tokenStore.SaveCookieToken(httpContext, newCookieToken);
}
// <input type="hidden" name="__AntiForgeryToken" value="..." />
TagBuilder retVal = new TagBuilder("input");
retVal.Attributes["type"] = "hidden";
retVal.Attributes["name"] = _config.FormFieldName;
retVal.Attributes["value"] = _serializer.Serialize(formToken);
return retVal;
}
// [ ENTRY POINT ]
// Generates a (cookie, form) serialized token pair for the current user.
// The caller may specify an existing cookie value if one exists. If the
// 'new cookie value' out param is non-null, the caller *must* persist
// the new value to cookie storage since the original value was null or
// invalid. This method is side-effect free.
public void GetTokens(HttpContextBase httpContext, string serializedOldCookieToken, out string serializedNewCookieToken, out string serializedFormToken)
{
CheckSSLConfig(httpContext);
AntiForgeryToken oldCookieToken = DeserializeTokenNoThrow(serializedOldCookieToken);
AntiForgeryToken newCookieToken, formToken;
GetTokens(httpContext, oldCookieToken, out newCookieToken, out formToken);
serializedNewCookieToken = Serialize(newCookieToken);
serializedFormToken = Serialize(formToken);
}
private void GetTokens(HttpContextBase httpContext, AntiForgeryToken oldCookieToken, out AntiForgeryToken newCookieToken, out AntiForgeryToken formToken)
{
newCookieToken = null;
if (!_validator.IsCookieTokenValid(oldCookieToken))
{
// Need to make sure we're always operating with a good cookie token.
oldCookieToken = newCookieToken = _validator.GenerateCookieToken();
}
Contract.Assert(_validator.IsCookieTokenValid(oldCookieToken));
formToken = _validator.GenerateFormToken(httpContext, ExtractIdentity(httpContext), oldCookieToken);
}
private string Serialize(AntiForgeryToken token)
{
return (token != null) ? _serializer.Serialize(token) : null;
}
// [ ENTRY POINT ]
// Given an HttpContext, validates that the anti-XSRF tokens contained
// in the cookies & form are OK for this request.
public void Validate(HttpContextBase httpContext)
{
CheckSSLConfig(httpContext);
// Extract cookie & form tokens
AntiForgeryToken cookieToken = _tokenStore.GetCookieToken(httpContext);
AntiForgeryToken formToken = _tokenStore.GetFormToken(httpContext);
// Validate
_validator.ValidateTokens(httpContext, ExtractIdentity(httpContext), cookieToken, formToken);
}
// [ ENTRY POINT ]
// Given the serialized string representations of a cookie & form token,
// validates that the pair is OK for this request.
public void Validate(HttpContextBase httpContext, string cookieToken, string formToken)
{
CheckSSLConfig(httpContext);
// Extract cookie & form tokens
AntiForgeryToken deserializedCookieToken = DeserializeToken(cookieToken);
AntiForgeryToken deserializedFormToken = DeserializeToken(formToken);
// Validate
_validator.ValidateTokens(httpContext, ExtractIdentity(httpContext), deserializedCookieToken, deserializedFormToken);
}
}
}

View File

@@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
namespace System.Web.Helpers.AntiXsrf
{
// Represents a binary blob (token) that contains random data.
// Useful for binary data inside a serialized stream.
[DebuggerDisplay("{DebuggerString}")]
internal sealed class BinaryBlob : IEquatable<BinaryBlob>
{
private static readonly RNGCryptoServiceProvider _prng = new RNGCryptoServiceProvider();
private readonly byte[] _data;
// Generates a new token using a specified bit length.
public BinaryBlob(int bitLength)
: this(bitLength, GenerateNewToken(bitLength))
{
}
// Generates a token using an existing binary value.
public BinaryBlob(int bitLength, byte[] data)
{
if (bitLength < 32 || bitLength % 8 != 0)
{
throw new ArgumentOutOfRangeException("bitLength");
}
if (data == null || data.Length != bitLength / 8)
{
throw new ArgumentOutOfRangeException("data");
}
_data = data;
}
public int BitLength
{
get
{
return checked(_data.Length * 8);
}
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by debugger.")]
private string DebuggerString
{
get
{
StringBuilder sb = new StringBuilder("0x", 2 + (_data.Length * 2));
for (int i = 0; i < _data.Length; i++)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{0:x2}", _data[i]);
}
return sb.ToString();
}
}
public override bool Equals(object obj)
{
return Equals(obj as BinaryBlob);
}
public bool Equals(BinaryBlob other)
{
if (other == null)
{
return false;
}
Contract.Assert(this._data.Length == other._data.Length);
return CryptoUtil.AreByteArraysEqual(this._data, other._data);
}
public byte[] GetData()
{
return _data;
}
public override int GetHashCode()
{
// Since data should contain uniformly-distributed entropy, the
// first 32 bits can serve as the hash code.
Contract.Assert(_data != null && _data.Length >= (32 / 8));
return BitConverter.ToInt32(_data, 0);
}
private static byte[] GenerateNewToken(int bitLength)
{
byte[] data = new byte[bitLength / 8];
_prng.GetBytes(data);
return data;
}
}
}

View File

@@ -0,0 +1,99 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Globalization;
using System.Linq;
using System.Security.Principal;
using System.Web.Helpers.Claims;
using System.Web.WebPages.Resources;
namespace System.Web.Helpers.AntiXsrf
{
internal sealed class ClaimUidExtractor : IClaimUidExtractor
{
internal const string NameIdentifierClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier";
internal const string IdentityProviderClaimType = "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider";
private readonly ClaimsIdentityConverter _claimsIdentityConverter;
private readonly IAntiForgeryConfig _config;
public ClaimUidExtractor()
: this(new AntiForgeryConfigWrapper(), ClaimsIdentityConverter.Default)
{
}
// for unit testing
internal ClaimUidExtractor(IAntiForgeryConfig config, ClaimsIdentityConverter claimsIdentityConverter)
{
_config = config;
_claimsIdentityConverter = claimsIdentityConverter;
}
public BinaryBlob ExtractClaimUid(IIdentity identity)
{
if (identity == null || !identity.IsAuthenticated || _config.SuppressIdentityHeuristicChecks)
{
// Skip anonymous users
// Skip when claims-based checks are disabled
return null;
}
ClaimsIdentity claimsIdentity = _claimsIdentityConverter.TryConvert(identity);
if (claimsIdentity == null)
{
// not a claims-based identity
return null;
}
string[] uniqueIdentifierParameters = GetUniqueIdentifierParameters(claimsIdentity, _config.UniqueClaimTypeIdentifier);
byte[] claimUidBytes = CryptoUtil.ComputeSHA256(uniqueIdentifierParameters);
return new BinaryBlob(256, claimUidBytes);
}
internal static string[] GetUniqueIdentifierParameters(ClaimsIdentity claimsIdentity, string uniqueClaimTypeIdentifier)
{
var claims = claimsIdentity.GetClaims();
// The application developer might not want to use our default behavior
// and instead might want us to use a claim he knows is unique within
// the security realm of his application. (Perhaps he has crafted this
// claim himself.)
if (!String.IsNullOrEmpty(uniqueClaimTypeIdentifier))
{
Claim matchingClaim = claims.SingleOrDefault(claim => String.Equals(uniqueClaimTypeIdentifier, claim.ClaimType, StringComparison.Ordinal));
if (matchingClaim == null || String.IsNullOrEmpty(matchingClaim.Value))
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, WebPageResources.ClaimUidExtractor_ClaimNotPresent, uniqueClaimTypeIdentifier));
}
return new string[]
{
uniqueClaimTypeIdentifier,
matchingClaim.Value
};
}
// By default, we look for 'nameIdentifier' and 'identityProvider' claims.
// For a correctly configured ACS consumer, this tuple will uniquely
// identify a user of the application. We assume that a well-behaved
// identity provider will never assign the same name identifier to multiple
// users within its security realm, and we assume that ACS has been
// configured so that each identity provider has a unique 'identityProvider'
// claim.
Claim nameIdentifierClaim = claims.SingleOrDefault(claim => String.Equals(NameIdentifierClaimType, claim.ClaimType, StringComparison.Ordinal));
Claim identityProviderClaim = claims.SingleOrDefault(claim => String.Equals(IdentityProviderClaimType, claim.ClaimType, StringComparison.Ordinal));
if (nameIdentifierClaim == null || String.IsNullOrEmpty(nameIdentifierClaim.Value)
|| identityProviderClaim == null || String.IsNullOrEmpty(identityProviderClaim.Value))
{
throw new InvalidOperationException(WebPageResources.ClaimUidExtractor_DefaultClaimsNotPresent);
}
return new string[]
{
NameIdentifierClaimType,
nameIdentifierClaim.Value,
IdentityProviderClaimType,
identityProviderClaim.Value
};
}
}
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.Helpers.AntiXsrf
{
// Provides configuration information about the anti-forgery system.
internal interface IAntiForgeryConfig
{
// Provides additional data to go into the tokens.
IAntiForgeryAdditionalDataProvider AdditionalDataProvider { get; }
// Name of the cookie to use.
string CookieName { get; }
// Name of the form field to use.
string FormFieldName { get; }
// Whether SSL is mandatory for this request.
bool RequireSSL { get; }
// Skip ClaimsIdentity & related logic.
bool SuppressIdentityHeuristicChecks { get; }
// ClaimType to use for ClaimsIdentity.
string UniqueClaimTypeIdentifier { get; }
}
}

View File

@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.Helpers.AntiXsrf
{
// Abstracts out the serialization process for an anti-forgery token
internal interface IAntiForgeryTokenSerializer
{
AntiForgeryToken Deserialize(string serializedToken);
string Serialize(AntiForgeryToken token);
}
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Security.Principal;
namespace System.Web.Helpers.AntiXsrf
{
// Can extract unique identifers for a claims-based identity
internal interface IClaimUidExtractor
{
BinaryBlob ExtractClaimUid(IIdentity identity);
}
}

View File

@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.Helpers.AntiXsrf
{
// Provides an abstraction around the cryptographic subsystem for the anti-XSRF helpers.
internal interface ICryptoSystem
{
string Protect(byte[] data);
byte[] Unprotect(string protectedData);
}
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.Helpers.AntiXsrf
{
// Provides an abstraction around how tokens are persisted and retrieved for a request
internal interface ITokenStore
{
AntiForgeryToken GetCookieToken(HttpContextBase httpContext);
AntiForgeryToken GetFormToken(HttpContextBase httpContext);
void SaveCookieToken(HttpContextBase httpContext, AntiForgeryToken token);
}
}

View File

@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Security.Principal;
namespace System.Web.Helpers.AntiXsrf
{
// Provides an abstraction around something that can validate anti-XSRF tokens
internal interface ITokenValidator
{
// Generates a new random cookie token.
AntiForgeryToken GenerateCookieToken();
// Given a cookie token, generates a corresponding form token.
// The incoming cookie token must be valid.
AntiForgeryToken GenerateFormToken(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken cookieToken);
// Determines whether an existing cookie token is valid (well-formed).
// If it is not, the caller must call GenerateCookieToken() before calling GenerateFormToken().
bool IsCookieTokenValid(AntiForgeryToken cookieToken);
// Validates a (cookie, form) token pair.
void ValidateTokens(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken cookieToken, AntiForgeryToken formToken);
}
}

View File

@@ -0,0 +1,99 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net;
using System.Text;
using System.Web.Security;
namespace System.Web.Helpers.AntiXsrf
{
// Interfaces with the System.Web.MachineKey static class
internal sealed class MachineKeyCryptoSystem : ICryptoSystem
{
// This is the magic header that identifies an AntiForgeryToken payload.
// It helps differentiate this from other encrypted payloads.
private const uint MagicHeader = 0x8587f266;
private readonly Func<string, MachineKeyProtection, byte[]> _decoder;
private readonly Func<byte[], MachineKeyProtection, string> _encoder;
public MachineKeyCryptoSystem()
: this(MachineKey.Encode, MachineKey.Decode)
{
}
// for unit testing
internal MachineKeyCryptoSystem(Func<byte[], MachineKeyProtection, string> encoder, Func<string, MachineKeyProtection, byte[]> decoder)
{
_encoder = encoder;
_decoder = decoder;
}
public string Protect(byte[] data)
{
byte[] dataWithHeader = new byte[data.Length + 4];
Buffer.BlockCopy(data, 0, dataWithHeader, 4, data.Length);
unchecked
{
dataWithHeader[0] = (byte)(MagicHeader >> 24);
dataWithHeader[1] = (byte)(MagicHeader >> 16);
dataWithHeader[2] = (byte)(MagicHeader >> 8);
dataWithHeader[3] = (byte)(MagicHeader);
}
string hex = _encoder(dataWithHeader, MachineKeyProtection.All);
return HexToBase64(hex);
}
public byte[] Unprotect(string protectedData)
{
string hex = Base64ToHex(protectedData);
byte[] dataWithHeader = _decoder(hex, MachineKeyProtection.All);
if (dataWithHeader == null || dataWithHeader.Length < 4 || (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(dataWithHeader, 0)) != MagicHeader)
{
// the decoded data is blank or doesn't begin with the magic header
return null;
}
byte[] retVal = new byte[dataWithHeader.Length - 4];
Buffer.BlockCopy(dataWithHeader, 4, retVal, 0, retVal.Length);
return retVal;
}
// String transformation helpers
internal static string Base64ToHex(string base64)
{
StringBuilder builder = new StringBuilder((int)(base64.Length * 1.5));
foreach (byte b in HttpServerUtility.UrlTokenDecode(base64))
{
builder.Append(HexDigit(b >> 4));
builder.Append(HexDigit(b & 0x0F));
}
string result = builder.ToString();
return result;
}
private static char HexDigit(int value)
{
return (char)(value > 9 ? value + '7' : value + '0');
}
private static int HexValue(char digit)
{
return digit > '9' ? digit - '7' : digit - '0';
}
internal static string HexToBase64(string hex)
{
int size = hex.Length / 2;
byte[] bytes = new byte[size];
for (int idx = 0; idx < size; idx++)
{
bytes[idx] = (byte)((HexValue(hex[idx * 2]) << 4) + HexValue(hex[(idx * 2) + 1]));
}
string result = HttpServerUtility.UrlTokenEncode(bytes);
return result;
}
}
}

View File

@@ -0,0 +1,147 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Security.Principal;
using System.Web.Mvc;
using System.Web.WebPages.Resources;
namespace System.Web.Helpers.AntiXsrf
{
internal sealed class TokenValidator : ITokenValidator
{
private readonly IClaimUidExtractor _claimUidExtractor;
private readonly IAntiForgeryConfig _config;
public TokenValidator()
: this(new AntiForgeryConfigWrapper(), new ClaimUidExtractor())
{
}
// for unit testing
internal TokenValidator(IAntiForgeryConfig config, IClaimUidExtractor claimUidExtractor)
{
_config = config;
_claimUidExtractor = claimUidExtractor;
}
public AntiForgeryToken GenerateCookieToken()
{
return new AntiForgeryToken()
{
// SecurityToken will be populated automatically.
IsSessionToken = true
};
}
public AntiForgeryToken GenerateFormToken(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken cookieToken)
{
Contract.Assert(IsCookieTokenValid(cookieToken));
AntiForgeryToken formToken = new AntiForgeryToken()
{
SecurityToken = cookieToken.SecurityToken,
IsSessionToken = false
};
bool requireAuthenticatedUserHeuristicChecks = false;
// populate Username and ClaimUid
if (identity != null && identity.IsAuthenticated)
{
if (!_config.SuppressIdentityHeuristicChecks)
{
// If the user is authenticated and heuristic checks are not suppressed,
// then Username, ClaimUid, or AdditionalData must be set.
requireAuthenticatedUserHeuristicChecks = true;
}
formToken.ClaimUid = _claimUidExtractor.ExtractClaimUid(identity);
if (formToken.ClaimUid == null)
{
formToken.Username = identity.Name;
}
}
// populate AdditionalData
if (_config.AdditionalDataProvider != null)
{
formToken.AdditionalData = _config.AdditionalDataProvider.GetAdditionalData(httpContext);
}
if (requireAuthenticatedUserHeuristicChecks
&& String.IsNullOrEmpty(formToken.Username)
&& formToken.ClaimUid == null
&& String.IsNullOrEmpty(formToken.AdditionalData))
{
// Application says user is authenticated, but we have no identifier for the user.
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
WebPageResources.TokenValidator_AuthenticatedUserWithoutUsername, identity.GetType()));
}
return formToken;
}
public bool IsCookieTokenValid(AntiForgeryToken cookieToken)
{
return (cookieToken != null && cookieToken.IsSessionToken);
}
public void ValidateTokens(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken sessionToken, AntiForgeryToken fieldToken)
{
// Were the tokens even present at all?
if (sessionToken == null)
{
throw HttpAntiForgeryException.CreateCookieMissingException(_config.CookieName);
}
if (fieldToken == null)
{
throw HttpAntiForgeryException.CreateFormFieldMissingException(_config.FormFieldName);
}
// Do the tokens have the correct format?
if (!sessionToken.IsSessionToken || fieldToken.IsSessionToken)
{
throw HttpAntiForgeryException.CreateTokensSwappedException(_config.CookieName, _config.FormFieldName);
}
// Are the security tokens embedded in each incoming token identical?
if (!Equals(sessionToken.SecurityToken, fieldToken.SecurityToken))
{
throw HttpAntiForgeryException.CreateSecurityTokenMismatchException();
}
// Is the incoming token meant for the current user?
string currentUsername = String.Empty;
BinaryBlob currentClaimUid = null;
if (identity != null && identity.IsAuthenticated)
{
currentClaimUid = _claimUidExtractor.ExtractClaimUid(identity);
if (currentClaimUid == null)
{
currentUsername = identity.Name ?? String.Empty;
}
}
// OpenID and other similar authentication schemes use URIs for the username.
// These should be treated as case-sensitive.
bool useCaseSensitiveUsernameComparison = currentUsername.StartsWith("http://", StringComparison.OrdinalIgnoreCase)
|| currentUsername.StartsWith("https://", StringComparison.OrdinalIgnoreCase);
if (!String.Equals(fieldToken.Username, currentUsername, (useCaseSensitiveUsernameComparison) ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase))
{
throw HttpAntiForgeryException.CreateUsernameMismatchException(fieldToken.Username, currentUsername);
}
if (!Equals(fieldToken.ClaimUid, currentClaimUid))
{
throw HttpAntiForgeryException.CreateClaimUidMismatchException();
}
// Is the AdditionalData valid?
if (_config.AdditionalDataProvider != null && !_config.AdditionalDataProvider.ValidateAdditionalData(httpContext, fieldToken.AdditionalData))
{
throw HttpAntiForgeryException.CreateAdditionalDataCheckFailedException();
}
}
}
}

View File

@@ -0,0 +1,71 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Reflection;
namespace System.Web.Helpers.Claims
{
// Represents a Claim; serves as an abstraction around the WIF SDK and 4.5 Claim types since
// we can't compile directly against them.
internal sealed class Claim
{
public Claim(string claimType, string value)
{
ClaimType = claimType;
Value = value;
}
public string ClaimType { get; private set; }
public string Value { get; private set; }
// Creates a Claim from a TClaim object (duck typing).
//
// The TClaim must have the following shape:
// class TClaim {
// string ClaimType { get; } // or just 'Type'
// string Value { get; }
// }
internal static Claim Create<TClaim>(TClaim claim)
{
return ClaimFactory<TClaim>.Create(claim);
}
private static class ClaimFactory<TClaim>
{
private static readonly Func<TClaim, string> _claimTypeGetter = CreateClaimTypeGetter();
private static readonly Func<TClaim, string> _valueGetter = CreateValueGetter();
public static Claim Create(TClaim claim)
{
return new Claim(_claimTypeGetter(claim), _valueGetter(claim));
}
private static Func<TClaim, string> CreateClaimTypeGetter()
{
// the claim type might go by one of two different property names
return CreateGeneralPropertyGetter("ClaimType") ?? CreateGeneralPropertyGetter("Type");
}
private static Func<TClaim, string> CreateGeneralPropertyGetter(string propertyName)
{
PropertyInfo propInfo = typeof(TClaim).GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance, null, typeof(string), Type.EmptyTypes, null);
if (propInfo == null)
{
return null;
}
MethodInfo propGetter = propInfo.GetGetMethod();
// For improved perf, instance methods can be treated as static methods by leaving
// the 'this' parameter unbound. Virtual dispatch for the property getter will
// still take place as expected.
return (Func<TClaim, string>)Delegate.CreateDelegate(typeof(Func<TClaim, string>), propGetter);
}
private static Func<TClaim, string> CreateValueGetter()
{
return CreateGeneralPropertyGetter("Value");
}
}
}
}

View File

@@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Principal;
namespace System.Web.Helpers.Claims
{
// Represents a ClaimsIdentity; serves as an abstraction around the WIF SDK and 4.5
// ClaimIdentity types since we can't compile directly against them.
internal abstract class ClaimsIdentity
{
public abstract IEnumerable<Claim> GetClaims();
// Attempts to convert an IIdentity into a ClaimsIdentity;
// returns null if the conversion fails (duck typing).
//
// The TClaimsIdentity must have the following shape:
// class TClaimsIdentity : IIdentity {
// TClaimsCollection Claims { get; }
// }
// where TClaimsCollection is assignable to IEnumerable<TClaim>,
// and where TClaim is valid for Claim.Create<TClaim>.
internal static ClaimsIdentity TryConvert<TClaimsIdentity, TClaim>(IIdentity identity)
where TClaimsIdentity : class, IIdentity
{
TClaimsIdentity castClaimsIdentity = identity as TClaimsIdentity;
return (castClaimsIdentity != null)
? new ClaimsIdentityImpl<TClaimsIdentity, TClaim>(castClaimsIdentity)
: null;
}
private sealed class ClaimsIdentityImpl<TClaimsIdentity, TClaim> : ClaimsIdentity
where TClaimsIdentity : class, IIdentity
{
private static readonly Func<TClaimsIdentity, IEnumerable<TClaim>> _claimsGetter = CreateClaimsGetter();
private readonly TClaimsIdentity _claimsIdentity;
public ClaimsIdentityImpl(TClaimsIdentity claimsIdentity)
{
_claimsIdentity = claimsIdentity;
}
private static Func<TClaimsIdentity, IEnumerable<TClaim>> CreateClaimsGetter()
{
PropertyInfo propInfo = typeof(TClaimsIdentity).GetProperty("Claims", BindingFlags.Public | BindingFlags.Instance);
MethodInfo propGetter = propInfo.GetGetMethod();
// For improved perf, instance methods can be treated as static methods by leaving
// the 'this' parameter unbound. Virtual dispatch for the property getter will
// still take place as expected.
return (Func<TClaimsIdentity, IEnumerable<TClaim>>)Delegate.CreateDelegate(typeof(Func<TClaimsIdentity, IEnumerable<TClaim>>), propGetter);
}
public override IEnumerable<Claim> GetClaims()
{
return _claimsGetter(_claimsIdentity).Select(Claim.Create);
}
}
}
}

View File

@@ -0,0 +1,99 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Reflection;
using System.Security.Principal;
using System.Web.Security;
namespace System.Web.Helpers.Claims
{
// Can convert IIdentity instances into our ClaimsIdentity wrapper.
internal sealed class ClaimsIdentityConverter
{
private static readonly MethodInfo _claimsIdentityTryConvertOpenMethod = typeof(ClaimsIdentity).GetMethod("TryConvert", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
private static readonly ClaimsIdentityConverter _default = new ClaimsIdentityConverter(GetDefaultConverters());
private readonly Func<IIdentity, ClaimsIdentity>[] _converters;
// Internal for unit testing; nobody should ever be calling this in production.
internal ClaimsIdentityConverter(Func<IIdentity, ClaimsIdentity>[] converters)
{
_converters = converters;
}
// By default, we understand the ClaimsIdentity / Claim types included
// with the WIF SDK and FX 4.5.
public static ClaimsIdentityConverter Default
{
get
{
return _default;
}
}
private static bool IsGrandfatheredIdentityType(IIdentity claimsIdentity)
{
// These specific types might also be claims-based types depending on
// the version of the framework we're running, but we don't want to
// treat them as claims-based types since we know their Name property
// will suffice as a unique identifier within the security realm of the
// current application.
return claimsIdentity is FormsIdentity
|| claimsIdentity is WindowsIdentity
|| claimsIdentity is GenericIdentity;
}
public ClaimsIdentity TryConvert(IIdentity identity)
{
if (IsGrandfatheredIdentityType(identity))
{
return null;
}
// loop through all registered converters until one matches
for (int i = 0; i < _converters.Length; i++)
{
ClaimsIdentity retVal = _converters[i](identity);
if (retVal != null)
{
return retVal;
}
}
return null;
}
private static void AddToList(IList<Func<IIdentity, ClaimsIdentity>> converters, Type claimsIdentityType, Type claimType)
{
if (claimsIdentityType != null && claimType != null)
{
MethodInfo tryConvertClosedMethod = _claimsIdentityTryConvertOpenMethod.MakeGenericMethod(claimsIdentityType, claimType);
Func<IIdentity, ClaimsIdentity> converter = (Func<IIdentity, ClaimsIdentity>)Delegate.CreateDelegate(typeof(Func<IIdentity, ClaimsIdentity>), tryConvertClosedMethod);
converters.Add(converter);
}
}
private static Func<IIdentity, ClaimsIdentity>[] GetDefaultConverters()
{
List<Func<IIdentity, ClaimsIdentity>> converters = new List<Func<IIdentity, ClaimsIdentity>>();
// WIF SDK is only available in full trust scenarios
if (AppDomain.CurrentDomain.IsHomogenous && AppDomain.CurrentDomain.IsFullyTrusted)
{
Type claimsIdentityType = Type.GetType("Microsoft.IdentityModel.Claims.IClaimsIdentity, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
Type claimType = Type.GetType("Microsoft.IdentityModel.Claims.Claim, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(converters, claimsIdentityType, claimType);
}
// 4.5 ClaimsIdentity type
{
Module mscorlibModule = typeof(object).Module;
Type claimsIdentityType = mscorlibModule.GetType("System.Security.Claims.ClaimsIdentity");
Type claimType = mscorlibModule.GetType("System.Security.Claims.Claim");
AddToList(converters, claimsIdentityType, claimType);
}
return converters.ToArray();
}
}
}

Some files were not shown because too many files have changed in this diff Show More