View on GitHub

easitrace

« Back to ARAMS

Movement Services | ARAMS - Authentication

ARAMS (Animal Reporting and Movement Service) provides secure authentication for recording livestock movements in England. This document covers authentication requirements, implementation details, and best practices for both Farm and Abattoir service variants.

Table of Contents

Overview

ARAMS authentication uses a three-tier credential system:

  1. Service Provider Credentials - Identify your software/service provider to ARAMS
  2. Property Credentials - User credentials for the specific farm or abattoir property
  3. SOAP Security Headers - WS-Security username/password tokens in SOAP requests

The authentication process validates all three levels before processing any livestock movement transactions. This multi-layer approach ensures that only authorized service providers and users can record movements on behalf of properties.

Authentication Flow

┌─────────────────────────────────────────────────────────┐
│  Client Application                                     │
│  ┌──────────────────────────────────────────────────┐  │
│  │ Prepares Transaction with Credentials:           │  │
│  │ - Service Provider ID & Password                 │  │
│  │ - Property Username & Password                   │  │
│  └──────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘
                         │
                         ↓
         ┌───────────────────────────────┐
         │   EasiTrace API Gateway       │
         │                               │
         │ 1. Validates all credentials  │
         │ 2. Creates SOAP request       │
         │ 3. Builds WS-Security header  │
         └───────────────────────────────┘
                         │
                         ↓
         ┌───────────────────────────────┐
         │   ARAMS Web Service           │
         │                               │
         │ 1. Validates credentials      │
         │ 2. Processes movement         │
         │ 3. Returns response           │
         └───────────────────────────────┘
                         │
                         ↓
┌─────────────────────────────────────────────────────────┐
│  Response Handling                                      │
│  ┌──────────────────────────────────────────────────┐  │
│  │ - Success: Movement recorded                     │  │
│  │ - Auth Failure: Invalid credentials             │  │
│  │ - Validation Error: Movement validation failed   │  │
│  └──────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

Prerequisites

To use ARAMS authentication, you must have:

  1. Service Provider Registration with ARAMS
    • Contact ARAMS to register as an approved software supplier
    • Receive a Service Provider ID (username) and Service Provider Password
    • These credentials identify your software solution to ARAMS
  2. Farm or Abattoir Property Access
    • Property users need valid ARAMS credentials for their property
    • These are the same credentials used to log into ARAMS directly
    • Each property has separate username/password credentials
  3. Property Location Code (CPH)
    • Common Purpose Holding identifier for the farm or abattoir
    • Format: XX/XXX/XXXX (e.g., “08/050/0046”)
    • Required for all transaction submissions
  4. Network Configuration
    • HTTPS access to ARAMS web services
    • TLS 1.2 or higher support
    • Outbound connections to:
      • Test: https://testws.arams.co.uk/FarmServices/services/
      • Production: https://webservices.arams.co.uk/FarmServices/services/

Credential Types

Service Provider Authentication

Identifies the software supplier making requests to ARAMS:

public class ServiceProviderAuthentication
{
    public string Username { get; set; }          // Service Provider ID from ARAMS
    public string Password { get; set; }          // Service Provider Password (SoftwareSupplierID)
    public string ProgramName { get; set; }       // Your application name
    public string ProgramVersion { get; set; }    // Your application version
    public string SchemaVersion { get; set; }     // ARAMS schema version
}

Usage in Farm Service:

Usage in Abattoir Service:

Property Authentication

Credentials for the specific farm or abattoir user:

public class PropertyAuthentication
{
    public string PropertyType { get; set; }  // "F" for Farm, "A" for Abattoir
    public string Username { get; set; }      // ARAMS user login for the property
    public string Password { get; set; }      // ARAMS user password
}

These are the same credentials the property owner/manager uses to access ARAMS directly.

Setup

Step 1: Store Credentials Securely

Never store credentials in source code. Use environment variables or secure vaults:

// Configuration example using environment variables
var serviceProviderId = Environment.GetEnvironmentVariable("ARAMS_SP_USERNAME");
var serviceProviderPassword = Environment.GetEnvironmentVariable("ARAMS_SP_PASSWORD");
var propertyUsername = Environment.GetEnvironmentVariable("ARAMS_PROPERTY_USERNAME");
var propertyPassword = Environment.GetEnvironmentVariable("ARAMS_PROPERTY_PASSWORD");

Step 2: Prepare Authentication Object

var authentication = new Authentication
{
    ServiceProviderAuth = new ServiceProviderAuthentication
    {
        Username = "ABC123456",                    // Service Provider ID from ARAMS
        Password = "ABC123456",                    // Service Provider Password
        ProgramName = "YourApplication",
        ProgramVersion = "1.0.0",
        SchemaVersion = "2.0"
    },
    PropertyAuth = new PropertyAuthentication
    {
        PropertyType = "F",                        // "F" for Farm, "A" for Abattoir
        Username = "farm_user@arams.co.uk",       // ARAMS property user login
        Password = "secure_password_here"         // ARAMS property user password
    }
};

Step 3: Create Transaction with Authentication

{
  "reference": "MOVEMENT-2024-001",
  "transactionDate": "2024-01-15T10:30:00+00:00",
  "type": "MOV-ON",
  "speciesCode": "S",
  "propertyIdentifier": "08/050/0046",
  "authentication": {
    "serviceProviderAuth": {
      "username": "ABC123456",
      "password": "ABC123456",
      "programName": "YourApplication",
      "programVersion": "1.0.0",
      "schemaVersion": "2.0"
    },
    "propertyAuth": {
      "propertyType": "F",
      "username": "farm_user@arams.co.uk",
      "password": "secure_password_here"
    }
  },
  "fields": {
    "ARAMS.Farm.Sheep.Departure.Location": "08/050/0046",
    "ARAMS.Farm.Sheep.Departure.Date": "2024-01-15",
    "ARAMS.Farm.Sheep.Destination.Location": "35/121/0016",
    "ARAMS.Farm.Sheep.Movement.Arrival.Date": "2024-01-15"
  },
  "animals": [
    {
      "rfid": "826590066101017",
      "visual": "UK12345"
    }
  ]
}

Farm Service Authentication

Required Credentials for Farm Operations

The ARAMS Farm service requires all three credential levels:

// Farm service credential requirements
public override RequiredCredentials RequiredCredentials =>
    RequiredCredentials.ServiceProviderPassword 
    | RequiredCredentials.PropertyUsername 
    | RequiredCredentials.PropertyPassword;

Credential Validation for Farms

ARAMS Farm validates credentials by attempting a test notification transaction:

public class UserCredentialValidator : IUserCredentialValidator<AramsMovementService>
{
    public bool Validate(string username, ref string password, 
        ServiceProviderAuthentication serviceProviderAuth)
    {
        // Create test authentication
        var auth = new Authentication()
        {
            ServiceProviderAuth = serviceProviderAuth,
            PropertyAuth = new PropertyAuthentication()
            {
                PropertyType = "F",
                Username = username,
                Password = password
            }
        };

        // Create minimal test transaction
        var transaction = new Transaction()
        {
            PropertyIdentifier = "00/000/0000",
            SpeciesCode = Species.Sheep.Value,
            HeadCount = 0,
            TransactionDate = DateTime.Now
        };

        // Pack transaction with provided credentials
        var packed = _container.Packer.Pack(transaction, auth);

        // Send test request to validate credentials
        var response = _container.Sender.Send(
            ServiceCapability.NotifyIncomingMovements, 
            packed, 
            auth);

        // Validate response indicates successful authentication
        if (!response.Success || string.IsNullOrWhiteSpace(response.RawResult)) 
            return false;

        var parsed = _container.Parser.Process(response.RawResult, transaction);
        return parsed.Status == ResponseResultStatus.Success;
    }
}

Farm Service Supported Operations

Transaction Type Property Credentials Required Service Provider Credentials Required
MOV-OFF Yes Yes
UPDATEMOV-OFF Yes Yes
MOV-ON Yes Yes
UPDATEMOV-ON Yes Yes
MOV-IN Yes Yes

Example: Farm Movement Transaction

{
  "reference": "FARM-MOV-OFF-20240115",
  "transactionDate": "2024-01-15T10:30:00+00:00",
  "type": "MOV-OFF",
  "speciesCode": "S",
  "propertyIdentifier": "08/050/0046",
  "authentication": {
    "serviceProviderAuth": {
      "username": "ABC123456",
      "password": "ABC123456"
    },
    "propertyAuth": {
      "propertyType": "F",
      "username": "john.smith@farm.co.uk",
      "password": "farm_secure_pwd"
    }
  },
  "fields": {
    "ARAMS.Farm.Sheep.Movement.WithinYourBusiness": "Y",
    "ARAMS.Farm.Sheep.Departure.Location": "08/050/0046",
    "ARAMS.Farm.Sheep.Departure.PostCode": "TF6 6JT",
    "ARAMS.Farm.Sheep.Departure.Date": "2024-01-15",
    "ARAMS.Farm.Sheep.Movement.LoadingDate": "2024-01-15",
    "ARAMS.Farm.Sheep.Movement.ExpectedDuration": "2",
    "ARAMS.Farm.Sheep.Destination.Location": "35/121/0016",
    "ARAMS.Farm.Sheep.Destination.PostCode": "SY21 8HZ",
    "ARAMS.Farm.Sheep.Movement.Haulier.Type": "Haulier",
    "ARAMS.Farm.Sheep.Movement.Haulier.VehicleRegistration": "AB21 XYZ",
    "ARAMS.Farm.Sheep.Movement.Haulier.AuthorisationNumber": "1234567",
    "ARAMS.Farm.Sheep.Movement.Haulier.Name": "John Smith",
    "ARAMS.Farm.Sheep.Movement.Haulier.PhoneNumber": "01234567890",
    "ARAMS.Farm.Sheep.Movement.Haulier.HaulageCompany": "Swift Transport Ltd"
  },
  "animals": [
    {
      "rfid": "826590066101017",
      "visual": "UK12345",
      "birthDate": "2021-03-15"
    },
    {
      "rfid": "826590066101018",
      "visual": "UK12346",
      "birthDate": "2021-03-16"
    }
  ]
}

Abattoir Service Authentication

Required Credentials for Abattoir Operations

The ARAMS Abattoir service requires the same three credential levels:

// Abattoir service credential requirements
public override RequiredCredentials RequiredCredentials =>
    RequiredCredentials.ServiceProviderPassword 
    | RequiredCredentials.PropertyUsername 
    | RequiredCredentials.PropertyPassword;

Credential Validation for Abattoirs

Abattoir validation uses the same test transaction approach:

public class UserCredentialValidator : IUserCredentialValidator<AramsAbattoirMovementService>
{
    public bool Validate(string username, ref string password, 
        ServiceProviderAuthentication serviceProviderAuth)
    {
        var auth = new Authentication()
        {
            ServiceProviderAuth = serviceProviderAuth,
            PropertyAuth = new PropertyAuthentication()
            {
                PropertyType = "F",
                Username = username,
                Password = password
            }
        };

        var transaction = new Transaction()
        {
            PropertyIdentifier = "00/000/0000",
            SpeciesCode = Species.Sheep.Value,
            HeadCount = 0,
            TransactionDate = DateTime.Now,
            Type = ServiceCapability.NotifyIncomingMovements.Code
        };

        var packed = _container.Packer.Pack(transaction, auth);
        var response = _container.Sender.Send(
            ServiceCapability.NotifyIncomingMovements, 
            packed, 
            auth);

        if (!response.Success || string.IsNullOrWhiteSpace(response.RawResult)) 
            return false;

        var parsed = _container.Parser.Process(response.RawResult, transaction);
        return parsed.Status == ResponseResultStatus.Success;
    }
}

Abattoir Service Supported Operations

Transaction Type Property Credentials Required Service Provider Credentials Required
MOV-ON Yes Yes
UPDATEMOV-ON Yes Yes
MOV-CANCEL Yes Yes
MOV-IN Yes Yes

Example: Abattoir Movement Transaction

{
  "reference": "ABATTOIR-MOV-ON-20240115",
  "transactionDate": "2024-01-15T14:00:00+00:00",
  "type": "MOV-ON",
  "speciesCode": "S",
  "propertyIdentifier": "40/XXX/0001",
  "authentication": {
    "serviceProviderAuth": {
      "username": "ABC123456",
      "password": "ABC123456"
    },
    "propertyAuth": {
      "propertyType": "A",
      "username": "slaughterhouse_user",
      "password": "abattoir_secure_pwd"
    }
  },
  "fields": {
    "ARAMS.Abattoir.Sheep.Destination.Location": "40/XXX/0001",
    "ARAMS.Abattoir.Sheep.Movement.Arrival.Date": "2024-01-15",
    "ARAMS.Abattoir.Sheep.Movement.Arrival.UnloadingDate": "2024-01-15",
    "ARAMS.Abattoir.Sheep.Movement.Haulier.Type": "Haulier",
    "ARAMS.Abattoir.Sheep.Movement.Haulier.VehicleRegistration": "AB21 XYZ",
    "ARAMS.Abattoir.Sheep.Movement.Haulier.AuthorisationNumber": "7654321",
    "ARAMS.Abattoir.Sheep.Movement.Haulier.Name": "Driver Name",
    "ARAMS.Abattoir.Sheep.Movement.SatisfiesFCI": true
  },
  "animals": [
    {
      "rfid": "826590066101017",
      "visual": "UK12345"
    }
  ]
}

Key Differences: Abattoir vs Farm

Service Provider Credential Usage:

Property Type:

Supported Operations:

Security Implementation

SOAP WS-Security Headers

ARAMS uses WS-Security (WSSE) with username and password tokens:

// SecurityHeader implementation
internal class SecurityHeader : System.ServiceModel.Channels.MessageHeader
{
    public string userName;
    public string password;

    protected override void OnWriteStartHeader(
        System.Xml.XmlDictionaryWriter writer, 
        System.ServiceModel.Channels.MessageVersion messageVersion)
    {
        writer.WriteStartElement("wsse", Name, WsseNamespace);
        writer.WriteXmlnsAttribute("wsse", WsseNamespace);
        writer.WriteXmlnsAttribute("wsu", WsuNamespace);
        writer.WriteAttributeString("s", "mustUnderstand", Namespace, "1");
    }

    protected override void OnWriteHeaderContents(
        System.Xml.XmlDictionaryWriter writer, 
        System.ServiceModel.Channels.MessageVersion messageVersion)
    {
        DateTime createdTimestamp = DateTime.Now;
        DateTime expiresTimestamp = createdTimestamp.AddMinutes(5);

        // Write timestamp (5-minute validity window)
        writer.WriteStartElement("wsu", "Timestamp", WsuNamespace);
        writer.WriteAttributeString("wsu", "Id", WsuNamespace, "TS-48");
        
        writer.WriteStartElement("wsu", "Created", WsuNamespace);
        writer.WriteValue(createdTimestamp);
        writer.WriteEndElement();

        writer.WriteStartElement("wsu", "Expires", WsuNamespace);
        writer.WriteValue(expiresTimestamp);
        writer.WriteEndElement();
        
        writer.WriteEndElement();

        // Write username token
        writer.WriteStartElement("wsse", "UsernameToken", WsseNamespace);
        writer.WriteAttributeString("wsu", "Id", WsuNamespace, "UsernameToken-47");

        writer.WriteStartElement("wsse", "Username", WsseNamespace);
        writer.WriteValue(userName);  // Property username
        writer.WriteEndElement();

        writer.WriteStartElement("wsse", "Password", WsseNamespace);
        writer.WriteAttributeString("Type", 
            "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
        writer.WriteValue(password);  // Property password
        writer.WriteEndElement();

        writer.WriteEndElement();
    }

    public override string Name => "Security";
    
    public string WsseNamespace => 
        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
    
    public string WsuNamespace => 
        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
    
    public override string Namespace => 
        "http://www.w3.org/2003/05/soap-envelope";
}

HTTPS Requirement

All communication with ARAMS endpoints must use HTTPS with:

var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport)
{
    MaxBufferPoolSize = 2147483647,
    MaxReceivedMessageSize = 2147483647
};

Credential Storage Best Practices

  1. Never hardcode credentials in source code
  2. Use environment variables for local development:
    export ARAMS_SP_USERNAME=ABC123456
    export ARAMS_SP_PASSWORD=ABC123456
    export ARAMS_PROPERTY_USERNAME=user@farm.co.uk
    export ARAMS_PROPERTY_PASSWORD=secure_pwd
    
  3. Use secure vaults in production (Azure Key Vault, AWS Secrets Manager, etc.)
  4. Rotate credentials regularly according to your security policy
  5. Audit credential usage through application logs
  6. Never log full credentials - log hashed or masked versions only

Credential Validation

Validation Process

All credentials are validated before submission:

  1. Service Provider Validation
    • Checks if Service Provider ID and Password are non-empty
    • Validates format of Service Provider ID
    • Ensures credentials match registered provider with ARAMS
  2. Property User Validation
    • Validates property username and password format
    • Checks property access permissions for the user
    • Verifies property type matches (Farm/Abattoir)
  3. Test Transaction Validation
    • Sends minimal test notification to ARAMS
    • Confirms successful authentication
    • Validates property accessibility

Validation Implementation

// Property validator ensures property identifier is accessible
public class PropertyValidator : IPropertyValidator<AramsMovementService>
{
    public bool Validate(string propertyIdentifier, 
        ServiceProviderAuthentication serviceProviderAuth)
    {
        // Property identifier format validation (XX/XXX/XXXX)
        if (!IsValidCphFormat(propertyIdentifier))
            return false;

        // Additional property accessibility checks
        return _propertyService.IsPropertyAccessible(propertyIdentifier);
    }

    private bool IsValidCphFormat(string cph)
    {
        // Validates CPH format: XX/XXX/XXXX
        var parts = cph.Split('/');
        return parts.Length == 3 
            && int.TryParse(parts[0], out var _)
            && int.TryParse(parts[1], out var _)
            && int.TryParse(parts[2], out var _);
    }
}

Error Handling

Error Cause Resolution
InvalidCredentialsException Service Provider ID or Password incorrect Verify Service Provider credentials with ARAMS
PropertyAuthenticationFailed Property username or password incorrect Verify property user credentials with property owner
PropertyNotAccessible User not authorized for this property Contact ARAMS to verify property access
InvalidPropertyIdentifier CPH format invalid or property doesn’t exist Check CPH format is XX/XXX/XXXX and property exists
CredentialsExpired Credentials have expired Request credential reset from ARAMS
InsufficientPermissions User doesn’t have permission for operation type Request appropriate permissions from ARAMS

Example Error Handling

try
{
    var response = movementService.SubmitMovement(transaction, authentication);
    
    if (!response.Success)
    {
        switch (response.ErrorCode)
        {
            case "AUTH001":
                logger.LogError("Invalid Service Provider credentials");
                return StatusCode(401, "Service Provider authentication failed");
                
            case "AUTH002":
                logger.LogError("Invalid Property credentials for {PropertyId}", 
                    transaction.PropertyIdentifier);
                return StatusCode(401, "Property authentication failed");
                
            case "AUTH003":
                logger.LogError("Insufficient permissions for operation");
                return StatusCode(403, "User lacks required permissions");
                
            default:
                logger.LogError("Authentication error: {ErrorCode}", response.ErrorCode);
                return StatusCode(500, "Authentication error occurred");
        }
    }
}
catch (AuthenticationException ex)
{
    logger.LogError(ex, "Authentication failed: {Message}", ex.Message);
    return StatusCode(401, "Authentication failed");
}

Test Environment

Test Environment Endpoints

Farm Service (Test):

https://testws.arams.co.uk/FarmServices/services/

Abattoir Service (Test):

https://testws.arams.co.uk/AbattoirServices/services/

Test Credentials

For testing purposes, contact ARAMS to obtain test credentials:

var testAuthentication = new Authentication
{
    ServiceProviderAuth = new ServiceProviderAuthentication
    {
        Username = "TEST_SP_ID",              // Test Service Provider ID
        Password = "TEST_SP_PASSWORD",
        ProgramName = "TestApplication",
        ProgramVersion = "1.0.0",
        SchemaVersion = "2.0"
    },
    PropertyAuth = new PropertyAuthentication
    {
        PropertyType = "F",
        Username = "test_user@test.arams.co.uk",
        Password = "test_password"
    }
};

Test Property Identifiers

Common test CPH values for testing:

Environmental Configuration

public class AramsSettings
{
    public bool IsTestEnvironment { get; set; }
    
    public string GetWebServiceUrl()
    {
        return IsTestEnvironment 
            ? "https://testws.arams.co.uk/FarmServices/services/"
            : "https://webservices.arams.co.uk/FarmServices/services/";
    }
    
    public string GetAbattoirServiceUrl()
    {
        return IsTestEnvironment 
            ? "https://testws.arams.co.uk/AbattoirServices/services/"
            : "https://webservices.arams.co.uk/AbattoirServices/services/";
    }
}

// Usage in configuration
var settings = new AramsSettings 
{ 
    IsTestEnvironment = !hostEnvironment.IsProduction() 
};

Testing Credential Validation

[Fact]
public void ValidateCredentials_WithCorrectServiceProviderAuth_ReturnsSuccess()
{
    // Arrange
    var testAuth = new Authentication
    {
        ServiceProviderAuth = new ServiceProviderAuthentication
        {
            Username = "TEST_SP_ID",
            Password = "TEST_SP_PASSWORD"
        },
        PropertyAuth = new PropertyAuthentication
        {
            PropertyType = "F",
            Username = "test_user",
            Password = "test_password"
        }
    };

    // Act
    var validator = new UserCredentialValidator(_container, _dateTime);
    var result = validator.Validate(
        testAuth.PropertyAuth.Username,
        ref testAuth.PropertyAuth.Password,
        testAuth.ServiceProviderAuth);

    // Assert
    Assert.True(result);
}

[Fact]
public void ValidateCredentials_WithInvalidPassword_ReturnsFalse()
{
    // Arrange
    var testAuth = new Authentication
    {
        ServiceProviderAuth = new ServiceProviderAuthentication
        {
            Username = "TEST_SP_ID",
            Password = "INVALID_PASSWORD"
        },
        PropertyAuth = new PropertyAuthentication
        {
            PropertyType = "F",
            Username = "test_user",
            Password = "wrong_password"
        }
    };

    // Act
    var validator = new UserCredentialValidator(_container, _dateTime);
    var result = validator.Validate(
        testAuth.PropertyAuth.Username,
        ref testAuth.PropertyAuth.Password,
        testAuth.ServiceProviderAuth);

    // Assert
    Assert.False(result);
}

Last Updated: January 2024
ARAMS API Version: 2.0
Related Documentation: ARAMS Service Overview