Skip to content

tmtsoftware/aps-submitter-prototype

Repository files navigation

aps-submitter-prototype

This project is contains a React web application subproject that submits sequences, and a backend service that read them from configuration. See README files for each of these subprojects for details on build, run, etc.

Startup Guide

1. Start CSW Services

csw-services start --location --auth --config --event --database

2. Start ESW Gateway

cat > /tmp/command-role-mapping.conf << 'EOF'
APS.primary.startSequence: [esw-user]
EOF

esw-gateway-server start -p 8090 -l -c /tmp/command-role-mapping.conf

Note: The esw-user role in the command role mapping is temporary to get things started.

3. Start APS Sequencer

cd ~/Desktop/Prototyping/aps-sequencer-prototype
sbt "runner/run sequencer -s APS -n primary -m APS_software_only_mode"

4. Start Submitter Backend

cd ~/Desktop/Prototyping/aps-submitter-prototype/apssubmitterprototype-backend
source ~/.zshrc
sbt "run start --port 8084"

5. Start Submitter Frontend

cd ~/Desktop/Prototyping/aps-submitter-prototype/apssubmitterprototype-frontend
npm start

6. Load Sequence Data into Config Service

Generate and store the sequence file:

python3 -c "
import json
source = 'APS.sequenceSubmitter'
matrix = [[0.0] * 3 for _ in range(492)]
actuatorOffsets = {
    'FloatMatrixKey': {
        'keyName': 'actuatorOffsets',
        'values': [matrix],
        'units': 'millimeter'
    }
}
sequence = [
    {'_type': 'Setup', 'source': source, 'commandName': 'calc-colorstep', 'paramSet': []},
    {'_type': 'Setup', 'source': source, 'commandName': 'cmd-m1cs-moves', 'paramSet': [actuatorOffsets]},
    {'_type': 'Setup', 'source': source, 'commandName': 'calc-tt-offsets-to-acts', 'paramSet': []},
    {'_type': 'Setup', 'source': source, 'commandName': 'calc-decompose-acts', 'paramSet': []}
]
print(json.dumps(sequence, indent=2))
" > ~/aps-sequence.json

cs launch csw-config-cli -- create /aps/sequences/testmode.json \
  --in ~/aps-sequence.json \
  --comment "APS software-only mode test sequence"

Note: If the file already exists from a previous run, use update instead of create, then set it as the active version:

cs launch csw-config-cli -- update /aps/sequences/testmode.json \
  --in ~/aps-sequence.json \
  --comment "update"

cs launch csw-config-cli -- setActiveVersion /aps/sequences/testmode.json \
  --id <version-id> --comment "set active"

7. Submit a Sequence

  1. Open http://localhost:3000 in a browser
  2. Log in with esw-user1 / esw-user1
  3. Enter config service path: /aps/sequences/testmode.json
  4. Click Load Template
  5. Click Submit Sequence

Expected response:

{
  "_type": "Completed",
  "runId": "...",
  "result": {
    "paramSet": []
  }
}

ESW Gateway Keycloak Setup

This documents the Keycloak configuration required to use the ESW Gateway with a frontend app in a CSW/ESW development environment.

Each time csw-services is restarted, these steps must be performed, as Keycloak is reset each time CSW is restarted.

Context

  • CSW services started with: csw-services start --location --auth --config --event --database
  • Keycloak admin console: http://localhost:8081 (login: admin/admin)
  • Keycloak API base: http://localhost:8081/admin/realms/TMT
  • ESW Gateway started with: esw-gateway-server start -p 8090 -l -c /tmp/command-role-mapping.conf
  • The gateway's auth-config (in its application.conf) references client-id = tmt-backend-app and realm = TMT

Problem

The embedded Keycloak that csw-services starts does not include a tmt-backend-app client by default, and tokens issued to the frontend do not include tmt-backend-app in their audience. The gateway rejects all tokens silently with 403 Forbidden and x-tmt-username: unknown in request headers.

TODO

This set of steps was derived by AI after hours of trial and error. These need to be tested once again to verify they work and are necessary.

Required Setup Steps

Step 1 — Get an admin token

Run this first. The token expires in 60 seconds so run subsequent steps quickly, or re-run this line before each step.

TOKEN=$(curl -s -X POST "http://localhost:8081/realms/master/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=admin&password=admin&grant_type=password&client_id=admin-cli" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

Step 2 — Create the tmt-backend-app client

The gateway validates tokens against this client. It must exist in the TMT realm.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  "http://localhost:8081/admin/realms/TMT/clients" \
  -d '{"clientId": "tmt-backend-app", "enabled": true, "publicClient": true, "bearerOnly": false}'

Step 3 — Find the tmt-frontend-app client ID

The frontend app uses tmt-frontend-app. You need its internal Keycloak UUID to add a mapper to it.

curl -s -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8081/admin/realms/TMT/clients?clientId=tmt-frontend-app" \
  | python3 -m json.tool | grep '"id"' | head -1

Note the UUID value (e.g. 963dec63-a99f-4030-ad4e-57efe8c00207).

Step 4 — Add tmt-backend-app audience mapper to tmt-frontend-app

This adds tmt-backend-app to the aud claim of tokens issued by tmt-frontend-app, which the gateway requires for token validation.

Replace <CLIENT-UUID> with the UUID from Step 3.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  "http://localhost:8081/admin/realms/TMT/clients/<CLIENT-UUID>/protocol-mappers/models" \
  -d '{
    "name": "tmt-backend-app-audience",
    "protocol": "openid-connect",
    "protocolMapper": "oidc-audience-mapper",
    "consentRequired": false,
    "config": {
      "included.client.audience": "tmt-backend-app",
      "id.token.claim": "false",
      "access.token.claim": "true"
    }
  }'

Step 5 — Assign aps-user role to your user

The gateway checks for {subsystem}-user role for sequencer commands. For APS sequencer submissions the user needs aps-user.

First, find the user ID:

curl -s -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8081/admin/realms/TMT/users" \
  | python3 -m json.tool | grep -E '"id"|"username"'

Then get the aps-user role ID:

ROLE_ID=$(curl -s -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8081/admin/realms/TMT/roles/aps-user" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")

Then assign the role (replace <USER-UUID> with the user's ID):

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  "http://localhost:8081/admin/realms/TMT/users/<USER-UUID>/role-mappings/realm" \
  -d "[{\"id\": \"$ROLE_ID\", \"name\": \"aps-user\"}]"

Step 6 — Create the command role mapping file

The gateway requires a command role mapping file. For APS sequencer access:

cat > /tmp/command-role-mapping.conf << 'CONF'
APS.primary.startSequence: [aps-user]
CONF

Step 7 — Start the gateway

esw-gateway-server start -p 8090 -l -c /tmp/command-role-mapping.conf

Step 8 — Log in as a user with aps-user role

In the frontend app, log in as the user you assigned aps-user to in Step 5. The predefined user esw-user1 (password: esw-user1) is a good choice after assigning aps-user to it.

Notes

  • Steps 2–5 only need to be done once per Keycloak instance. They persist across gateway and service restarts as long as csw-services is not restarted.
  • If csw-services is restarted, Keycloak resets and all steps must be repeated.
  • The tmt-frontend-app client UUID and user UUIDs are specific to each Keycloak instance — always look them up rather than hardcoding them.
  • The Keycloak admin UI at http://localhost:8081 only shows the master realm. The TMT realm is created programmatically and must be managed via the API.
  • The predefined users in the TMT realm (all with password = username) are: config-admin1, config-user1, dummy-user, esw-user1, iris-user1, osw-user1, tcs-user1, wfos-user1

How to Use the Project

The project has following structure:

.
├── src
│   ├── assets
│   ├── components
│   ├── config
│   ├── contexts
│   ├── hooks
│   ├── models
│   ├── routes
│   ├── utils
├── test
├── types
  • assets: This directory contains all the files (images, audio etc) that are used by the UI component.
  • components: This directory contain all the components created for this UI application.
  • config: This contain the application specific configurations.
  • contexts: This contain contexts like LocationServiceContext to pass and share data to nested react conponents.
  • hooks: This contain helper hooks.
    • useAuth.tsx This file contain auth related helper hooks and exposes login, logout and auth constants.
    • useQuery.tsx This file contain hooks to query data asynchronous and expose other constants like loading, error to track query state.
  • routes: This contain route related files.
    • Routes.tsx This file uses react-router to describe frontend routes for this application.
    • ProtectedRoute.tsx This file contain auth protected frontend routes.
  • utils: This contain common utilities.
    • Http.ts has generic helper functions written over fetch API to do GET, POST requests.
    • api.ts This file uses Http.ts and provide application specific functions to do POST requests.
    • resolveBackend.ts This file contain helper function to resolve location of backend using location service.
  • test: This directory contains all the tests for the UI application.
  • types: This directory contains all the types that needs to be imported externally for UI application.

References

  • ESW-TS Library - Link
  • ESW-TS Library Documentation - Link

About

sequence submitter from user interface

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors