Invoking WCF Service Secured With Basic Authentication Using SoapUI
In this post, the author will demonstrate, with examples, how to use the SoapUI API tool to invoke a secured WCF SOAP service.
Join the DZone community and get the full member experience.
Join For FreeIn this post, we will demonstrate how to use the SoapUI API tool to invoke a secured WCF SOAP service. First, we will create a service where it will be the system under test. Next, we will approach the steps required to invoke the created service while secured by a basic authentication mechanism.
WCF Basic Authentication Service
The access to the resource in the service to be implemented will be secured using Basic Authentication transport security mechanisms. One of many provided by the Windows Communication Foundation. This kind of mechanism is used in conjunction with HTTPS to provide confidentiality.
This service exposes one endpoint that calculates a very big sum. To get started quickly, we will use the default template of the WCF Service Application provided in Visual Studio 2019.
From Menu File, New, then Project, or click on Start Page to start a new project. Let’s name the solution and the project to AVeryBigSum_BasicAuthentication.
Now you’ll see a couple of files already added to the WCF Service project. We have the option to delete the interface IService1.cs and service Service1.svc file to create new ones. Otherwise, we can rename both files, therefore, pay attention to renaming as well as the markup of the Service1.svc file by right clicking on it -> View Markup and changing to that below.
xxxxxxxxxx
<% ServiceHost Language="C#" Debug="true"
Service="AVeryBigSum_BasicAuthentication.Avbs" CodeBehind="Avbs.svc.cs" %>
After renaming both files, open the IAvbs.cs, copy the following code and add it to the modified interface.
xxxxxxxxxx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace AVeryBigSum_BasicAuthentication
{
[ServiceContract]
public interface IAvbs
{
[OperationContract]
long AVeryBS(long[] ar);
}
}
In case you choose to delete those files, you can add a new interface by right-clicking on the project and Add new item. Select the Interface template and rename it to IAvbs. As well you need to copy the code above and add it to the newly created interface.
The service implements only one operation defined in the interface contract. To implement it, we need to modify the default file created by VStudio or add a new service class Avbs.svc, which will implement the above-defined interface.
xxxxxxxxxx
using System;
/*...*/
namespace AVeryBigSum_BasicAuthentication
{
public class Avbs : IAvbs
{
public long AVeryBS(long[] ar)
{
long aVeryBigSum = 0;
foreach (long i in ar) aVeryBigSum += i;
return aVeryBigSum;
}
}
}
So far, we have defined a service contract, an operation with a sample definition. Now we have to define its endpoints. To add an endpoint, we need to change the configuration file (web.config). Apart from copying and pasting, we need to understand the importance of each of these WCF tags.
AppSettings
Hence, let's start with the AppSettings element. This element contains custom application settings. The element stores custom application configuration information, such as database connection strings, file paths, XML Web service URLs, or any other custom configuration information for an application.
We use this element to store the Service´s User and Password credentials. The key/value pairs specified in the element are accessed in code using the ConfigurationSettings library in this way ConfigurationManager.AppSettings["AVeryBigSum_User"].
xxxxxxxxxx
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
<add key="AVeryBigSum_User" value="AVeryBigSum"/>
<add key="AVeryBigSum_Pass" value="12345"/>
</appSettings>
Thus, we can change these credentials without the need to rebuild the dynamic link libraries files (DLL) of our project.
Despite the advantage of using the element above, all the magic related to the definition of the service happens in the boundaries of the ServiceModel tag next.
Behaviors
The behaviors tag defines the protocol elements consumed by endpoints and services, respectively. The service credentials element is essential to define. It specifies the custom validation mode used in the authentication process.
xxxxxxxxxx
<behaviors>
<serviceBehaviors>
<behavior name="DebugModeBehavior">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
<!--For UserPass Authentication-->
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="AVeryBigSum_BasicAuthentication.ServiceAuthenticator, AVeryBigSum_BasicAuthentication"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
Inside service credentials, another important property is defined to specify the settings for username and password validation. The userNamePasswordValidationMode property sets how the credential is validated. Our service uses a custom class to validate the credentials. This class AVeryBigSum.ServiceAuthenticator can be found in the AVeryBigSum project.
Bindings
Each endpoint in a WCF service requires a binding to be well-specified. A binding consists of an ordered stack of binding elements, each of which specifies a part of the communication information required to connect to a service endpoint.
As we can see, we are using WSHttpBinding. It represents an interoperable binding that supports distributed transactions, secure and reliable sessions.
xxxxxxxxxx
<bindings>
<wsHttpBinding>
<!-- configure wsHttp binding with Transport security mode and clientCredentialType as Certificate -->
<binding name="wsHttpBinding_LargeBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="250000000" maxReceivedMessageSize="250000000" messageEncoding="Text"
textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<!--For UserPass Authentication-->
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" establishSecurityContext="false"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
WSHttpBinding uses the HTTP transport and provides message security, transactions, reliable messaging, and WS-Addressing, either enabled by default or available through a single control setting.
Inside the WSHttpBinding element, we define the security mode as TransportWithMessageCredential. The transport determines the actual mechanism that provides transport-level security. For HTTP, the mechanism is Secure Sockets Layer (SSL) over HTTP (HTTPS);
Service
Finally, at the service element, we define endpoints, exposing the service metadata. It is useful to publish metadata like Web services Description Language (WSDL) document that describes all methods and data types employed by a service. It will be used by SoapUi, to retrieve and invoke all serviceable endpoints.
xxxxxxxxxx
<services>
<service behaviorConfiguration="DebugModeBehavior" name="AVeryBigSum_BasicAuthentication.Avbs">
<endpoint address="endpointAVeryBigSum_BasicAuthentication" binding="wsHttpBinding"
bindingConfiguration="wsHttpBinding_LargeBinding" name="EndpointAVeryBigSum_BasicAuthentication"
contract="AVeryBigSum_BasicAuthentication.IAvbs" />
<endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wsHttpBinding_LargeBinding"
name="mexEndpoint" contract="IMetadataExchange" />
</service>
</services>
Custom Validator Class
The custom validator extends the UserNamePasswordValidator class and overrides the method to Validate. This validator is defined in Service Behaviors as the default Authorization manager, as shown above in the behavior section. This class compares the information received by the client call to those defined in the AppsSetting/WebConfig element.
xxxxxxxxxx
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IdentityModel.Selectors;
using System.Linq;
using System.ServiceModel;
using System.Web;
namespace AVeryBigSum_BasicAuthentication
{
public class ServiceAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
throw new SecurityTokenException("Username and password required");
if (!(userName == ConfigurationManager.AppSettings["AVeryBigSum_User"] && password == ConfigurationManager.AppSettings["AVeryBigSum_Pass"]))
throw new FaultException(string.Format("Wrong username ({0}) or password ", userName));
}
}
}
By the way, for this class to work properly, we need to add two external libraries to the project. We can do this by right click on the project -> Manage NuGet Packages and browsing for Microsoft.IdentityModel.Logging and Microsoft.IdentityModel.Tokens packages and add both.
Now that we have defined the endpoint, next, we will host the service in the local development server.
Deploy and Run the Service
- To host our service in IIS, right-click on the project, and go to Properties. In the properties->window, select the Web tab.
- Now under Servers on Web settings, you’ll see the following details, change the “IIS Express” to “IIS Server.”
- Now Click on Create Virtual Directory with Visual Studio running As Administrator. You’ll get a message The Virtual directory was created successfully! Otherwise, you’ll receive an error message, and you need to ensure that you launch the Visual Studio as Administrator.
Now press F5, and your application will be up and running on the IIS server instead of your IIS Express.
Invoking the Service
We created a basic authentication service to be invoked using SoapUI. Now we will demonstrate step by step how to use this tool to successfully invoke this kind of service.
Create a New SOAP Project
Firstly we need to create a SoapUI project, and in the "Initial WSDL," add the URL of the WSDL service created at the beginning. Also, add your desired project name.
A new project is generated with a sample request for the service.
Authentication and Security-Related Settings Tab
After create successfully the new SoapUI project, collapse until the request´s endpoint. Now double-click the request or right-click the mouse to open the Show Request Editor. Navigate to the Auth (Basic) tab in the bottom corner, surrounded by a green circle.
WS-Addressing Related Settings Tab
Navigate to the WS-A Configurations tab, and enable the WS-A addressing that defines two interoperable constructs typically provided by transport protocols (endpoint references) and messaging systems (message information headers). These constructs normalize this underlying information into a uniform format that can be processed independently of transport or application.
To instruct the service to process the crucial element in the header, we need to specify to TRUE the "Must understand" configuration. The header contains crucial data to process, and the recipient must process the headers. If the service can't process the header or didn't receive the header, an error will be raised.
Also, SOAPUI allows us to enable the Add default wsa: To and Add default wsa: Action configuration. The Add default wsa: To provide the value for the destination property. The default anonymous value for this property is "http://www.w3.org/2005/08/addressing/anonymous". In the above example, the default wsa: Action, wsa: To, and wsa: MessageId headers have been enabled, so when we send the request, we can see them in the raw request view.
WS-Reliable Message Related Settings Tab
To ensure reliable communication between two systems we enable the WS-Reliable Message specification. The aim of this is to ensure that messages are transferred properly from the sender to the receiver in the presence of network failures. As well we select the latest version of this specification for this demonstration.
Request Properties
Finally, in the left corner Request Properties -> WSS-Password Type, we select PasswordText. WSS-Password Type is a concept that will outline if the password in the XML payload is plain text or digest. For Digest, you can use the Require Ws-Security Password Digest Credentials, which is a one-to-one relationship of the user to assertion as we need to know the password. For Plain text, you can use the WS-Security UsernameToken Profile Credentials.
Conclusion
In this post, we demonstrate how to configure a SoapUI project to invoke a WCF Basic Authentication service. We used the secured service created to serve as a system under test.
The sample of the WCF service and the SoapUI project is accessible from the GitHub repository; to download it, please follow this link.
Published at DZone with permission of Jailson Evora. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments