Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Overview

Since FIXEdge 5.10 all logon password data is unconditionally encrypted.The article describes the approach that can be used for secure authentication and password management in FIXEdge with use of password encryption. The approach is an alternative to storing session's UserName and Password in FIXEdge.properties configuration file as a plain text. 

Info

Encryption for the Password tag (554) was added in FIXEdge 5.10;

Encryption for the NewPassword tag (925) was added in FIXEdge 5.10.1.

Using passwords in logon for authentication. Simple scenario.

Image Removed

How to configure passwords history

In order to store passwords in the separate file there is a History element in the Business Layer of FIXEdge. You can find detailed information about it here: History element 

Assumes that passwords are stored for unique Senders.

The following Passwords.header file should be created:

Code Block
titlePasswords.header
Field.1.IsKeyField=yes
Field.1.Tag=49
Field.2.Tag=554
FieldsCount=2

Use Case

The approach assumes the following:

  1. There is a FIXEdge Admin who registers new users and assigns their original credentials (UserName and Password) via special Control FIX session to the FIXEdge;
  2. User credentials - username and password in an encrypted form - are stored in a separate storage (file or database);
  3. When user credentials are registered by an Admin, the user can setup the session with the FIXEdge:
    1. If user's Logon message contains UserName and Password, which are specified in the storage, the session will be accepted by the FIXEdge;
    2. If user's Logon message contains UserName and Password, which are not specified in the storage, the session will be rejected by the FIXEdge;
  4. If the user wants to update a password, he or she just sends a Logon message with current UserName and Password along with NewPassword field specified:
    1. In case of successful authentication, NewPassword will need to be specified in next Logon message;
    2. In case of authentication fail, the procedure should be repeated with correct original credentials;

Image Added

Configuration

Password Storage

The idea of storing user credentials in a separate place can be implemented by means of History element of FIXEdge Business Layer. File history is considered below, however ODBC History (means Database) can be used for this purpose as well. 

It is assumed that user credentials are stored per unique SenderCompID. The following text block should be added to BL_Config.xml file to configure the file history:

Code Block
languagexml
titleBL_Config.xml
	<History 
		Name="Passwords" 
		StorageType="File"
		WorkingDirectory="FIXEdge1/conf/" 
		StorageFileName="Passwords">
		<KeyFields>49<<KeyFields>49, 56</KeyFields>
		<Fields>554<<Fields>553, 554</Fields>
	</History>

In this case Passwords.header and the history file should be placed in WorkingDirectory iwill appear in FIXEdge WorkingDirectory (i.e. FIXEdge1/conf/).

How to save sessions passwords to history

Passwords can be saved to history with special session CONTROL-FIXEDGE. (Make sure that FIXEdge is configured for accepting CONTROL-FIXEDGE session).

...

Business Rules

Rules for Control Session

Originally FIXEdge administrator should assign user credentials for the particular client. This can be achieved by means of a special CONTROL-CENTER session. Please find the sample of such session below:

Code Block
languagebash
titleSnippet from FIXEdge.properties
collapsetrue
FixLayer.FixEngine.Session.ControlSession.Version = FIX44
FixLayer.FixEngine.Session.ControlSession.Role = Acceptor
FixLayer.FixEngine.Session.ControlSession.SenderCompID = CENTER
FixLayer.FixEngine.Session.ControlSession.TargetCompID = CONTROL
FixLayer.FixEngine.Session.ControlSession.InSeqNum = 0
FixLayer.FixEngine.Session.ControlSession.OutSeqNum = 0
FixLayer.FixEngine.Session.ControlSession.Description = FIXEdge Control Session to manage user credentials
FixLayer.FixEngine.Session.ControlSession.RecreateOnLogout = true
FixLayer.FixEngine.Session.ControlSession.ForceReconnect = true
FixLayer.FixEngine.Session.ControlSession.ForceSeqNumReset = 1
FixLayer.FixEngine.Session.ControlSession.IgnoreSeqNumTooLowAtLogon = true
FixLayer.FixEngine.Session.ControlSession.RejectMessageWhileNoConnection = false
FixLayer.FixEngine.Session.ControlSession.IntradayLogoutTolerance = true
FixLayer.FixEngine.Session.ControlSession.StorageType = persistentMM
Note

Note, UserName and Password for Control Session (if they are required) will still need to be specified in plain text in FIXEdge.properties configuration file. However, the access to the Control Session can be limited, for example by source IP.

The following rule should be specified in BL_Config configuration file in order to register new user credentials via CONTROL-CENTER session:

Code Block
languagexml
titleBL_Config.xml
	<Rule Description="AddSessionToPasswordHistoryAddSession2PasswordHistory" >
    <Source>
        		<Source>
			<FixSession SenderCompID="CONTROL" TargetCompID="FIXEDGECENTER" />
    		</Source>
    		<Condition>
		        <EqualField Field="35" Value="BE"/>
		        <EqualField Field="924" Value="3"/>
    		</Condition>
		<Action>
			<SetField Field="56"   <Action>
Value="FIXEDGE" />
			<CopyField SourceField="115" TargetField="49" IsRequiredField="Y"/>
			<HashField Field="554"/>
			<SaveToHistory Name="Passwords"/>
        			<StopProcessing/>
     		</Action>
 	</Rule> 

...

This rule says that if User Request message (35 = BE) with UserRequestType = "Change Password For User" (924 = 3) comes from CENTER-CONTROL FIX session, it should encrypt the "Password" field and save the credentials to the "Passwords" history.

FIX Client Simulator can be used to setup CENTER-CONTROL FIX session with the FIXEdge server and send the messages over it. For example, this message can be used to setup username "TestClient1" with password "TestPassword1" to for session CLIENT1.

