Home » ASP » ASP.MVC » How to add active directory (AD) security to WCF services with attribute?

How to add active directory (AD) security to WCF services with attribute?

If you are using WCF web services with active directory (AD) you may want to have a more atomic authorization process than setting the security by IIS. You may want to allow for specific method some group when some other may only have access to others.

The first step is to create a custom attribute. This example show you how to add a single role but you could modify this code to allow multiple roles.

public class SecureOperationAttribute : Attribute, IOperationBehavior
{
	public string Role { get; set; } 
	public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters){}
	public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)	{	}
	public void Validate(OperationDescription operationDescription)	{}
	public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
	{

		dispatchOperation.Invoker = new SecureOperationInvoker(Role, dispatchOperation);
	}
}

Once the attribute is set you need to create the invoker.

public class SecureOperationInvoker : IOperationInvoker
{
	private readonly IOperationInvoker _baseInvoker;
	private readonly string _operationName;
	private readonly string _role;

	public SecureOperationInvoker(string  role, DispatchOperation operation)
	{
		_role = role;
		_baseInvoker = operation.Invoker;
		_operationName = operation.Name;
	}

	public object Invoke(object instance, object[] inputs, out object[] outputs)
	{
		if (!UserIsInRole(_role))
		{
			throw new FaultException(string.Format("Authentification fail. The operation '{0}' requires the role '{1}'.", _operationName, _role),									new FaultCode("Authentification"));
		}
		return _baseInvoker.Invoke(instance, inputs, out outputs);
	}

	public object[] AllocateInputs()
	{
		return _baseInvoker.AllocateInputs();
	}

	public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
	{
		return _baseInvoker.InvokeBegin(instance, inputs, callback, state);
	}

	public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
	{
		return _baseInvoker.InvokeEnd(instance, out outputs, result);
	}

	public bool IsSynchronous
	{
		get
		{
			return _baseInvoker.IsSynchronous;
		}
	}
	
	public bool UserIsInRole(string role)
    {
        var winPrinc = new WindowsPrincipal(OperationContext.Current.ServiceSecurityContext.WindowsIdentity);
        return winPrinc.IsInRole(role);
    }
}

Of course, this example a small representation of what should have been done in a real system. In fact, the UserIsInRole shouldn’t be hardcoded to use WindowsPrincipal. It should be injected to be able to test without having to use WindowsPrincipal. Also, the role variable may in fact not be exactly the name of the active directory (AD) group, so you may need to inject also a mechanism to translate the role used by the attribute to the AD group.

Here is how to use the attribute over your WCF contract.

[ServiceContract]
public interface IMyEntityXYZ
{
	[OperationContract]
	[SecureOperation(Role = "Admin")]
	void Action(DTOXYZ[] xyz);
}

What I like is that you can set the security on the contract. It’s simple for the maintenance cause the operation signature contains who has access the the method defined. It’s also easy to test if you are using injection to create a stub method for the validation of the role.

If you like my article, think to buy my annual book, professionally edited by a proofreader. directly from me or on Amazon. I also wrote a TypeScript book called Holistic TypeScript

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.