163 lines
6.4 KiB
C#
163 lines
6.4 KiB
C#
|
//------------------------------------------------------------
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//------------------------------------------------------------
|
||
|
namespace System.ServiceModel.Activation
|
||
|
{
|
||
|
using System.ComponentModel;
|
||
|
using System.Runtime;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Security;
|
||
|
using System.Security.Principal;
|
||
|
using System.ServiceModel.Activation.Interop;
|
||
|
using System.Threading;
|
||
|
|
||
|
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - All member methods are security critical. The class might be used outside of the restricted SecurityContext." +
|
||
|
"Ensure they do not accidentally satisfy any demands.")]
|
||
|
class HostedImpersonationContext
|
||
|
{
|
||
|
[Fx.Tag.SecurityNote(Critical = "Stores the impersonation token handle. Since we're allowing 'safe' Impersonation of the token we got from asp.net we need to protect this value.")]
|
||
|
[SecurityCritical]
|
||
|
SafeCloseHandleCritical tokenHandle;
|
||
|
|
||
|
[Fx.Tag.SecurityNote(Critical = "Controls lifetime of token handle, caller must use care.")]
|
||
|
[SecurityCritical]
|
||
|
int refCount = 0;
|
||
|
|
||
|
[Fx.Tag.SecurityNote(Critical = "Security critical field, caller must use care.")]
|
||
|
[SecurityCritical]
|
||
|
bool isImpersonated;
|
||
|
|
||
|
[Fx.Tag.SecurityNote(Critical = "Calls two safe native methods under OpenCurrentThreadTokenCritical: GetCurrentThread and OpenThreadToken." +
|
||
|
"Marshal.GetLastWin32Error captures current thread token in a SecurityCritical field.")]
|
||
|
[SecurityCritical]
|
||
|
public HostedImpersonationContext()
|
||
|
{
|
||
|
if (ServiceHostingEnvironment.AspNetCompatibilityEnabled)
|
||
|
{
|
||
|
int error;
|
||
|
bool isSuccess = SafeNativeMethods.OpenCurrentThreadTokenCritical(TokenAccessLevels.Query | TokenAccessLevels.Impersonate,
|
||
|
true, out tokenHandle, out error);
|
||
|
|
||
|
if (isSuccess)
|
||
|
{
|
||
|
isImpersonated = true;
|
||
|
Interlocked.Increment(ref refCount);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CloseInvalidOutSafeHandleCritical(tokenHandle);
|
||
|
tokenHandle = null;
|
||
|
if (error != SafeNativeMethods.ERROR_NO_TOKEN)
|
||
|
{
|
||
|
throw FxTrace.Exception.AsError(new Win32Exception(error, SR.Hosting_ImpersonationFailed));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Fx.Tag.SecurityNote(Critical = "Calls SetHandleAsInvalid which has a LinkDemand for UnmanagedCode.")]
|
||
|
[SecurityCritical]
|
||
|
static void CloseInvalidOutSafeHandleCritical(SafeHandle handle)
|
||
|
{
|
||
|
// Workaround for 64-bit CLR bug VSWhidbey 546830 - sometimes invalid SafeHandles come back null.
|
||
|
if (handle != null)
|
||
|
{
|
||
|
Fx.Assert(handle.IsInvalid, "CloseInvalidOutSafeHandle called with a valid handle!");
|
||
|
|
||
|
// Calls SuppressFinalize.
|
||
|
handle.SetHandleAsInvalid();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public bool IsImpersonated
|
||
|
{
|
||
|
[Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical isImpersonated field.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")]
|
||
|
[SecuritySafeCritical]
|
||
|
get
|
||
|
{
|
||
|
return isImpersonated;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical tokenHandle field and uses LinkDemanded DangerousGetHandle method as well as UnsafeCreate." +
|
||
|
"Caller should use with care, must take responsibility for reverting impersonation.")]
|
||
|
[SecurityCritical]
|
||
|
public IDisposable Impersonate()
|
||
|
{
|
||
|
if (!isImpersonated)
|
||
|
return null;
|
||
|
|
||
|
Fx.Assert(tokenHandle != null, "The token handle was incorrectly released earlier.");
|
||
|
HostedInnerImpersonationContext context = null;
|
||
|
lock (tokenHandle)
|
||
|
{
|
||
|
context = HostedInnerImpersonationContext.UnsafeCreate(tokenHandle.DangerousGetHandle());
|
||
|
GC.KeepAlive(tokenHandle);
|
||
|
}
|
||
|
return context;
|
||
|
}
|
||
|
|
||
|
[Fx.Tag.SecurityNote(Critical = "Controls lifetime of token handle, caller must use care.")]
|
||
|
[SecurityCritical]
|
||
|
public void AddRef()
|
||
|
{
|
||
|
if (IsImpersonated)
|
||
|
{
|
||
|
Interlocked.Increment(ref refCount);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Fx.Tag.SecurityNote(Critical = "Controls lifetime of token handle, caller must use care.")]
|
||
|
[SecurityCritical]
|
||
|
public void Release()
|
||
|
{
|
||
|
if (IsImpersonated)
|
||
|
{
|
||
|
Fx.Assert(tokenHandle != null, "The token handle is incorrectly released earlier.");
|
||
|
int currentCount = Interlocked.Decrement(ref refCount);
|
||
|
if (currentCount == 0)
|
||
|
{
|
||
|
lock (tokenHandle)
|
||
|
{
|
||
|
tokenHandle.Close();
|
||
|
tokenHandle = null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Fx.Tag.SecurityNote(Critical = "Keeps track of impersonated user, caller must use with care and call Dispose at the appropriate time.")]
|
||
|
#pragma warning disable 618 // have not moved to the v4 security model yet
|
||
|
[SecurityCritical(SecurityCriticalScope.Everything)]
|
||
|
#pragma warning restore 618
|
||
|
class HostedInnerImpersonationContext : IDisposable
|
||
|
{
|
||
|
IDisposable impersonatedContext;
|
||
|
|
||
|
HostedInnerImpersonationContext(IDisposable impersonatedContext)
|
||
|
{
|
||
|
if (impersonatedContext == null)
|
||
|
{
|
||
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_ImpersonationFailed));
|
||
|
}
|
||
|
this.impersonatedContext = impersonatedContext;
|
||
|
}
|
||
|
|
||
|
public static HostedInnerImpersonationContext UnsafeCreate(IntPtr token)
|
||
|
{
|
||
|
return new HostedInnerImpersonationContext(HostingEnvironmentWrapper.UnsafeImpersonate(token));
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
if (impersonatedContext != null)
|
||
|
{
|
||
|
impersonatedContext.Dispose();
|
||
|
impersonatedContext = null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|