private void DeserializeTokens( HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet, out AntiforgeryToken cookieToken, out AntiforgeryToken requestToken) { var antiforgeryFeature = GetAntiforgeryFeature(httpContext); if (antiforgeryFeature.HaveDeserializedCookieToken) { cookieToken = antiforgeryFeature.CookieToken; } else { cookieToken = _tokenSerializer.Deserialize(antiforgeryTokenSet.CookieToken); antiforgeryFeature.CookieToken = cookieToken; antiforgeryFeature.HaveDeserializedCookieToken = true; } if (antiforgeryFeature.HaveDeserializedRequestToken) { requestToken = antiforgeryFeature.RequestToken; } else { requestToken = _tokenSerializer.Deserialize(antiforgeryTokenSet.RequestToken); antiforgeryFeature.RequestToken = requestToken; antiforgeryFeature.HaveDeserializedRequestToken = true; } }
public string Serialize(AntiforgeryToken token) { if (token == null) { throw new ArgumentNullException(nameof(token)); } var serializationContext = _pool.Get(); try { var writer = serializationContext.Writer; writer.Write(TokenVersion); writer.Write(token.SecurityToken !.GetData()); writer.Write(token.IsCookieToken); if (!token.IsCookieToken) { 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(); var stream = serializationContext.Stream; var bytes = _cryptoSystem.Protect(stream.ToArray()); var count = bytes.Length; var charsRequired = WebEncoders.GetArraySizeRequiredToEncode(count); var chars = serializationContext.GetChars(charsRequired); var outputLength = WebEncoders.Base64UrlEncode( bytes, offset: 0, output: chars, outputOffset: 0, count: count); return(new string(chars, startIndex : 0, length : outputLength)); } finally { _pool.Return(serializationContext); } }
/* The serialized format of the anti-XSRF token is as follows: * Version: 1 byte integer * SecurityToken: 16 byte binary blob * IsCookieToken: 1 byte Boolean * [if IsCookieToken != 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?Deserialize(BinaryReader reader) { // we can only consume tokens of the same serialized version that we generate var embeddedVersion = reader.ReadByte(); if (embeddedVersion != TokenVersion) { return(null); } var deserializedToken = new AntiforgeryToken(); var securityTokenBytes = reader.ReadBytes(AntiforgeryToken.SecurityTokenBitLength / 8); deserializedToken.SecurityToken = new BinaryBlob(AntiforgeryToken.SecurityTokenBitLength, securityTokenBytes); deserializedToken.IsCookieToken = reader.ReadBoolean(); if (!deserializedToken.IsCookieToken) { var isClaimsBased = reader.ReadBoolean(); if (isClaimsBased) { var 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); }
private bool TryDeserializeTokens( HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet, out AntiforgeryToken cookieToken, out AntiforgeryToken requestToken) { try { DeserializeTokens(httpContext, antiforgeryTokenSet, out cookieToken, out requestToken); return(true); } catch (AntiforgeryValidationException ex) { _logger.FailedToDeserialzeTokens(ex); cookieToken = null; requestToken = null; return(false); } }
/// <inheritdoc /> public AntiforgeryToken GenerateRequestToken( HttpContext httpContext, AntiforgeryToken cookieToken) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } if (cookieToken == null) { throw new ArgumentNullException(nameof(cookieToken)); } if (!IsCookieTokenValid(cookieToken)) { throw new ArgumentException( Resources.Antiforgery_CookieToken_IsInvalid, nameof(cookieToken)); } var requestToken = new AntiforgeryToken() { SecurityToken = cookieToken.SecurityToken, IsCookieToken = false }; var isIdentityAuthenticated = false; // populate Username and ClaimUid var authenticatedIdentity = GetAuthenticatedIdentity(httpContext.User); if (authenticatedIdentity != null) { isIdentityAuthenticated = true; requestToken.ClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(httpContext.User)); if (requestToken.ClaimUid == null) { requestToken.Username = authenticatedIdentity.Name; } } // populate AdditionalData if (_additionalDataProvider != null) { requestToken.AdditionalData = _additionalDataProvider.GetAdditionalData(httpContext); } if (isIdentityAuthenticated && string.IsNullOrEmpty(requestToken.Username) && requestToken.ClaimUid == null && string.IsNullOrEmpty(requestToken.AdditionalData)) { // Application says user is authenticated, but we have no identifier for the user. throw new InvalidOperationException( Resources.FormatAntiforgeryTokenValidator_AuthenticatedUserWithoutUsername( authenticatedIdentity.GetType(), nameof(IIdentity.IsAuthenticated), "true", nameof(IIdentity.Name), nameof(IAntiforgeryAdditionalDataProvider), nameof(DefaultAntiforgeryAdditionalDataProvider))); } return(requestToken); }
/// <inheritdoc /> public bool TryValidateTokenSet( HttpContext httpContext, AntiforgeryToken cookieToken, AntiforgeryToken requestToken, out string message) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } if (cookieToken == null) { throw new ArgumentNullException( nameof(cookieToken), Resources.Antiforgery_CookieToken_MustBeProvided_Generic); } if (requestToken == null) { throw new ArgumentNullException( nameof(requestToken), Resources.Antiforgery_RequestToken_MustBeProvided_Generic); } // Do the tokens have the correct format? if (!cookieToken.IsCookieToken || requestToken.IsCookieToken) { message = Resources.AntiforgeryToken_TokensSwapped; return(false); } // Are the security tokens embedded in each incoming token identical? if (!object.Equals(cookieToken.SecurityToken, requestToken.SecurityToken)) { message = Resources.AntiforgeryToken_SecurityTokenMismatch; return(false); } // Is the incoming token meant for the current user? var currentUsername = string.Empty; BinaryBlob currentClaimUid = null; var authenticatedIdentity = GetAuthenticatedIdentity(httpContext.User); if (authenticatedIdentity != null) { currentClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(httpContext.User)); if (currentClaimUid == null) { currentUsername = authenticatedIdentity.Name ?? string.Empty; } } // OpenID and other similar authentication schemes use URIs for the username. // These should be treated as case-sensitive. var comparer = StringComparer.OrdinalIgnoreCase; if (currentUsername.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || currentUsername.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) { comparer = StringComparer.Ordinal; } if (!comparer.Equals(requestToken.Username, currentUsername)) { message = Resources.FormatAntiforgeryToken_UsernameMismatch(requestToken.Username, currentUsername); return(false); } if (!object.Equals(requestToken.ClaimUid, currentClaimUid)) { message = Resources.AntiforgeryToken_ClaimUidMismatch; return(false); } // Is the AdditionalData valid? if (_additionalDataProvider != null && !_additionalDataProvider.ValidateAdditionalData(httpContext, requestToken.AdditionalData)) { message = Resources.AntiforgeryToken_AdditionalDataCheckFailed; return(false); } message = null; return(true); }
/// <inheritdoc /> public bool IsCookieTokenValid(AntiforgeryToken cookieToken) { return(cookieToken != null && cookieToken.IsCookieToken); }