Project

General

Profile

Administration REST API

Introduction

Some of the administrative functionality (of the runtime system) can be accessed via a REST API hosted inside the FWD Application Server. Over time, all administrative functionality will be exposed via this mechanism.

This is composed of multiple sub-modules, and it behaves as a hub for all of them offering some services:
  • a common bootstrap procedure (see below, the initialization);
  • a common context prefix (/admin/)
  • a shared authentication (using /admin/login and /admin/logout paths/endpoints)
  • a shared authorization using a common token.

See #7080 for details on this work.

Setup / Configuration

In order to enable support in FWD, the module must first enabled in directory.xml. Together with this flag a session timeout can be set. This is done by adding the following entry under /server/<server-id> or /server/default/:

        <node class="container" name="admin-rest">
          <node class="boolean" name="enabled">
            <node-attribute name="value" value="TRUE"/>
          </node>
          <node class="integer" name="timeout">
            <node-attribute name="value" value="3600"/>
          </node>
        </node>

A value different of TRUE for enabled flag will disable the module (along with all sub-modules) at next server startup.
The timeout represents the number of seconds after which the FWD context of the session will automatically be destroyed and a new login is necessary. If set to zero, the context will live until a logout operation is performed (WARNING: missing a logout operation will lead to memory leaks, when timeout is set to zero).

If the administration module is enabled, at server's startup FWD will scan all sub-modules and will request an initialization for each one sequentially. It's up to each submodule to assess the environment (own directory entries, configuration files, loaded database schemas, etc) and decide whether it is active or not. The necessary configurations are described below, for each submodule, individually.

Each feature of each submodule can be individually authorized using ACLs. The ACLs require a list of subjects. A module must be authenticated as one of these users to be able to execute a specific request. The granularity allows different HTTP methods and different context sub-paths for each module. The login and logout are always accessible, and not bound to any ACL.

For a FWD user to be able to be used in a REST request the webServiceToken must be set into directory.xml. Here is an example:

    <node class="container" name="security">
      <node class="container" name="accounts">
        <node class="container" name="users">
          <node class="user" name="restAdmin">
            <node-attribute name="enabled" value="TRUE"/>
            <node-attribute name="groups" value="admins"/>
            <node-attribute name="groups" value="everybody"/>
            <node-attribute name="person" value="REST Admin"/>
            <node-attribute name="alias" value="shared"/>
            <node-attribute name="protected" value="FALSE"/>
            <node-attribute name="webServiceToken" value="[rest-admin-token]"/>
          </node>
        </node>

Finally, in /security/config/resource-plugins container add the following item to list, if not already present:

<node-attribute name="values" value="com.goldencode.p2j.security.WebServiceResource"/>

Authentication

To be able to execute any of the sub-module REST request, the admin (restAdmin as mentioned above) must be authenticated using login call:
API GET /admin/login
Request Authentication Type: Basic Auth, Username: restAdmin, Password: [rest-admin-token]
Headers <none>
Body <empty>
Response Headers FwdSessionId will be set to an UUID (e.g.: 0ea12c7b-9c76-4bdb-8e8e-450d93b3b065) which will be needed to be passed back on subsequent requests
Body <empty>
To close a session, use the following call:
API GET /admin/logout
Request Authentication <none>
Headers FwdSessionId (the UUID received from the login call (in our example, 0ea12c7b-9c76-4bdb-8e8e-450d93b3b065)
Body <empty>
Response Headers <none>
Body <empty>

API Reference

Legacy Security Authentication Administration API
Tenant Administration API
Session Management API
Hooks Management API
User Management API
Certs Management API
SOAP WSDL Management API
Passkey Management API

Usage in bash Scripts

A practical example for how to use the REST API in bash follows. The api function would be a helper that makes invocation very easy. Just make sure the session ID is handled properly, since it is needed in all subsequent APIs.

#!/bin/bash

set -euo pipefail

##############################################################################
# Verify required external tools
##############################################################################

require_command()
{
   local cmd="$1" 

   if ! command -v "$cmd" >/dev/null 2>&1; then
      echo "ERROR: required command not found: $cmd" >&2
      exit 1
   fi
}

require_command curl
require_command jq
require_command awk

##############################################################################
# Common configuration
##############################################################################

base_url="https://localhost:8443" 

session_id="" 

##############################################################################
# Login
##############################################################################

login()
{
   local rest_user="$1" 
   local rest_token="$2" 
   local headers
   local session_id

   headers="$(
      curl \
         --silent \
         --show-error \
         --fail \
         --location \
         --user "${rest_user}:${rest_token}" \
         --dump-header - \
         --output /dev/null \
         "${base_url}/admin/login" 
   )" 

   session_id="$(
      awk '
         BEGIN { IGNORECASE=1 }

         /^FwdSessionId:/ {
            gsub("\r", "", $2)
            print $2
         }
      ' <<< "$headers" 
   )" 

   if [[ -z "$session_id" ]]; then
      echo "ERROR: login failed, missing FwdSessionId" >&2
      return 1
   fi

   printf '%s\n' "$session_id" 
   return 0
}

