//------------------------------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//----------------------------------------------------------------------------------------------------
namespace System.ServiceModel.Security
{
using System.Runtime;
using System.Security;
using System.Security.Principal;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Diagnostics;
///
/// The helper class to enable impersonation while serializing the body of the reply message.
///
public class ImpersonateOnSerializingReplyMessageProperty : IMessageProperty
{
const string PropertyName = "ImpersonateOnSerializingReplyMessageProperty";
MessageRpc rpc;
internal ImpersonateOnSerializingReplyMessageProperty(ref MessageRpc rpc)
{
this.rpc = rpc;
}
///
/// Gets the name of the message property.
///
public static string Name
{
get { return PropertyName; }
}
///
/// Gets the ImpersonateOnSerializingReplyMessageProperty property from a message.
///
/// The message to extract the property from.
/// An output paramter to hold the ImpersonateOnSerializingReplyMessageProperty property.
/// True if the ImpersonateOnSerializingReplyMessageProperty property was found.
public static bool TryGet(Message message, out ImpersonateOnSerializingReplyMessageProperty property)
{
if (message == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
}
return TryGet(message.Properties, out property);
}
///
/// Gets the ImpersonateOnSerializingReplyMessageProperty property from MessageProperties.
///
/// The MessagePropeties object.
/// An output paramter to hold the ImpersonateOnSerializingReplyMessageProperty property.
/// True if the ImpersonateOnSerializingReplyMessageProperty property was found.
public static bool TryGet(MessageProperties properties, out ImpersonateOnSerializingReplyMessageProperty property)
{
if (properties == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("properties");
}
object value = null;
if (properties.TryGetValue(PropertyName, out value))
{
property = value as ImpersonateOnSerializingReplyMessageProperty;
}
else
{
property = null;
}
return property != null;
}
///
/// Creates a copy of the message property.
///
/// Returns a copy of the message property.
public IMessageProperty CreateCopy()
{
ImpersonateOnSerializingReplyMessageProperty result = new ImpersonateOnSerializingReplyMessageProperty(ref this.rpc);
return result;
}
///
/// Starts Impersonating with the caller's context if impersonation is enabled on the service and sets the appropriate principal on the thread as per the service configuration.
///
/// The impersonated context.
/// The original principal on the thread before invoking this method.
/// The value determines if the principal was set on the thread by the method.
/// Returns false if operation context was not available to impersonate.
[Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method StartImpersonation.", Safe = "Manages the result of impersonation and properly Disposes it.")]
[SecuritySafeCritical]
public void StartImpersonation(out IDisposable impersonationContext, out IPrincipal originalPrincipal, out bool isThreadPrincipalSet)
{
impersonationContext = null;
originalPrincipal = null;
isThreadPrincipalSet = false;
if (OperationContext.Current != null)
{
EndpointDispatcher endpointDispatcher = OperationContext.Current.EndpointDispatcher;
if (endpointDispatcher != null)
{
DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
ImmutableDispatchRuntime runtime = dispatchRuntime.GetRuntime();
if (runtime != null && runtime.SecurityImpersonation != null)
{
runtime.SecurityImpersonation.StartImpersonation(ref this.rpc, out impersonationContext, out originalPrincipal, out isThreadPrincipalSet);
}
}
}
}
///
/// Reverts impersonation and sets the original principal on the thread.
///
/// The impersonation context to revert.
/// The original principal to set on the thread.
/// The value determines if the thread principal was set during impersonation.
/// Returns false if operation context was not available to revert the impersonation.
[Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method StartImpersonation.", Safe = "Manages the result of impersonation and properly Disposes it.")]
[SecuritySafeCritical]
public void StopImpersonation(IDisposable impersonationContext, IPrincipal originalPrincipal, bool isThreadPrincipalSet)
{
if (OperationContext.Current != null)
{
EndpointDispatcher endpointDispatcher = OperationContext.Current.EndpointDispatcher;
if (endpointDispatcher != null)
{
DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
ImmutableDispatchRuntime runtime = dispatchRuntime.GetRuntime();
if (runtime != null && runtime.SecurityImpersonation != null)
{
runtime.SecurityImpersonation.StopImpersonation(ref this.rpc, impersonationContext, originalPrincipal, isThreadPrincipalSet);
}
}
}
}
}
}