Archive

Archive for the ‘Advanced’ Category

Implementing restricted access to a WCF service with the ServiceAuthorizationManager

April 7, 2011 6 comments

Introduction

The IT industry divides security into two parts: authentication and authorization. Authentication verifies that a users is who he claims to be. This can be done in a couple of ways: certificates, username/password, windows credentials, … Authorization will decide what an (authenticated) user is allowed to execute. In this article I will describe a generic implementation to authorize access to a WCF service.

Implementing restricted access to a WCF service can be done in a couple of ways. A first option is to mark methods with the declarative PrincipalPermissionAttribute to restrict access to certain roles or users. An other option is to imperatively check the credentials of the current user.

Both of these methods have the drawback that they result in a lot of duplication when you have multiple service methods. Because duplication is the root of all evil, the creators of WCF have foreseen an extension point in WCF to implement authorization in a generic way: the ServiceAuthorizationManager.

Implementation

Implementing a ServiceAuthorizationManager is straightforward; you need to extend the class “ServiceAuthorizationManager” and you need to override the method “CheckAccessCore”. In this small example, I will restrict access to my service to users of the windows group “Administrators”.

public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
    protected override bool CheckAccessCore(OperationContext operationContext)
    {
        try
        {
            ServiceSecurityContext securityContext = operationContext.ServiceSecurityContext;
            WindowsIdentity callingIdentity = securityContext.WindowsIdentity;

            WindowsPrincipal principal = new WindowsPrincipal(callingIdentity);
            return principal.IsInRole("Administrators");
        }
        catch (Exception)
        {
            return false;
        }
    }
}

Now that our custom ServiceAuthorizationManager has been implemented, we need to hook it into the WCF pipeline. The most easy way to do is, by using the web.config or app.config file.

<system.serviceModel>
	<!-- Define service and endpoints -->

	<behaviors>
		<serviceBehaviors>
			<behavior name="MyServiceBehavior">
				<serviceAuthorization serviceAuthorizationManagerType="MyNamespace.MyServiceAuthorizationManager, MyAssembly" />
			</behavior>
		</serviceBehaviors>
	</behaviors>
</system.serviceModel>

Conclusion

When you test your service, you will notice that every method is secured by our custom ServiceAuthorizationManager implementation. I hope that you agree with me, that the ServiceAuthorizationManager is a clean way to implement authorization at the service level.

Categories: Advanced, C#, WCF

Adding support for nested files in custom Visual Studio project types with MPF

March 10, 2011 1 comment

MPF, short for Managed Package Framework, is a great wrapper library to develop custom Visual Studio packages in C#, but it does not seem to cover everything that is possible within Visual Studio 2010. One of the things it does not provide out of the box is support for so called nested files in custom project types: having a “.xaml” file and below it having the corresponding “.xaml.cs” file. The official Visual Studio C# project type has support for this.

related files

Being a motivated programmer, this of course did not prevent me from implementing this functionality myself. In this article I will explain what you need to do in MPF to support this in your custom project types.

First, we need to override the method “AddNewFileNodeToHierarchy” of our ProjectNode implementation.

protected override void AddNewFileNodeToHierarchy(HierarchyNode parentNode, string path)
{
    if (IsRelatedFile(path) && (parentNode is FolderNode || parentNode is ProjectNode))
    {
        for (HierarchyNode child = parentNode.FirstChild; child != null; child = child.NextSibling)
        {
            string childPath = child.Url;
            if (IsParentOfRelatedFile(childPath, path))
            {
                base.AddNewFileNodeToHierarchy(child, path);
                child.Collapse(); // By default the node would be expanded, we don't want that...
                return; // Correct parent found
            }
        }
    }

    // Not a related file or the parent was not found, add using base functionality
    base.AddNewFileNodeToHierarchy(parentNode, path);
}

This new implementation uses a couple of helper functions.

“IsRelatedFile” should return true if the file is related:

private bool IsRelatedFile(string path)
{
    string extension = Path.GetExtension(path).ToLowerInvariant();

    switch (extension)
    {
        case ".diagram":
        case "your related file extensions ...":
            return true;
        default:
            return false;
    }
}

“IsParentOfRelatedFile” should return true if a node is the matching parent for a given related file:

private bool IsParentOfRelatedFile(string parentPath, string path)
{
    string extension = Path.GetExtension(path);

    return path.Equals(parentPath + extension, StringComparison.InvariantCultureIgnoreCase);
}

“Collapse” is an extension method I have created to collapse nodes in Visual Studio. We have to do this, because otherwise the parent of our related node will always be expanded when we add the nodes to the project. This is visually not appealing.

        public static void Collapse(this HierarchyNode node)
        {
            IVsUIHierarchyWindow uiWindow = UIHierarchyUtilities.GetUIHierarchyWindow(node.ProjectMgr.Site,
                HierarchyNode.SolutionExplorer);
            if (uiWindow != null)
            {
                ErrorHandler.ThrowOnFailure(uiWindow.ExpandItem(node.ProjectMgr, node.ID, EXPANDFLAGS.EXPF_CollapseFolder));
            }
        }

With this in place Visual Studio will already add a parent file and is related file correctly in in the Solution explorer of Visual Studio. But you will notice a very annoying behavior: Visual Studio gives our parent file the behavior of folder; double clicking on it will expand or collapse it. Yet in order to mimic the behavior of the standard C# project type, we only want that our parent file is opened in the editor of Visual Studio, not expanded or collapsed. So we have to intercept the double click and enter behavior of our parent node.

To do this, we have to override the method “ExecCommandOnNode” of our FileNode implementation:

protected override int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
{
    if (cmdGroup == VsMenus.guidVsUIHierarchyWindowCmds)
    {
        switch (cmd)
        {
            case (uint)VSConstants.VsUIHierarchyWindowCmdIds.UIHWCMDID_DoubleClick:
            case (uint)VSConstants.VsUIHierarchyWindowCmdIds.UIHWCMDID_EnterKey:
                this.DoDefaultAction();
                return VSConstants.S_FALSE; // We do not want that the node is expanded in the solution view
        }

    }
    return base.ExecCommandOnNode(cmdGroup, cmd, nCmdexecopt, pvaIn, pvaOut);
}

Now our custom project supports nested files! Glimlach

Undocumented parameters of the WCF Service Moniker

March 6, 2011 1 comment

By looking at the .Net assemblies with Reflector, I have found parameters for the WCF service moniker that were not described in the documentation of Microsoft at the moment of writing this article. They can be found in the internal enum “System.ServiceModel.ComIntegration.MonikerHelper.MonikerAttribute”.

MonikerAttribute

I think that the meaning of each attribute should be pretty clear for people with WCF experience. All these attributes can be used as parameters for the WCF service moniker connection string.

  • Address: the address of the WCF service
  • Contract: the name of the contract of the WCF service
  • Wsdl: the complete WSDL of the WCF service
  • SpnIdentity: the expected Server Principal Name (SPN) identity of the WCF service endpoint.
  • UpnIdentity: the expected User Principal Name (UPN) identity of the WCF service endpoint. This is the logon name of the service on the network.
  • DnsIdentity: the dns (or the subject if the dns field is null) of an X.509 certificate used to authenticate the WCF service endpoint.
  • Binding: the binding of the WCF service
  • BindingConfiguration: the name of the binding configuration in the <appname.exe>.config file.
  • MexAddress: the MEX address of the WCF service
  • MexBinding: the MEX binding type of the WCF service
  • MexBindingConfiguration: the name of the mex binding configuration in the <appname.exe>.config file.
  • BindingNamespace: The binding name space of the WCF service.
  • ContractNamespace: The contract name space of the WCF service.
  • MexSpnIdentity: the expected Server Principal Name (SPN) identity of the MEX endpoint of the WCF service
  • MexUpnIdentity: the expected User Principal Name (UPN) identity of the MEX endpoint of the WCF service. This is the logon name of the service on the network.
  • MexDnsIdentity: the dns (or the subject if the dns field is null) of an X.509 certificate used to authenticate the MEX endpoint of the WCF service.
  • Serializer: the serializer to use (the DataContract serializer or the old XML serializer)
Categories: Advanced, C#, WCF

Retrieving the client certificate from an X509Identity in WCF

January 28, 2011 2 comments

Please note: This article is merely a demonstration, I absolutely do not recommend relying on internal classes of the .Net framework in real applications.

WCF can be configured for two mayor modes of security:

  • Transport security
  • Message security
  • (And you actually also have the in between TransportWithMessageCredential, but lets forget this for simplicity …)

In both of these modes WCF can be configured to use X509 certificates as client and service credentials. At the service side, WCF maps these credentials to an IIdentity instance that can be retrieved using the ServiceSecurityContext.

IIdentity identity = ServiceSecurityContext.Current.PrimaryIdentity;

The implementation type of this identity is the internal class  System.IdentityModel.Claims.X509Identity. If we look at this type using reflector we can see the following:

Inspect X509Identity using Reflector

The X509Identity contains the X509 client certificate inside a private variable “certificate”. Using reflection, we can easily retrieve this certificate:

private X509Certificate2 ClientCertificate
{
    get
    {
        try
        {
            IIdentity identity = ServiceSecurityContext.Current.PrimaryIdentity;

            // X509Identity is an internal class, so we cannot directly access it
            Type x509IdentityType = identity.GetType();

            // The certificate is stored inside a private field of this class
            FieldInfo certificateField = x509IdentityType.GetField("certificate", BindingFlags.Instance | BindingFlags.NonPublic);

            return (X509Certificate2)certificateField.GetValue(identity);
        }
        catch (Exception)
        {
            return null;
        }
    }
}

Using this property we can now retrieve the client certificate. This was not that difficult to do? Glimlach

Categories: Advanced, C#, WCF