Skip to content

Commit

Permalink
Merge pull request #1502 from mconnew/Issue1454
Browse files Browse the repository at this point in the history
Fix UpnEndpointIdentity on UWP
  • Loading branch information
mconnew authored Sep 16, 2016
2 parents 2f6cda5 + dac98a7 commit b3a031c
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,13 @@ public static Claim CreateThumbprintClaim(byte[] thumbprint)
return new Claim(ClaimTypes.Thumbprint, SecurityUtils.CloneBuffer(thumbprint), Rights.PossessProperty, ClaimComparer.Thumbprint);
}

#if SUPPORTS_WINDOWSIDENTITY
public static Claim CreateUpnClaim(string upn)
{
if (upn == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("upn");

return new Claim(ClaimTypes.Upn, upn, Rights.PossessProperty, ClaimComparer.Upn);
}
#endif // SUPPORTS_WINDOWSIDENTITY

public static Claim CreateUriClaim(Uri uri)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ internal class ClaimComparer : IEqualityComparer<Claim>
private static IEqualityComparer<Claim> s_dnsComparer;
private static IEqualityComparer<Claim> s_rsaComparer;
private static IEqualityComparer<Claim> s_thumbprintComparer;
#if SUPPORTS_WINDOWSIDENTITY
private static IEqualityComparer<Claim> s_upnComparer;
#endif // SUPPORTS_WINDOWSIDENTITY
private static IEqualityComparer<Claim> s_x500DistinguishedNameComparer;
private IEqualityComparer _resourceComparer;

Expand Down Expand Up @@ -113,7 +111,6 @@ public static IEqualityComparer<Claim> Thumbprint
}
}

#if SUPPORTS_WINDOWSIDENTITY
public static IEqualityComparer<Claim> Upn
{
get
Expand All @@ -125,7 +122,6 @@ public static IEqualityComparer<Claim> Upn
return s_upnComparer;
}
}
#endif // SUPPORTS_WINDOWSIDENTITY

public static IEqualityComparer<Claim> X500DistinguishedName
{
Expand Down Expand Up @@ -160,7 +156,7 @@ public int GetHashCode(Claim claim)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("claim");

return claim.ClaimType.GetHashCode() ^ claim.Right.GetHashCode()
^ ((claim.Resource == null) ? 0 : _resourceComparer.GetHashCode(claim.Resource));
^ ((claim.Resource == null) ? 0 : _resourceComparer.GetHashCode(claim.Resource));
}

private class ObjectComparer : IEqualityComparer
Expand Down Expand Up @@ -240,6 +236,7 @@ int IEqualityComparer.GetHashCode(object obj)
private class X500DistinguishedNameObjectComparer : IEqualityComparer
{
private IEqualityComparer _binaryComparer;

public X500DistinguishedNameObjectComparer()
{
_binaryComparer = new BinaryObjectComparer();
Expand All @@ -258,12 +255,35 @@ int IEqualityComparer.GetHashCode(object obj)
}
}

#if SUPPORTS_WINDOWSIDENTITY
private class UpnObjectComparer : IEqualityComparer
{
bool IEqualityComparer.Equals(object obj1, object obj2)
{
throw ExceptionHelper.PlatformNotSupported();
if (StringComparer.OrdinalIgnoreCase.Equals(obj1 as string, obj2 as string))
return true;

string upn1 = obj1 as string;
string upn2 = obj2 as string;
if (upn1 == null || upn2 == null)
return false;

#if SUPPORTS_WINDOWSIDENTITY
SecurityIdentifier sid1;
if (!TryLookupSidFromName(upn1, out sid1))
return false;

// Normalize to sid
SecurityIdentifier sid2;
if (!TryLookupSidFromName(upn2, out sid2))
return false;

return sid1 == sid2;
#else
// If WindowsIdentity isn't supported, then we can't
// retrieve the SecurityIdentifier's to compare so
// must return false
return false;
#endif // SUPPORTS_WINDOWSIDENTITY
}

int IEqualityComparer.GetHashCode(object obj)
Expand All @@ -272,14 +292,17 @@ int IEqualityComparer.GetHashCode(object obj)
if (upn == null)
return 0;

#if SUPPORTS_WINDOWSIDENTITY
// Normalize to sid
SecurityIdentifier sid;
if (TryLookupSidFromName(upn, out sid))
return sid.GetHashCode();
#endif // SUPPORTS_WINDOWSIDENTITY

return StringComparer.OrdinalIgnoreCase.GetHashCode(upn);
}

