Skip to main content

Automatic License Acquisition

Describes the automatic license acquisition service, which polls for and installs a license on an unlicensed deployment, automating the manual upload

Overview

The Automatic License Acquisition service (SpecariaLicenseAcquisitionService) automates the process of obtaining and activating a license for a deployment. Its primary purpose is to prevent a newly enrolled deployment from remaining in an unlicensed state while waiting for an operator to manually download and upload a license file.

This service runs within the admin-api component. On application startup and at a regular, configurable interval, it checks if the deployment has an active, valid license. If the deployment is unlicensed (including being in a bootstrap or disabled state), the service polls a central Specaria platform API to determine if a license has been issued.

If a new license JWT is available, the service downloads and activates it using the same validation and installation path as a manual license upload. This process verifies the JWT against the platform's JSON Web Key Set (JWKS) and persists it. When a license is installed by this service, the uploaded_by audit field is set to auto-acquisition.

This service is designed to be "fail-open." Any errors during the acquisition process, such as network failures or license validation issues, are logged without crashing the application or the polling mechanism. The deployment continues to operate with its existing license state, and the service will retry on its next scheduled run.

How It Works

The license acquisition logic is triggered in two ways:

  1. On startup: A single attempt is made once the application is fully initialized (ApplicationReadyEvent).
  2. Periodically: A scheduled task runs at a fixed delay.

Both triggers execute the same core logic, which follows a best-effort, fail-open approach. The service only attempts acquisition if the deployment does not already have an active, valid license; it does not handle proactive renewal for licenses that are nearing expiration.

The following diagram illustrates the decision flow for each acquisition attempt.

flowchart TD
    subgraph Acquisition Cycle
        A[Start: Triggered by Startup or Schedule] --> B{Feature Enabled?};
        B -- No --> Z[Stop];
        B -- Yes --> C{Deployment Licensed?};
        C -- Yes --> Z;
        C -- No --> D[Fetch Issued License from Platform];
        D --> E{License Found?};
        E -- No/Error --> F[Log Warning & Stop];
        E -- Yes --> G[Extract JTI from New License];
        G --> H{JTI Matches Active License?};
        H -- Yes --> I[Log Idempotency Skip & Stop];
        H -- No --> J[Activate New License];
        J -- Success --> K[Log Success & Stop];
        J -- Failure --> F;
    end

Acquisition Steps

Each time the service runs, it performs the following sequence of operations:

  1. Check if Enabled: The service first calls acquireClient.isEnabled(). If this returns false (indicating the deployment is not yet configured with a platform deployment ID), the entire process is skipped.

  2. Check Current License State: It inspects the deployment's current license state. If the licenseMode is already "licensed", it means a valid, full license is active, and the service does nothing. States such as a bootstrap grace period or a disabled license are considered "unlicensed" and will trigger an acquisition attempt.

  3. Fetch Issued License: The service calls acquireClient.fetchIssuedLicense() to request the license JWT from the Specaria platform. If the platform returns no license (e.g., via an HTTP 204 No Content response), the service stops.

  4. Perform Idempotency Check: If a license JWT is returned, the service performs an idempotency check to avoid redundant work. It extracts the JWT ID (jti claim) from the newly fetched license and compares it to the jti of the currently active license. If they are identical, the service logs that the license is already active and stops. This prevents re-activating the same license on every cycle.

  5. Activate License: If the fetched license is new, the service passes the JWT to licenseValidator.uploadAndActivate(). This is the same internal method used for manual license uploads. It performs a full validation of the JWT (including signature, claims, and expiration) and, if valid, writes it to the s2r_license store.

Security and Logging

To maintain secret hygiene, the service never logs the full license JWT. On successful activation, it logs only the license's jti and the trigger (startup or scheduled).

Example success log:

INFO  S2R-LIC auto-acquired license jti=a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8 (trigger=scheduled)

Configuration

The polling frequency of the service is controlled by a single configuration property.

NameTypeDefaultRequiredDescription
s2r.specaria.license-acquire-intervalString (ISO-8601 Duration)PT6HNoThe interval between periodic acquisition attempts.

NOTE

The default value PT6H represents a 6-hour interval. To disable periodic polling (while keeping the startup check), you can set this value to a very large duration.

Troubleshooting

The service is designed to fail open, meaning failures will not impact the running deployment.

ConditionTriggerLog MessageMeaning & Resolution
Acquisition FailedAny Exception during the process, such as a network error, upstream server error, or a JWT validation failure (e.g., bad signature, expired token, aud mismatch).WARN S2R-LIC auto-acquire failed (fail-open, trigger=...): <error_message>The acquisition attempt failed. The deployment continues with its current license state. The service will automatically retry on the next scheduled interval. Check the error message for details on the cause (e.g., network connectivity to the Specaria platform).
Idempotency SkipThe platform returned a license that is already active on the deployment (same jti).DEBUG S2R-LIC auto-acquire: issued license jti=... already active — skippingThis is normal operational behavior, not an error. The service correctly identified that no update was needed. No action is required.

See Also

  • Manual License Management: The automatic service uses the same underlying LicenseValidator as the manual license upload process.
  • Deployment Tenant Binding: The service's operations are executed within a tenant context provided by the DeploymentTenantBinding component.
Tagsguides

All SOAP-to-REST docs