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; } } } }