#if SUPPORTS_WINDOWSIDENTITY
private bool TryLookupSidFromName(string upn, out SecurityIdentifier sid)
{
sid = null;
Expand All @@ -293,7 +316,7 @@ private bool TryLookupSidFromName(string upn, out SecurityIdentifier sid)
}
return sid != null;
}
#endif // SUPPORTS_WINDOWSIDENTITY
}
#endif // SUPPORTS_WINDOWSIDENTITY
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,9 @@ internal static void TraceIdentityDeterminationSuccess(EndpointAddress epr, Endp
internal static void TraceIdentityDeterminationFailure(EndpointAddress epr, Type identityVerifier)
{
}

internal static void TraceSpnToSidMappingFailure(string spn, Exception e)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
// See the LICENSE file in the project root for more information.


using System.ComponentModel;
using System.Security.Principal;
using System.IdentityModel.Claims;
using System.Runtime;
using System.Runtime.InteropServices;
using System.ServiceModel.Diagnostics;
using System.Text;
using System.Xml;

namespace System.ServiceModel
{
Expand All @@ -23,24 +29,22 @@ public class UpnEndpointIdentity : EndpointIdentity
public UpnEndpointIdentity(string upnName)
{
if (upnName == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("upnName");
#if SUPPORTS_WINDOWSIDENTITY
base.Initialize(Claim.CreateUpnClaim(upnName));
#else
throw ExceptionHelper.PlatformNotSupported("UpnEndpointIdentity is not supported on this platform");
#endif // SUPPORTS_WINDOWSIDENTITY
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(upnName));
}

Initialize(Claim.CreateUpnClaim(upnName));
}

public UpnEndpointIdentity(Claim identity)
{
if (identity == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("identity");
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(identity));

// PreSharp Bug: Parameter 'identity.ResourceType' to this public method must be validated: A null-dereference can occur here.
if (!identity.ClaimType.Equals(ClaimTypes.Upn))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.Format(SR.UnrecognizedClaimTypeForIdentity, identity.ClaimType, ClaimTypes.Upn));

base.Initialize(identity);
Initialize(identity);
}

#if SUPPORTS_WINDOWSIDENTITY
Expand All @@ -53,6 +57,110 @@ internal UpnEndpointIdentity(WindowsIdentity windowsIdentity)
_upnSid = windowsIdentity.User;
_hasUpnSidBeenComputed = true;
}

internal override void EnsureIdentityClaim()
{
if (_windowsIdentity != null)
{
lock (_thisLock)
{
if (_windowsIdentity != null)
{
Initialize(Claim.CreateUpnClaim(GetUpnFromWindowsIdentity(_windowsIdentity)));
_windowsIdentity.Dispose();
_windowsIdentity = null;
}
}
}
}

string GetUpnFromWindowsIdentity(WindowsIdentity windowsIdentity)
{
string downlevelName = null;
string upnName = null;

try
{
downlevelName = windowsIdentity.Name;

if (IsMachineJoinedToDomain())
{
upnName = GetUpnFromDownlevelName(downlevelName);
}
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
}

// if the AD cannot be queried for the fully qualified domain name,
// fall back to the downlevel UPN name
return upnName ?? downlevelName;
}

bool IsMachineJoinedToDomain()
{
throw ExceptionHelper.PlatformNotSupported();
}

string GetUpnFromDownlevelName(string downlevelName)
{
throw ExceptionHelper.PlatformNotSupported();
}
#endif // SUPPORTS_WINDOWSIDENTITY

internal override void WriteContentsTo(XmlDictionaryWriter writer)
{
if (writer == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(writer));

writer.WriteElementString(XD.AddressingDictionary.Upn, XD.AddressingDictionary.IdentityExtensionNamespace, (string)this.IdentityClaim.Resource);
}

#if SUPPORTS_WINDOWSIDENTITY
internal SecurityIdentifier GetUpnSid()
{
Fx.Assert(ClaimTypes.Upn.Equals(this.IdentityClaim.ClaimType), "");
if (!_hasUpnSidBeenComputed)
{
lock (_thisLock)
{
string upn = (string)this.IdentityClaim.Resource;
if (!_hasUpnSidBeenComputed)
{
try
{
NTAccount userAccount = new NTAccount(upn);
_upnSid = userAccount.Translate(typeof(SecurityIdentifier)) as SecurityIdentifier;
}
#pragma warning suppress 56500 // covered by FxCOP
catch (Exception e)
{
// Always immediately rethrow fatal exceptions.
if (Fx.IsFatal(e))
{
throw;
}

if (e is NullReferenceException)
{
throw;
}

SecurityTraceRecordHelper.TraceSpnToSidMappingFailure(upn, e);
}
finally
{
_hasUpnSidBeenComputed = true;
}
}
}
}
return _upnSid;
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public static class UpnEndpointIdentityTest
[WcfTheory]
[InlineData("")]
[InlineData("test@wcf.example.com")]
[Issue(1454, Framework = FrameworkID.NetNative)]
public static void Ctor_UpnName(string upn)
{
UpnEndpointIdentity upnEndpointEntity = new UpnEndpointIdentity(upn);
Expand Down

0 comments on commit b3a031c

Please sign in to comment.