ATS Bus 2.5 introduced the IT and OT web service channels and these have been improved in ATS Bus 2.8 to support encryption and user authentication using the ATS Security Manager.
ATS Bus 2.7 introduced a REST API for the OT bus stop work order manager. It allows third parties to view, close and reset work orders. The RESTful API has the same functionality as the front-end application including encryption (https) and authentication. In version 2.8, the user authentication has been updated. When using the API, users should first obtain a token from the ATS Security Manager and then use that token in the authorisation header to invoke the methods on the work order manager RESTful API.
ATS Bus 2.8 introduced a new RESTful API to monitor the bus stops. This RESTful API allows users to integrate the bus stop monitor functionality in their own web based monitoring tools.
All ATS Bus RESTful API’s have 2 configuration items in common and these are explained here:
ATS Bus enforces encryption on all RESTful API’s except for the IT and OT web service server channels where it is configurable. The following endpoints require a certificate to work:
The ATS Bus installers do not provide and install a self-signed certificate, this is something the user has to do after ATS Bus and the bus stops are installed. A temporary certificate can be created using the following PowerShell command:
New-SelfSignedCertificate -DnsName <FQDN>, <Hostname> -CertStoreLocation “cert:\LocalMachine\My” -NotAfter “2030-01-01” -Subject "CN=AtsBusSelfSignedCert"
Where:
<FQDN> is a string holding the computer name including domain name
<Hostname> is a string holding the computer name without domain name
This will create a certificate with the common name AtsBusSelfSignedCert in the Local Computer certificate store at the Personal location. Please copy this certificate to the Trusted Root Authority to ensure that the chain is trusted.
The following Windows commands can be used to bind a certificate to the RESTful endpoint (which listens at the monitoring port configured in ATS Bus Cockpit):
netsh http add sslcert ipport=0.0.0.0:<port> appid=APPID certhash=THUMBPRINT
Where:
THUMBPRINT is the thumbprint of the certificate in the certificate store.
<port> is the port the RESTful API binds to. See ‘How to setup encryption’ for a list of default port numbers.
APPID is a GUID that identifies the bus stop. The APPID should be formatted as a GUID with curly braces: {ED3CE4E1-E134-49FC-AA7F-E4E1D142B0D4}
The netsh command given above should be executed for all encrypted endpoints.
ATS Bus Data Service + IT + OT bus stop on the same host where the OT bus stop has an SSL enabled web service server channel configured at port 9999:
netsh http add sslcert ipport=0.0.0.0:8704 appid={ED3CE4E1-E134-49FC-AA7F-E4E1D142B0D4} certhash=THUMBPRINT
netsh http add sslcert ipport=0.0.0.0:8708 appid={ED3CE4E1-E134-49FC-AA7F-E4E1D142B0D4} certhash=THUMBPRINT
netsh http add sslcert ipport=0.0.0.0:8800 appid={8F1A5AAD-F7BE-497E-9A46-22720C893894} certhash=THUMBPRINT
netsh http add sslcert ipport=0.0.0.0:8802 appid={FF104272-EA63-42C3-8FD8-071F1855F44F} certhash=THUMBPRINT
netsh http add sslcert ipport=0.0.0.0:9999 appid={E6818A12-D5C9-43D3-B9CA-7129C3C1AC51} certhash=THUMBPRINT
(The example above shows that the ATS Bus data Service, bus stops and the web service server channel use different application ID’s)
The following windows commands can be used to release a certificate from an endpoint:
netsh http delete sslcert ipport=0.0.0.0:<port>
Follow the steps below to create a certificate for the ADOS web API’s that require HTTPS and is the recommended approach. Self-signed certificates should not be used for ADOS web API’s.
Open the certificate manager for the local computer using the following command: certlm.msc
Right click on the Personal folder and select All Tasks > Request New Certificate.
Click Next.
Select the Active Directory Enrollment Policy and press Next.
#
Request a certificate of a specific type that is required for the web API and click Enroll.
Review the certificate and press Finish.
The certificate uses a FQDN in the Subject Alternative Name and therefore the ADOS web API’s (Security Manager, Configuration Manager, License Manager, Bus services, Inspect services, CM4D services) should configure the FQDN everywhere the hostname is required. Clients should then invoke the services using the FQDN otherwise the server responds with HTTP Bad Request.
There may be multiple certificates in the personal store with the same ‘Issue to’ property. This causes an issue when the certificate that has the ‘Server authentication’ set expires earlier than the certificate that does not have that intended purpose set. The ADOS web API’s select the certificate by its subject CN and the longest validity. It does not check the intended purpose.
It is recommended to check if the subject common name can be changed in the certificate type selection window as indicated below:
ATS Bus uses the ATS Security Manager to allow users to use the front-end applications and RESTful API.
The process for configuring a user is explained in the online ATS Security manual available here.
The illustration below shows the authentication workflow:
The client reaches out to the ATS Security Manager to get a Token using the password flow. The client has to provide the following details:
Username (from the ATS Security Manager)
Password (from the ATS Security Manager)
Client ID (Depending on the API that is invoked)
Scope (Depending on the API that is invoked), the scope is used in the RESTful API to limit client application access.
The ATS Security Manager will authenticate the user and return a Bearer to the client once authorized.
The client then uses the Bearer token in the authentication header in the HTTP request to ATS Bus RESTful API.
The ATS Bus RESTful API checks with the ATS Security Manager if the token is valid.
The ATS Security Manager returns the claims to the ATS Bus RESTful API
The ATS Bus RESTful API executes if the client has sufficient claims and returns a response.
A C# example can be found here that demonstrates how to authenticate a user and invoke a method on a RESTful resource.
When connecting to a RESTful API, a token is required to identify the user and the client application that is invoking the RESTful API. The token is obtained from the ATS Security Manager that has users and client applications defined. Users are configured using the ATS Security Manager web interface and API clients, API resources and API scopes are configured by ATS Bus. The following list shows the flow, client ID and API scopes to use when connecting to the ATS Bus RESTful API:
Bus stop monitoring and work order manager RESTful API:
Username: configured in ATS Security Manager
Password: configured in ATS Security Manager
Flow: password
Client id: 779917d9-5897-4742-87a6-94a745443bfb
Client secret: not required
Scopes:
e64a5309-fb1b-41c3-8dc1-fe39a14ebb04\monitoring.read-only
e64a5309-fb1b-41c3-8dc1-fe39a14ebb04\monitoring.read-write
e64a5309-fb1b-41c3-8dc1-fe39a14ebb04\workorders.read-only
e64a5309-fb1b-41c3-8dc1-fe39a14ebb04\ workorders.read-only
IT bus stop web service server channel:
Username: configured in ATS Security Manager
Password: configured in ATS Security Manager
Flow: password
Client id: 88bc7355-8bf6-42c6-8685-d3fb561888ed
Client secret: not required
Scopes:
d7d6f417-ca9d-4192-a035-303d383680df\itwebservice.read-write
OT bus stop web service server channel:
Username: configured in ATS Security Manager
Password: configured in ATS Security Manager
Flow: password
Client id: 7984e128-d408-4cbf-a3cb-38df8ac6e085
Client secret: not required
Scopes:
11aa08b7-703c-45d0-8af3-7e8ab7f548e3\otwebservice.read-write
ATS Bus defines the following RESTful API resources that are accessible by the user:
Work order manager: https://<host>:<bus stop monitor port number>/api/v1/workorders (OT bus stops only)
Bus stop monitoring: https:// <host>:<bus stop monitor port number>/api/v1/monitoring
IT and OT Web Service Server channel: http://<host>:<port>/Publish or https://<host>:<port>/Publish
IT and OT Web Service Server channel: http://<host>:<port>/Receive or https://<host>:<port>/Receive
IT and OT Web Service Server channel: http://<host>:<port>/ReceiveJson or https://<host>:<port>/ReceiveJson
Each resource defines a set of methods that can perform an action on the resource. The following methods are available:
OT bus stop:
GET: api/v1/workorders, Retrieve all resources (OT bus stops only)
GET: api/v1/workorders/{compositeKey}, Retrieve a single work order by its composite key (OT bus stops only)
PUT: api/v1/workorders/{compositeKey}, Reset a work order to state Created (OT bus stops only)
DELETE: api/v1/workorders/{compositeKey}, Close a work order by its composite key (OT bus stops only)
All bus stops:
GET: api/v1/monitoring/GetStatus, Retrieve all status information of the bus stop
POST: api/v1/workorders/Restart, Restart the bus stop.
IT and OT web service server channel:
GET: /Publish, Retrieve a message sent/published by the web service server channel
POST: /Receive or /ReceiveJson to deliver XML or JSON to the web service server channel
Swagger UI (https:// <host>:<bus stop monitor port number>/swagger) provides documentation for the resources and methods supported by the bus stop RESTful API’s and it also allows to invoke these methods.
Swagger is not available for the IT and OT web service server channels
The Swagger UI user must be authenticated before it can invoke the methods. Swagger will show a red exclamation mark (as indicated below) when the user is not authorised, clicking it will show a dialog that can authenticate a user. A username, password, client ID and scope must be provided before clicking the Authorize button. Once authenticated, the exclamation mark changes to a blue i.
Click on the exclamation mark, an authentication dialog will appear.
Provide the user that is configured in the ATS Security Manager
Provide a valid password
Provide the client ID, use ‘6d34a158-fa74-4dbe-8338-caff2c9c643a’ for Swagger UI.
Select the API scopes, workorders.read-write will work for the work order manager. The scopes are used to limit client application access to the methods.
Press Authorize.
If authorized, Swagger will show a blue ‘I’
The bearer token will also show in the Authorization header.
The C# example in this chapter shows how to authenticate a user and post XML to an IT web service server channel:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using Newtonsoft.Json;
namespace WebServiceClient
{
public class Class1
{
private static string jsonConfig = @"{
""token_endpoint"": ""http://SECURITY-MANAGER-HOST:5000/connect/token"",
""grant_type"": ""password"",
""username"": ""Admin"",
""password"": ""------YOUR-USER-PASSWORD-HERE------"",
""client_id"": ""88BC7355-8BF6-42C6-8685-D3FB561888ED"",
""client_secret"": """",
""device_code"": """",
""scope"": ""d7d6f417-ca9d-4192-a035-303d383680df\\itwebservice.read-write"",
""refresh_token"": """"
}";
private static string xmlString = @"<root><node1>1</node1></root>";
static void Main()
{
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) => true;
var serializer = new JsonSerializer();
var form = serializer.Deserialize<Dictionary<string, string>>(new JsonTextReader(new StringReader(jsonConfig)));
if (!form.ContainsKey("token_endpoint"))
{
Console.WriteLine("'token_endpoint' is missing in the JSON config file.");
Environment.Exit(0);
}
var tokenClient = new HttpClient {BaseAddress = new Uri(form["token_endpoint"])};
tokenClient.DefaultRequestHeaders.Accept.Clear();
tokenClient.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("en-GB"));
tokenClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Remove empty values
form = form.Where(x => !string.IsNullOrEmpty(x.Value) && x.Key!="token_endpoint").ToDictionary(x => x.Key, x => x.Value);
var tokenResponse = tokenClient.PostAsync(string.Empty, new FormUrlEncodedContent(form)).Result;
if (!tokenResponse.IsSuccessStatusCode)
{
var details = tokenResponse.Content.ReadAsStringAsync().Result;
throw new Exception($"Authentication failed. Token response : {tokenResponse.ReasonPhrase}, details: {details}");
}
var token = tokenResponse.Content.ReadAsAsync<TokenOAuth>(new[] { new JsonMediaTypeFormatter() }).Result;
if (string.IsNullOrEmpty(token.AccessToken))
{
throw new Exception("Authentication failed.");
}
tokenClient.Dispose();
var client = new HttpClient { BaseAddress = new Uri("https://localhost:9999/MyApi1") };
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("en-GB"));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
var response = client.PostAsync(string.Empty,new StringContent(xmlString)).Result;
if (!response.IsSuccessStatusCode)
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
// Make any other calls using HttpClient here.
// Dispose once all HttpClient calls are complete. This is not necessary if the containing
// object will be disposed of; for example in this case the HttpClient instance will be
// disposed automatically when the application terminates so the following call is superfluous.
client.Dispose();
}
}
internal class TokenOAuth
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("refresh_token")]
public string RefreshToken { get; set; }
}
}
Can we improve this topic?