##############################################################################
# Logout
##############################################################################

logout()
{
   local session_id="$1" 

   if [[ -z "${session_id:-}" ]]; then
      echo "WARNING: no active session" >&2
      return 0
   fi

   curl \
      --silent \
      --show-error \
      --fail \
      --location \
      --request GET \
      --header "FwdSessionId: ${session_id}" \
      --output /dev/null \
      "${base_url}/admin/logout" 

   echo "Logged out successfully" 
   return 0
}

##############################################################################
# Common REST API wrapper
##############################################################################

function api()
{
   local session_id="$1" 
   local method="$2" 
   local path="$3" 
   local body="${4:-}" 

   local response
   local http_code

   response="$(
      curl \
         --silent \
         --show-error \
         --location \
         --write-out $'\n%{http_code}' \
         --request "$method" \
         --header "FwdSessionId: ${session_id}" \
         --header "Content-Type: application/json" \
         ${body:+--data "$body"} \
         "${base_url}${path}" 
   )" 

   http_code="${response##*$'\n'}" 
   response="${response%$'\n'*}" 

   if [[ "$http_code" -lt 200 || "$http_code" -ge 300 ]]; then
      printf 'ERROR: %s %s failed with HTTP %s\n' \
         "$method" "$path" "$http_code" >&2

      if jq -e . >/dev/null 2>&1 <<< "$response"; then
         jq . <<< "$response" >&2
      else
         printf '%s\n' "$response" >&2
      fi

      return 1
   fi

   printf '%s\n' "$response" 
   return 0
}

##############################################################################
# Example usage
##############################################################################

rest_user="restAdmin" 
rest_token="admin" 

if ! session_id="$(login "$rest_user" "$rest_token")"; then
   echo "Login failed" >&2
   exit 1
fi

# Trap to logout so we don't need to explicitly logout after script failures
trap 'logout "$session_id" >/dev/null 2>&1 || true' EXIT

# Sample User Management APIs

# Get users
if response="$(api "$session_id" GET "/admin/security/users")"; then
   jq . <<< "$response" 
else
   echo "List users failed" >&2
   exit 1
fi
user_count="$(
   jq '.users | length' <<< "$response" 
)" 
echo "Found ${user_count} users" 

# Create a user
user="jdoe" 
email="jdoe@example.com" 
enabled=true
person="John Doe" 
password="SecureP@ss123" 
groups="users,everybody" 
json="$(
   jq -n \
      --arg user "$user" \
      --arg email "$email" \
      --arg person "$person" \
      --arg password "$password" \
      --arg groups "$groups" \
      --argjson enabled "$enabled" \
      '
      {
         name: $user,
         email: $email,
         enabled: $enabled,
         person: $person,
         password: $password,
         groups: (
            $groups
            | split(",")
            | map(gsub("^\\s+|\\s+$"; ""))
         )
      }
      '
)" 
if response="$(api "$session_id" POST "/admin/security/users" "$json")"; then
   jq . <<< "$response" 
else
   echo "Create user=${user} failed" >&2
   jq . <<< "$response" 
   exit 1
fi

logout "$session_id" 

© 2024-2025 Golden Code Development Corporation. ALL RIGHTS RESERVED.