Unit Testing WCF Security with Castles WcfFacility
Building off David Tchepak’s post “Faking WCF Authentication”, here’s some code to override the Service Host creation when using the Castle WcfFacility.
The main integration points are a custom IWcfServiceModel and IServiceHostBuilder using the custom model. Both points have abstract base classes to build from. The model in this case is just an empty class used by the facility for finding the builder.
public class TestSecurityServiceModel : WcfServiceModel<TestSecurityServiceModel>
{
}
The service host builder is where we inject the authorization data we want available in our services. This host and authorization code are from David’s post, check out that for the TestAuthPolicy, TestPrincipal, and TestIdentity code. Here’s the builder.
public class SecurityDefaultServiceHostBuilder : AbstractServiceHostBuilder<TestSecurityServiceModel>
{
public SecurityDefaultServiceHostBuilder(IKernel kernel)
: base(kernel)
{
}
protected override ServiceHost CreateServiceHost(ComponentModel model, TestSecurityServiceModel serviceModel, params Uri[] baseAddresses)
{
return CreateServiceHost(model, GetEffectiveBaseAddresses(serviceModel, baseAddresses));
}
protected override ServiceHost CreateServiceHost(ComponentModel model, Uri[] baseAddresses)
{
return InjectAuthorizationPolicies(new DefaultServiceHost(model, baseAddresses));
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return InjectAuthorizationPolicies(new DefaultServiceHost(serviceType, baseAddresses));
}
private static ServiceHost InjectAuthorizationPolicies(ServiceHost host)
{
host.Authorization.ExternalAuthorizationPolicies
= new List<IAuthorizationPolicy> { new TestAuthPolicy() }.AsReadOnly();
host.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
return host;
}
}
It’s creating an instance of the DefaultServiceHost and added the authorization properties needed before returning the created service host.
Lastly, we need to integrate this with the WcfFacility. This is don’t at two points, first we need to tell the facility about our custom building and model with the AddServiceHostBuilder method.
var facility = new WcfFacility();
_container.AddFacility("wcf", facility);
facility.Services.AddServiceHostBuilder<SecurityDefaultServiceHostBuilder, TestSecurityServiceModel>();
Then when registering a service we set the ActAs model to the new TestSecurityServiceModel. This tells the facility to use the SecurityDefaultServiceHostBuilder to the service host.
Component.For<IService>()
.ImplementedBy<Service>()
.Named("MyService")
.ActAs(new TestSecurityServiceModel()
.AddEndpoints(
WcfEndpoint.BoundTo(new NetTcpBinding { PortSharingEnabled = true })
.At(MyServiceAddress))),
Now, when a client channel connects to this service the service host will be built by the new builder and have the authorization data needed to test the service.
IService client = ChannelFactory<IService>.CreateChannel(
new NetTcpBinding { PortSharingEnabled = true }, new EndpointAddress(MyServiceAddress));
client.ServiceCall(1);
This was used for unit/integration tests, but could be used to simply extend the service host when used in the WcfFacility.
Webmentions
These are webmentions via the IndieWeb and webmention.io. Mention this post from your site: