using System;
using System.Collections.Generic;
using System.Security.Claims;
namespace WalkingTec.Mvvm.Core.Auth
{
///
/// Compares two instances of Claim
///
public class ClaimComparer : EqualityComparer
{
///
/// Claim comparison options
///
public class Options
{
///
/// Specifies if the issuer value is being taken into account
///
public bool IgnoreIssuer { get; set; } = false;
///
/// Specifies if claim and issuer value comparison should be case-sensitive
///
public bool IgnoreValueCase { get; set; } = false;
}
private readonly Options _options = new Options();
///
/// Initializes a new instance of the class with default options.
///
public ClaimComparer()
{ }
///
/// Initializes a new instance of the class with given comparison options.
///
/// Comparison options.
public ClaimComparer(Options options)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
}
///
public override bool Equals(Claim x, Claim y)
{
if (x == null && y == null) return true;
if (x == null && y != null) return false;
if (x != null && y == null) return false;
StringComparison valueComparison = StringComparison.Ordinal;
if (_options.IgnoreValueCase == true) valueComparison = StringComparison.OrdinalIgnoreCase;
var equal = (String.Equals(x.Type, y.Type, StringComparison.OrdinalIgnoreCase) &&
String.Equals(x.Value, y.Value, valueComparison) &&
String.Equals(x.ValueType, y.ValueType, StringComparison.Ordinal));
if (_options.IgnoreIssuer)
{
return equal;
}
else
{
return (equal && String.Equals(x.Issuer, y.Issuer, valueComparison));
}
}
///
public override int GetHashCode(Claim claim)
{
if (claim is null) return 0;
int typeHash = claim.Type?.ToLowerInvariant().GetHashCode() ?? 0 ^ claim.ValueType?.GetHashCode() ?? 0;
int valueHash;
int issuerHash;
if (_options.IgnoreValueCase)
{
valueHash = claim.Value?.ToLowerInvariant().GetHashCode() ?? 0;
issuerHash = claim.Issuer?.ToLowerInvariant().GetHashCode() ?? 0;
}
else
{
valueHash = claim.Value?.GetHashCode() ?? 0;
issuerHash = claim.Issuer?.GetHashCode() ?? 0;
}
if (_options.IgnoreIssuer)
{
return typeHash ^ valueHash;
}
else
{
return typeHash ^ valueHash ^ issuerHash;
}
}
}
}