WCF Security - WCF Multi-layer Services Development with Entity Framework Fourth Edition (2014)

WCF Multi-layer Services Development with Entity Framework Fourth Edition (2014)

Chapter 12. WCF Security

At this point, we have learned how to develop a three-layer WCF service with LINQ to Entities. To further enhance our WCF service, in this chapter we will explore the security settings of a WCF service. We will host our HelloWorld WCF service using the basic and the Windows authentication with the HTTPS protocol.

We will cover the following topics in this chapter:

· WCF security components

· Hosting a WCF service with basic authentication

· Hosting the WCF service with Windows authentication

WCF security components

WCF security spans multiple components in the WCF architecture. The main aim of security in WCF is to provide integrity, confidentiality, authentication, authorization, and audit for the applications that are built on top of the WCF framework. A good WCF architecture splits these functions into the following pieces:

· Transfer security: This is responsible for providing message confidentiality, data integrity, and the authentication of communicating parties

· Authorization: This is responsible for providing a framework to make authorization decisions

· Auditing: This is responsible for logging the security-related events to the audit log

In this section, we will cover WCF authorization and auditing briefly; in the next section, we will discuss WCF transfer security in detail.

WCF authorization

Authorization is the process of controlling access and rights to resources, such as services or files. Unlike WCF service authentication, which is usually handled automatically by the communication framework, for WCF service authorization you will have to come up with your own strategy and infrastructure. You can choose one of the following authorization types to implement an authorization for your WCF service:

· Role-based: The user is authorized based on his/her role membership. Users belonging to the same role will share the same security privileges within the application.

· Identity-based: The identity model is an extension of the role-based authorization. The identity model enables you to manage claims and policies in order to authorize clients. You can verify claims contained within the users' credentials and compare the claims with a set of authorization policies to determine whether the user is authorized for an operation.

· Resource-based: Windows access control lists (ACLs) are used to secure individual resources. The caller will be impersonated, and the operating system will perform standard access checks using the original caller's security context when a resource is accessed.

Between these three methods, identity/claims is now preferred for WCF authorization. Starting from .NET 4.5, Windows Identity Foundation (WIF) makes it even easier to implement a claims-aware WCF service. For more information on WIF, you can refer tohttp://msdn.microsoft.com/en-us/library/hh291066(v=vs.110).aspx.

In this book, we will not discuss WCF service authorization any further, as it is fundamentally the same as the authorizations of any other type of application.

WCF auditing

WCF applications can log security events (success, failure, or both) by using the auditing feature. The events are written to the Windows system event log and can be examined using Event Viewer.

The benefits of WCF auditing include the following:

· Audits security events such as authentication and authorization failures

· Detects attacks that have occurred or that are in progress

· Helps debug security-related problems

You can configure the WCF service's security logging through the ServiceSecurityAudit behavior in the service configuration file. You can specify security audit levels for both message authentication and service authorization events.

For example, the following behavior configuration will enable a security audit for all events, for both the authorization and authentication of a WCF service:

<behavior name = "MySecurityAudit">

<serviceSecurityAudit auditLogLocation = "Default"

serviceAuthorizationAuditLevel = "SuccessOrFailure"

messageAuthenticationAuditLevel = "SuccessOrFailure" />

</behavior>

WCF transfer security

In the rest of this chapter, we will focus on the transfer security part of WCF services. We will discuss WCF's transport-level and message-level security, transfer security modes supported by various bindings, and WCF authentications.

WCF security modes

WCF transfer security is also referred to as a security mode. There are two transfer security levels for WCF services—transport level and message level. You can also mix these two levels to create a mixed-level security mode.

The WCF security modes that are available are none, transport, message, both (transport and message), mixed (TransportWithMessageCredential, and TransportCredentialOnly).

Not every WCF binding supports every security mode. For example, basicHttpBinding supports transport, message, or mixed security modes, but not both, while netNamedPipeBinding only supports transport-level security (or none). The following table lists the most common bindings and their supported security modes:

Binding name

None

Transport

Message

Mixed

Both

basicHttpBinding

Yes (default)

Yes

Yes

Yes

No

netTCPBinding

Yes

Yes (default)

Yes

Yes

No

netNamedPipeBinding

Yes

Yes (default)

No

No

No

wsHttpBinding or

ws2007HttpBinding

Yes

Yes

Yes (default)

Yes

No

wsFederationHttpBinding

Yes

No

Yes (default)

Yes

No

wsDualHttpBinding

Yes

No

Yes (default)

No

No

netMsmqBinding

Yes

Yes (default)

Yes

No

Yes

WCF transport security

WCF transport security is applied at the transport level on the byte stream below the message layer. In this case, a message does not have a security header and it does not carry any user authentication data. The transport security mode only provides point-to-point security between two endpoints, and it is the least flexible in terms of WS-Security usage because it is highly dependent on the transport layer. However, the transport security mode is the fastest in terms of performance and it gives the best interoperability with client applications.

The most common approach for the transport security mode is to combine it with Secure Sockets Layer (SSL) or HTTPS to encrypt and sign the contents of all the packets. We will secure a WCF service with transport security and SSL in the later sections of this chapter.

WCF message security

WCF message security is applied on the message level. With message security, the user credentials and claims are encapsulated in every message. The message security mode provides end-to-end security and it provides high flexibility from an authentication perspective. Since messages are directly encrypted and signed, having intermediaries does not break the security. You can use any type of authentication credentials you want; it is largely independent of the transport layer as long as both the client and the server agree.

WCF mixed security

WCF mixed security gives you the best of both transport security and message security. In this case, WCF transport security ensures the integrity and confidentiality of the messages, while WCF message security encapsulates the user credentials and claims in each message. The WCF mixed security mode allows you to use a variety of user credentials that are not possible when using strict transport security mechanisms, while leveraging transport security's performance.

WCF transport and message security

When WCF transport security and WCF message security are combined, the user credentials and claims are transferred at both transport layer and within the message. Similarly, message protection is provided at the transport layer and within the message. Note that this is not a common scenario, and the Microsoft Message Queuing (MSMQ) binding is the only binding that supports this mode.

Authentication options for transport security

The WCF authentication options depend on the transfer security mode being used. For this reason, the authentication choices are partly determined by the transfer security mode. The following are the available authentication options for the transport security mode:

· None: When using the None option, callers are not authenticated at all.

· Basic: The Basic option is available only with the HTTP protocol. The client is authenticated using the username and password against the Microsoft Active Directory service. Note that the username and password are transported using a Base64 encoded string, which is very similar to a clear string. Therefore, this is not a secure option at all if used by itself.

· NTLM: The NTLM option is also available with the HTTP protocol only. The client is authenticated using a challenge-response scheme against Windows accounts. NTLM authentication is well-suited for a workgroup environment and is more secure than basic authentication.

· Windows: When using the Windows option, the WCF service uses Kerberos authentication in a domain or the NTLM authentication when deployed in a workgroup environment. This option uses a Windows token presented by the caller to authenticate against the Active Directory. This is the most secure option compared to basic or NTLM authentication.

· Certificate: When using the Certificate option, the caller presents an X.509 client certificate that the WCF service validates by trusting the certificate (peer trust) or trusting the issuer of the certificate (chain trust). This option should be considered only when Windows authentication is not possible, as in the case of business-to-business (B2B) scenarios.

Authentication options for message security

For WCF services using the message security mode, authentication choices are different from the services using the transport security mode. The following are the available authentication options for the message security mode:

· None: When using the None option, callers are not authenticated at all.

· Windows: When using the Windows option, the WCF service uses Kerberos authentication when in a domain or the NTLM authentication when deployed in a workgroup environment. The Windows option uses the Windows token presented by the caller to authenticate against the Active Directory.

· Username: When using the Username option, the caller provides a username and password to the service. The service can then authenticate the caller against their Windows credentials or use a membership provider. This option should be considered only when Windows authentication is not possible.

· Certificate: When using the Certificate option, the caller presents an X.509 client certificate. The WCF service looks up the certificate information on the host side and validates it (peer trust) or trusts the issuer of the client certificate (chain trust). This option should be considered only when Windows authentication is not possible.

· Issue Token: When using the Issue Token option, the client and service depend on the Secure Token Service (STS) to issue tokens that the client and service trust.

Hosting a WCF service using basic authentication

In the previous sections, we learned the basic concepts and theories about WCF security. Now, we will do some practical work. We will host a WCF service with basic authentication and then consume this service in a client application.

Since with basic authentication the username and password are transmitted in a Base64 encoded text, SSL will be configured with this authentication mode to enhance the security of the service.

To keep the code simple and to focus only on the security side of the WCF service, HelloWorldService and HelloWorldClient will be used for this practice.

Setting up the service

First, we will set up a copy of HelloWorldService with no authentication. We will enhance this service, as shown in the following sections, to enable basic authentication and host it with the HTTPS protocol.

To set up the service, follow these steps:

1. You can refer to Chapter 1, Implementing a Basic HelloWorld WCF Service, and Chapter 2, Hosting the HelloWorld WCF Service, to get the HelloWorld solution ready.

2. Create a new folder, HostIISSecure, under C:\SOAwithWCFandEF\Projects\HelloWorld\.

3. Copy all the files from HostIIS to this new folder.

4. Start the IIS manager and add a new application, HelloWorldServiceSecure, pointing to this new folder.

5. Test it with this URL in a browser: http://localhost/HelloWorldServiceSecure/HelloWorldService.svc.

You should see the WSDL description page of HelloWorldService. Click on the link to make sure that you can get the WSDL code of this new service.

Enabling the Basic Authentication feature

Basic Authentication is a feature of Internet Information Service. By default, the module is not installed. In this section, we will install and enable this feature:

1. Open Control Panel.

2. Go to Programs | Turn Windows features on or off.

3. Now the Windows Features dialog window should pop up.

4. Navigate to Internet Information Services | World Wide Web Service | Security.

5. Check Basic Authentication.

6. Note that Windows Authentication is unchecked for now, as shown in the following screenshot. Later in this chapter, we will learn how to host this same WCF service with Windows authentication, in which case you will need to come back to this same place and check theWindows Authentication option:

Enabling the Basic Authentication feature

Configuring basic authentication on IIS

Now, the Basic Authentication feature is enabled on the computer, but the IIS application is still not using it. We need to configure the HelloWorldServiceSecure application to be authenticated with this feature, as follows:

1. Start the IIS manager.

2. Select the HelloWorldServiceSecure application.

3. In the Features View panel, double-click on Authentication:

Configuring basic authentication on IIS

4. In the Authentication panel, disable Anonymous Authentication and enable Basic Authentication. If you don't see the Basic Authentication option on your screen, close the IIS manager and then start it again to refresh the authentication options. The authentication of the service should be configured as shown in the following screenshot (anonymous authentication must be disabled because when negotiating with the server, most browsers will try for anonymous authentication first):

Configuring basic authentication on IIS

5. If your computer is within a domain while the Basic Authentication node is still selected, click on the Edit button in the right-hand side panel and enter your domain name in both the Default domain and Realm boxes (You should enter your domain name here (normally, your company's name), not your computer name. For example, if your computer's full address is pcNameA.companyNameB.com, enter companyNameB here.):

Configuring basic authentication on IIS

Now, if you browse to the original service address, you will be prompted to enter your credentials. After you have entered your Windows credentials, you will get an error as The authentication schemes configured on the host ('Basic') do not allow those configured on the binding 'BasicHttpBinding' ('Anonymous'). This is because the HelloWorldServiceSecure service is still configured to communicate using anonymous authentication. Next, we will modify the service configuration file to use basic authentication instead.

Configuring the HTTPS protocol

Before we modify the service configuration file, we need to do more on the IIS site. We will enable the HTTPS protocol for our website so that the client can communicate with our service via the HTTPS protocol. This is especially important for basic authentication, since with basic authentication, the username and password are transmitted in Base64 encoded text, which can be easily decoded to clear text.

To configure HTTPS for our service, follow these steps:

1. Start the IIS manager.

2. Select the root node in the left-hand side panel (it should be your computer's name).

3. Double-click on Server Certificates in the middle panel:

Configuring the HTTPS protocol

4. On the right-hand side, in the Actions panel, click on the Create Self-Signed Certificate… link:

Configuring the HTTPS protocol

5. The Create Self-Signed Certificate dialog window should appear on your screen. Specify a name, MyTestCert, for the certificate and click on the OK button to close the dialog window.

6. In the IIS manager, select the website of the HelloWorldServiceSecure application. By default, this should be Default Web Site. Make sure you select the website, not the HelloWorldServiceSecure application, as the binding settings apply to the whole website.

7. On the right-hand side, in the Actions panel, click on the Bindings… link.

8. If https is not in the list of the binding types, click on the Add button, or else select https from the list and click on Edit.

9. On the Add Site Binding/Edit Site Binding dialog window, specify the test certificate in the SSL certificate field:

Configuring the HTTPS protocol

10.Click on the OK button to close the Add Site Binding dialog window and then click on the Close button to close the Site Bindings dialog window.

11.The bindings of your website should be similar to those shown in the following screenshot:

Configuring the HTTPS protocol

In your staging and production environments, you should create a signed certificate from a Certificate Authority such as VeriSign. Moreover, if SSL brings too much overhead in development time, you can host your service without SSL. It is recommended that you turn it on for security purposes when the service is deployed to the staging and production environments.

Configuring basic authentication on the service

Now, IIS is configured to use basic authentication, but the service is not. We need to configure the HelloWorldService service to be authenticated with the basic authentication:

1. Open the HelloWorld solution.

2. Add a new solution folder, HostIISSecure, to the solution.

3. Add the C:\SOAwithWCFandEF\Projects\HelloWorld\HostIISSecure\Web.config file to the new solution folder.

4. Add another solution folder, bin, under the HostIISSecure solution folder.

5. Add all the files under the C:\SOAwithWCFandEF\Projects\HelloWorld\HostIISSecure\bin folder to this new solution folder.

6. Open the properties of the HelloWorldService project and add the following statements to the post-built event of the project. This will make sure that the HelloWorldServiceSecure application will always have the latest service binary files as other hosting applications:

7. xcopy "$(AssemblyName).dll" "C:\SOAwithWCFandEF\Projects\HelloWorld\HostIISSecure\bin" /Y

xcopy "$(AssemblyName).pdb" "C:\SOAwithWCFandEF\Projects\HelloWorld\HostIISSecure\bin" /Y

7. Now, open the Web.config file within the HostIISSecure solution folder and make the following changes to this file:

o Change the service metadata attribute from httpGetEnabled to httpsGetEnabled.

o Add the following services node just after the behaviors node. This will define an endpoint with our specific binding configuration:

o <services>

o <service name="HelloWorldService.HelloWorldService">

o <endpoint address="" binding="basicHttpBinding"

o contract="HelloWorldService.IHelloWorldService"

o bindingConfiguration="secureHttpBinding">

o <identity>

o <dns value="localhost" />

o </identity>

o </endpoint>

o <endpoint address="mex" binding="mexHttpBinding"

o contract="IMetadataExchange" />

o </service>

</services>

o Add the following bindings node just after the new node that we just added. This will define the binding with basic authentication:

o <bindings>

o <basicHttpBinding>

o <binding name ="secureHttpBinding">

o <security mode="Transport">

o <transport clientCredentialType="Basic" />

o </security>

o </binding>

o </basicHttpBinding>

</bindings>

o Now, the system.serviceModel node should have four child nodes: serviceHostingEnvironment (existing node), behaviors (existing node), services (new node), and bindings (new node).

o Save your Web.config file.

In your Web.config file, the system.serviceModel node should be as follows:

<system.serviceModel>

<serviceHostingEnvironment >

<serviceActivations>

<add factory="System.ServiceModel.Activation.ServiceHostFactory"

relativeAddress="./HelloWorldService.svc"

service="HelloWorldService.HelloWorldService"/>

</serviceActivations>

</serviceHostingEnvironment>

<behaviors>

<serviceBehaviors>

<behavior>

<serviceMetadata httpsGetEnabled="true"/>

</behavior>

</serviceBehaviors>

</behaviors>

<services>

<service name="HelloWorldService.HelloWorldService">

<endpoint address="" binding="basicHttpBinding"

contract="HelloWorldService.IHelloWorldService"

bindingConfiguration="secureHttpBinding">

<identity>

<dns value="localhost" />

</identity>

</endpoint>

<endpoint address="mex" binding="mexHttpBinding"

contract="IMetadataExchange" />

</service>

</services>

<bindings>

<basicHttpBinding>

<binding name ="secureHttpBinding">

<security mode="Transport">

<transport clientCredentialType="Basic" />

</security>

</binding>

</basicHttpBinding>

</bindings>

</system.serviceModel>

The service is now ready. You can go to https://[your_pc_name]/HelloWorldServiceSecure/HelloWorldService.svc and see the WSDL of the service.

You will be prompted to enter your credentials. You should then enter your Windows login credentials here.

Note

If you go to https://localhost/HelloWorldServiceSecure/HelloWorldService.svc (using localhost instead of your PC name in the URL), you will get a warning: The security certificate presented by this website was issued for a different website's address. You can ignore this warning and still see the WSDL of the service. However, in one of the following sections, when you add the service reference, you must use your PC name instead of localhost.

On the service WSDL page, you should see the following XML node:

<http:BasicAuthentication xmlns:http="http://schemas.microsoft.com/ws/06/2004/policy/http"/>

This means that the service is now secured by basic authentication.

Testing the service with basic authentication

To test the secured service, we need a test client. In this section, we will create a console application to test the secured service:

1. Add a console application project, HelloWorldClientSecure, to the solution.

2. Right-click on the new project and select Add | Service Reference… from the context menu.

3. Enter https://[your_pc_name]/HelloWorldServiceSecure/HelloWorldService.svc as the address and HelloWorldServiceRef as the namespace. You will be prompted to enter your credentials. Enter your Windows login credentials here.

If you get an error saying An error (Details) occurred while attempting to find service and the error details are Metadata contains a reference that cannot be resolved, you might need to give your IIS identity proper access rights to your C:\Windows\Temp directory.

You might be prompted to enter your credentials up to three times while Visual Studio is trying to discover or enumerate all the services for the desired name on your machine. In my environment, it was trying to discover the service at three places:HelloWorldService.svc/_vti_bin/ListData.svc/$metadata, HelloWorldService.svc/$metadata, and HelloWorldService.svc.

If you are prompted more than three times for your credentials and you still cannot add the service reference, make sure you are using the correct URL for the service. You might need to replace localhost with the system name of your PC, or you might need to include your domain name in the URL. This is because the host part of the URL must match the Issued to part of the self-signed certificate. You can open your certificate (from the IIS manager) to see the exact party name that this certificate is issued to and use this in your URL. In the following screenshot, the computer is not in a domain, so in this case, Issued to is the same as the computer name. If it is within a domain, the Issued to field should look similar to MyLaptop.domain_name.com. In this case, you should use MyLaptop.domain_name.com in the URL.

Testing the service with basic authentication

If your computer is within a domain, you also need to make sure that you have set your default domain and realm in your bindings settings. You can refer to the previous section, Configuring the HTTPS protocol, for more details.

4. Now, open the Program.cs file and add the following code to the Main method (remember to replace the user's credentials with your own):

5. var client =

6. new HelloWorldServiceRef.HelloWorldServiceClient();

7. client.ClientCredentials.UserName.UserName = "your_user_name";

8. client.ClientCredentials.UserName.Password = "your_password";

Console.WriteLine(client.GetMessage("Basic Authentication caller"));

5. Set the HelloWorldClientSecure project as the startup project and run the program. You should get an output that looks similar to the output shown in the following screenshot:

Testing the service with basic authentication

Hosting a WCF service with Windows authentication

In the previous sections, we learned how to host a WCF service with basic authentication. As you can see, with basic authentication, the client has to capture the user's credentials (the credentials are hardcoded, taken from a configuration file, or the user is prompted to enter them), and the credentials are transported in clear text unless HTTPS is configured.

This might be an acceptable approach if the clients are outside your domain, that is, from the Internet or extranet. However, for intranet clients, a better approach is to use Windows authentication so that you don't need to capture the user's credentials. Instead, you can use the user's network credential token and pass it to the WCF service. In this section, we will configure our WCF service to use this authentication mode.

As we have the IIS application and the test client for basic authentication ready, we will just modify them to enable Windows authentication. We can do this as follows:

1. Go to Control Panel | Programs and Features | Turn Windows features on or off and check Windows Authentication under Internet Information Services | World Wide Web Services | Security. See the previous section in this chapter (Enabling the Basic Authentication feature) for a screenshot.

Note

Windows authentication is not supported on the Windows Home version. You need to have Professional or above to have this option. You can go to Control Panel | System and Security | System to check your Windows version.

2. Go to IIS manager | HelloWorldServiceSecure | Authentication, disable Basic Authentication and enable Windows Authentication. If Windows Authentication is not in the list, close the IIS manager and then reopen it.

3. Start Visual Studio, open the Web.config file located under the HostIISSecure folder, and change the attribute value of clientCredentialType in the binding node from Basic to Windows.

4. Save the configuration file.

5. Expand the Service References folder in the HelloWorldClientSecure project, right-click on the HelloWorldServiceRef item, and select Update Service Reference from the context menu. The service reference will be updated without asking for additional credentials. This is because we are now using Windows authentication, so your current login token is passed to the service.

6. Open the client's config file, App.config, in the HelloWorldClientSecure project to verify that the attribute value of clientCredentialType in the binding node has been changed from Basic to Windows.

7. Open the Program.cs file in the HelloWorldClientSecure project and change the old code in the Main method as follows:

8. var client =

9. new HelloWorldServiceRef.HelloWorldServiceClient();

10.client.ChannelFactory.Credentials.Windows.ClientCredential =

11. System.Net.CredentialCache.DefaultNetworkCredentials;

Console.WriteLine(client.GetMessage("Windows Authentication caller"));

8. Run the program again and you should get an output similar to the one shown in the following screenshot:

Hosting a WCF service with Windows authentication

This output shows that the service is now hosted with Windows authentication and the client is passing the user's default network credential to the service. The current logged-in user's Windows token, instead of the user's name/password, is now transmitted over the network.

Note

Besides setting the attribute value of clientCredentialType to Windows or Basic in the binding node of the service web configuration file, you can also set it to InheritedFromHost, which means that the WCF service will inherit the security settings of the hosting IIS application. This option will be very helpful if you would like to specify multiple authentication schemes on a single endpoint.

Summary

In this chapter, we learned the basic concepts of WCF security and hosted the HelloWorld service using basic authentication and Windows authentication. The .NET Framework gives you a variety of configuration settings for WCF security. You should examine your WCF service needs and pick the most appropriate settings for your organization.

In the next chapter, we will explore the basic concepts of WCF extension points and learn how to extend our HelloWorld service.