Integration Framework Authentication

The Integration Framework authenticates requests based on a JWT token that is passed to it in the Authorization header. Based on the token setup the appropriate LS One user and Store is loaded for the request and used for database access or service calls made by the request.

How to: Send the token with HTTP/HTTPS requests

If you're making HTTP/HTTPS request from an external system (a web site, SOAPUI etc) you must place the token value in the Authorization header. The value of the header should be in the format:

  • "Bearer:<token value>"

Example:

  • "Bearer:eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyICI6ImFkbWluIiwic3RvcmUiOiJTMDAwMSIsInRpY2tzIjo2MzY3MzAzODMyOTU1OTM5NTF9.amPTF_DMdfarZEsHcBaTdITd-IVCZn7jhfGFH1eX7Ac"

How to: Send the token from .Net code

The same information has to be sent if you're integrating to the Integration Framework from a .Net assembly. An example implementation can be found in the development pack at DevPack\IFSamples. The sample is described Samples, but below are code samples that explain how the tokens are attached to the HTTP/HTTPS and Net.TCP requests sent from the code. We'll go through each part of the sample code that is responsible for sending the token to the Integration Framework.

 

The implementation is based on recommendations on  MSDN:

 

1: The AuthorizationTokenMessageInspector class

This class is responsible for creating a header and adding it to all outgoing requests. This creates a single point in the sample application where the token is added to the request. The class implements the IClientMessageInspector interface and adds the token in the BeforeSendRequest method:

public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
	switch (schemeType)
	{
		case ClientSchemeType.NetTCP:
			MessageHeader header = MessageHeader.CreateHeader("Authorization", "LSAuth", $"Bearer:{settings.If.IFToken}");
			request.Headers.Add(header);
			break;

		case ClientSchemeType.HTTP:
			HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
			requestMessage.Headers["Authorization"] = $"Bearer:{settings.If.IFToken}";
			request.Properties[HttpRequestMessageProperty.Name] = requestMessage;
			break;
	}

	return null;
}

Note that the method for adding the token is different based on whether the client is making a Net.TCP- or HTTP/HTTPS request. In this case the token value is fetched via settings.If.IFToken from the Web.config file at DevPack\IFSamples\StoreWebSite\Web.Config.xml.

 

3: The AuthorizationTokenBehavior class

This class is responsible for adding our AuthorizationTokenMessageInspector to the runtime so that our BeforeSendRequest method is executed and the token added to the request header. The class implements the IEndpointBehavior interface and adds our AuthorizationTokenBehavior instance in the ApplyClientBehavior method:

public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
	AuthorizationTokenMessageInspector inspector = new AuthorizationTokenMessageInspector(settings, schemeType);
	clientRuntime.MessageInspectors.Add(inspector);
}

The behavior implementation then needs to be added to each endpoint. In the sample implementation this is done imperatively but it can also be done via the configuration file.

 

4: Adding the behavior implementation to the endpoints

The AuthorizationTokenBehavior class needs to be added to each endpoint after they are constructed. That way each call made to the service endpoints will go through our AuthorizationTokenMessageInspector -> BeforeSendRequest function.

 

Adding behavior to the Net.TCP endpoint:

wcfCustomerServiceFactory = new ChannelFactory<IIntegrationFrameworkCustomerService>(siteService.DefaultBinding, new EndpointAddress(settings.If.NetTcpUrl + IntegrationFrameworkConstants.IntegrationFrameworkCustomerService));
wcfCustomerServiceFactory.Endpoint.Behaviors.Add(new AuthorizationTokenBehavior(settings, ClientSchemeType.NetTCP));
wcfCustomerService = wcfCustomerServiceFactory.CreateChannel();

 

Adding behavior to the HTTP/HTTPS endpoint:

wcfCustomerService = new IfCustomerService.IntegrationFrameworkCustomerServiceClient(
	bindingPrefix + "_IIntegrationFrameworkCustomerService", 
	new EndpointAddress(settings.If.HttpUrl + IntegrationFrameworkConstants.IntegrationFrameworkCustomerService)

);

((ClientBase<IfCustomerService.IIntegrationFrameworkCustomerService>)wcfCustomerService).Endpoint.Behaviors.Add(new AuthorizationTokenBehavior(settings, ClientSchemeType.HTTP));

 

At this point all requests made to the Integration Framework will get the correct authorization headers with the token value added.

How to: Handle authorization errors

When authorization fails, LSOne Integration Framework will send an UnauthorizedAccessException to the calling client with different messages:

  • Authorization header not found - when Authorization header is missing from request
  • Authorization header invalid - when Authorization header has incorrect value
  • Authorization failed - if received token could not be validated (does not exist in LSOne database for the client's host name)

 


string url = "http://localhost:9103/IntegrationFrameworkRetailItemService";
RecordIdentifier itemId = new RecordIdentifier{
	SerializationType = RecordIdentifierRecordIdentifierType.String,
	StringSerializationData = "38001"
};
string tokenBad = "some invalid token";
string tokenOk = "valid token for the machine";

IIntegrationFrameworkRetailItemService wcfItemService = null;

//1. Authorization header not found
Console.WriteLine();
Console.WriteLine("1. Authorization header not found");
try
{
	wcfItemService = new IntegrationFrameworkRetailItemServiceClient(
							"WSHttpBinding_IIntegrationFrameworkRetailItemService",
							new EndpointAddress(url));
	
	var item = wcfItemService.Get(itemId);
	item.Dump();
}
catch(UnauthorizedAccessException uae)
{
	Console.WriteLine("Exception -> " + uae.Message);
}
catch(Exception ex)
{
	Console.WriteLine("Exception -> " + ex.Message);
}

//2. Authorization failed
Console.WriteLine();
Console.WriteLine("2. Authorization failed");
try
{
	wcfItemService = new IntegrationFrameworkRetailItemServiceClient(
							"WSHttpBinding_IIntegrationFrameworkRetailItemService",
							new EndpointAddress(url));
	((ClientBase<IIntegrationFrameworkRetailItemService>)wcfItemService)
	.Endpoint.Behaviors.Add(new AuthorizationTokenBehavior(tokenBad, ClientSchemeType.HTTP));
	
	var item = wcfItemService.Get(itemId);
	item.Dump();
}
catch(UnauthorizedAccessException uae)
{
	Console.WriteLine("Exception -> " + uae.Message);
}
catch(Exception ex)
{
	Console.WriteLine("Exception -> " + ex.Message);
}


//3. Success
Console.WriteLine();
Console.WriteLine("3. Success");
try
{
	wcfItemService = new IntegrationFrameworkRetailItemServiceClient(
							"WSHttpBinding_IIntegrationFrameworkRetailItemService",
							new EndpointAddress(url));
	((ClientBase<IIntegrationFrameworkRetailItemService>)wcfItemService)
		.Endpoint.Behaviors.Add(new AuthorizationTokenBehavior(tokenOk, ClientSchemeType.HTTP));

	RetailItem item = wcfItemService.Get(itemId);
	item.Dump();
}
catch(UnauthorizedAccessException uae)
{
	Console.WriteLine("Exception -> " + uae.Message);
}
catch(Exception ex)
{
	Console.WriteLine("Exception -> " + ex.Message);
}