Password checking script usage

  1. Get saved password from history;
  2. Get 554 tag value from logon;
  3. Decrypt the value;
  4. Get hash from the decrypted value;
  5. Compare hashes;
  6. Return bool value to accepting or rejecting session.

BL Rules listing

Rules for Authentication and Password Change

The following rule performs users authentication and password update. In this example it is assumed that all the client FIX sessions have TargetCompID equal to "FIXEDGE":

Code Block
languagexml
titleBL_Config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
<!DOCTYPE FIXEdge SYSTEM "BusinessLayer.dtd">
-->
<FIXEdge>
<BusinessLayer>
	<!-- ===================== Password history ===================== -->
	<History 
		Name="Passwords" 
		StorageType="File"
		WorkingDirectory="FIXEdge1/conf/" 
		StorageFileName="Passwords">
		<KeyFields>49</KeyFields>
		<Fields>554</Fields>
	</History>

<!-- ===================== Passwords managment ===================== -->
	<Rule Description="AddSessionToPasswordHistory" >
			<CreateSessionEvent>
		<Source>
			<FixSession SenderCompID="CONTROL.*" TargetCompID="FIXEDGE" />
		</Source>
    		<Condition>
    	    <EqualField Field="35" Value="BE"/>
     	   <EqualField Field="924" Value="3"/>
	    </Condition>
    	<Action>
    	    <CopyField SourceField="115" TargetField="49" IsRequiredField="Y			<Exclusion>
				<Script Language="JavaScript" FileName ="FIXEdge1/conf/IsValidPassword.js"/>
			<HashField Field="554"/></Exclusion>
			<SaveToHistory Name="Passwords"/></Condition>
		<CreateSessionAction>
    	    <StopProcessing/>
    	<RejectSession>Authentication <error</Action>RejectSession>
		 </Rule>CreateSessionAction>
 
<!-- ===================== Authentication ===================== -->
    <CreateSessionEvent>
        <Source>
     	</CreateSessionEvent>

The JavaScript which is called from this rule returns bool value to accept or reject a session. It does the following:

  1. Gets username (553 tag) and password (554 tag) from Logon message;
  2. Gets username and password of the FIX client from history;
  3. Compares username and password hash with ones from the storage;
  4. Gets new password (925 tag) from Logon message if any and updates password of the FIX client in history.

Here is the code of this JavaScript which should be put to FIXEdge WorkingDirectory (i.e. FIXEdge1/conf/):

Code Block
languagejs
titleIsValidPassword.js
linenumberstrue
collapsetrue
valid = false;

sender    = getStringField(49);
target    = getStringField(56);
user       <FixSession SenderCompID=".*" TargetCompID=".*"/>
        </Source>
        <Condition>
            <EqualField Field="49" Value="CONTROL"/>
            <EqualField Field="56" Value="FIXEDGE"/>
        </Condition>
        
        <Condition>
            <Script Language="JavaScript" FileName ="FIXEdge1/conf/Password_Logon.js"/>
        </Condition>
        <CreateSessionActionIfTrue>
            <AcceptSession/>
        </CreateSessionActionIfTrue>
           <CreateSessionActionIfFalse>
            <RejectSession>Authentication error</RejectSession>
       </CreateSessionActionIfFalse>
    </CreateSessionEvent>
    
    <DefaultRule>
    	<Action>
        	<DoNothing/>
        </Action>
	</DefaultRule>

</BusinessLayer>
</FIXEdge>

JavaScript listing

Code Block
languagejs
titlePassword_Logon.js
// The script checks if password is valid for the session

valid = false;
// get hash from history
sender    = getStringField(49);
key = new Array(sender);
savedPass = getFromHistory getStringField(553);
passEncrypted = getStringField(554); // the value in Password (554) tag is encrypted
newPassEncrypted   = getStringField(925); // the value in NewPassword (925) tag is encrypted

//Decrypts provided value and returns hash of it. Does nothing for null values
function getPass(p) 
{
	if (p != null)
		return hashString(decryptString(p));  
	else
		return p;
}

//get hashs of values in Password (554) and NewPassword (554) tags
inputPass = getPass(passEncrypted); 
newPass = getPass(newPassEncrypted);

key = new Array(sender, target);
savedUser = getFromHistory("Passwords", key, "553");
savedPass = getFromHistory("Passwords", key, "554");

reason = "";
if ( savedUser == null)
{
	reason = "(Username is not found in history)";
}

if ( savedUser == "N/A" ) // Accept the session if stored username is "N/A" without checking the credentials.
{
	valid = true;
}
else if ( (user != null ) && (user == savedUser) ) // username is found in the history
{
	if( (savedPass == null) || (savedPass == hashString("N/A")) || (inputPass == savedPass) ) // Accept the session if stored password is "N/A" or the same as in Logon
	{
		if( (newPass != null) && (newPass != savedPass) ) // Update the password in the history if NewPassword (925) is defined
		{
			values = new Array();
			values.push(user);
			values.push(newPass);
			updateHistory("Passwords", key, values, "554");
 
// get hash from logon message
encryptedPass = getStringField(554);
// accept session if only password is in history
if (encryptedPass != null && savedPass != null)
{
	pass = hashString(decryptString(encryptedPass ));
	if (pass == savedPass )			print("[NOTE] Password has been successfully changed for session " + sender + "-" + target +  ".");
		}
		valid = true;
	}
}

if (valid == false)
{
	// Print session reject reason to FIXEdge.log
	print("[WARN] WrongInvalid username/password combination has been received for SenderCompIDsession " + sender + "-" + target + ". "+ reason);
}

valid;

References

Business Rules Guide

BL Scripting with JavaScript

...