aspnetcore/src/Microsoft.AspNet.Antiforgery/DefaultAntiforgeryTokenGene...

170 lines
6.6 KiB
C#

// 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;
using System.Security.Claims;
using Microsoft.AspNet.Http;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Antiforgery
{
public class DefaultAntiforgeryTokenGenerator : IAntiforgeryTokenGenerator
{
private readonly IClaimUidExtractor _claimUidExtractor;
private readonly AntiforgeryOptions _options;
private readonly IAntiforgeryAdditionalDataProvider _additionalDataProvider;
public DefaultAntiforgeryTokenGenerator(
IOptions<AntiforgeryOptions> optionsAccessor,
IClaimUidExtractor claimUidExtractor,
IAntiforgeryAdditionalDataProvider additionalDataProvider)
{
_options = optionsAccessor.Options;
_claimUidExtractor = claimUidExtractor;
_additionalDataProvider = additionalDataProvider;
}
public AntiforgeryToken GenerateCookieToken()
{
return new AntiforgeryToken()
{
// SecurityToken will be populated automatically.
IsSessionToken = true
};
}
public AntiforgeryToken GenerateFormToken(
HttpContext httpContext,
AntiforgeryToken cookieToken)
{
Debug.Assert(IsCookieTokenValid(cookieToken));
var formToken = new AntiforgeryToken()
{
SecurityToken = cookieToken.SecurityToken,
IsSessionToken = false
};
var isIdentityAuthenticated = false;
var identity = httpContext.User?.Identity as ClaimsIdentity;
// populate Username and ClaimUid
if (identity != null && identity.IsAuthenticated)
{
isIdentityAuthenticated = true;
formToken.ClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(identity));
if (formToken.ClaimUid == null)
{
formToken.Username = identity.Name;
}
}
// populate AdditionalData
if (_additionalDataProvider != null)
{
formToken.AdditionalData = _additionalDataProvider.GetAdditionalData(httpContext);
}
if (isIdentityAuthenticated
&& 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(
Resources.FormatAntiforgeryTokenValidator_AuthenticatedUserWithoutUsername(identity.GetType()));
}
return formToken;
}
public bool IsCookieTokenValid(AntiforgeryToken cookieToken)
{
return (cookieToken != null && cookieToken.IsSessionToken);
}
public void ValidateTokens(
HttpContext httpContext,
AntiforgeryToken sessionToken,
AntiforgeryToken fieldToken)
{
// Were the tokens even present at all?
if (sessionToken == null)
{
throw new InvalidOperationException(
Resources.FormatAntiforgeryToken_CookieMissing(_options.CookieName));
}
if (fieldToken == null)
{
throw new InvalidOperationException(
Resources.FormatAntiforgeryToken_FormFieldMissing(_options.FormFieldName));
}
// Do the tokens have the correct format?
if (!sessionToken.IsSessionToken || fieldToken.IsSessionToken)
{
throw new InvalidOperationException(
Resources.FormatAntiforgeryToken_TokensSwapped(_options.CookieName, _options.FormFieldName));
}
// Are the security tokens embedded in each incoming token identical?
if (!Equals(sessionToken.SecurityToken, fieldToken.SecurityToken))
{
throw new InvalidOperationException(Resources.AntiforgeryToken_SecurityTokenMismatch);
}
// Is the incoming token meant for the current user?
var currentUsername = string.Empty;
BinaryBlob currentClaimUid = null;
var identity = httpContext.User?.Identity as ClaimsIdentity;
if (identity != null && identity.IsAuthenticated)
{
currentClaimUid = GetClaimUidBlob(_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.
var useCaseSensitiveUsernameComparison =
currentUsername.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
currentUsername.StartsWith("https://", StringComparison.OrdinalIgnoreCase);
if (!string.Equals(fieldToken.Username,
currentUsername,
(useCaseSensitiveUsernameComparison) ?
StringComparison.Ordinal :
StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
Resources.FormatAntiforgeryToken_UsernameMismatch(fieldToken.Username, currentUsername));
}
if (!Equals(fieldToken.ClaimUid, currentClaimUid))
{
throw new InvalidOperationException(Resources.AntiforgeryToken_ClaimUidMismatch);
}
// Is the AdditionalData valid?
if (_additionalDataProvider != null &&
!_additionalDataProvider.ValidateAdditionalData(httpContext, fieldToken.AdditionalData))
{
throw new InvalidOperationException(Resources.AntiforgeryToken_AdditionalDataCheckFailed);
}
}
private static BinaryBlob GetClaimUidBlob(string base64ClaimUid)
{
if (base64ClaimUid == null)
{
return null;
}
return new BinaryBlob(256, Convert.FromBase64String(base64ClaimUid));
}
}
}