opcua-session-manager · master
Docs · Recipes

Upgrading to v4.5

Bump to v4.5.0. Two inherited changes need attention: subscription notifications are typed objects now, and server certificates are bound to the endpoint ApplicationUri by default. The IPC envelope is unchanged.

v4.5 is a lock-step release with php-opcua/opcua-client v4.5.0 — the core's security-hardening release. The session manager itself gained no new commands and no new IPC surface; what it gained is the plumbing for two core changes that cross the daemon boundary.

Two things need your attention:

  1. Subscription notifications are typed objects. Application code that reads $publishResult->notifications with array offsets must move to properties.
  2. The server certificate is now bound to the endpoint's ApplicationUri, and the check is on by default. Servers with a misconfigured SAN extension will start failing.

Everything else — the IPC envelope, the CLI, the cache codec, the ManagedClient API — is unchanged.

Step 1 — Update Composer

bash terminal
composer require php-opcua/opcua-session-manager:^4.5

This pulls v4.5.0 and the matching opcua-client ^4.5 as a transitive dependency. Pin tighter (~4.5.0) if you want to vet patches before they roll out.

Step 2 — Migrate notification handling

The core's PublishResult::$notifications used to hold associative arrays with a 'type' discriminator. It now holds DataChangeNotification and EventNotification objects. ManagedClient::publish() returns them decoded — TypeSerializer rebuilds the typed instance, with a real DataValue / Variant inside, on the client side of the socket.

php v4.4 — array offsets
foreach ($client->publish()->notifications as $n) {
    if ($n['type'] === 'DataChange') {
        echo $n['clientHandle'], ' → ', var_export($n['dataValue'], true), PHP_EOL;
    }
}
php v4.5 — typed objects
use PhpOpcua\Client\Module\Subscription\DataChangeNotification;
use PhpOpcua\Client\Module\Subscription\EventNotification;

foreach ($client->publish()->notifications as $n) {
    if ($n instanceof DataChangeNotification) {
        echo $n->clientHandle, ' → ', var_export($n->dataValue->getValue(), true), PHP_EOL;
    }

    if ($n instanceof EventNotification) {
        echo $n->clientHandle, ' → ', count($n->eventFields), ' fields', PHP_EOL;
    }
}

Note that $n->dataValue is a real DataValue — in v4.4 the value that came back over IPC was still the serialized array, so this is a fix as much as a migration.

If you use auto-publish, there is nothing to migrate. The PSR-14 events (DataChangeReceived, EventNotificationReceived, …) carry the same payload they always did.

Step 3 — Decide on ApplicationUri verification

The core now requires the server certificate's SAN ApplicationUri to match the ApplicationUri the endpoint declares in its ApplicationDescription during discovery. On mismatch it throws UntrustedCertificateException, so a certificate trusted for server A is no longer accepted from server B.

The check is on by default. If one of your servers has a misconfigured SAN extension, opt out for that session only:

php php — per-session opt-out
$client = (new ManagedClient())
    ->setSecurityPolicy(SecurityPolicy::Basic256Sha256)
    ->setSecurityMode(SecurityMode::SignAndEncrypt)
    ->verifyApplicationUri(false);

$client->open('opc.tcp://legacy-plc.example:4840');

The flag rides in the open command's config object as verifyApplicationUri, lands in SessionConfig, and is applied to that session's ClientBuilder. Leave it unset to keep the core default (verification on).

Treat the opt-out as a workaround for a broken server, not a default — it disables the check that stops one server from presenting another's trusted certificate.

Step 4 — Verify the daemon version

bash terminal — verify
vendor/bin/opcua-session-manager --version
# → opcua-session-manager 4.5.0

What did not change

  • IPC envelope shape. Still the flat {command, sessionId?, method?, params?, args?, authToken?} request and {success, data | error} response. No new commands.
  • Notification payload on the wire. Notifications keep the {type, clientHandle, dataValue|eventFields} envelope the daemon has emitted since v4.0 — only the PHP type on either end changed. Version skew therefore works in both directions (see below).
  • ManagedClient public API. One method added (verifyApplicationUri()); nothing removed, renamed, or re-signed.
  • CLI flag names and defaults. Same set as v4.4.
  • Cache codec. Still Cache\WireCacheCodec. No reseed required.

What did change

Inherited from opcua-client v4.5.0

  • CreateSessionResponse.serverSignature is verified (Part 4 §5.6.2 proof of possession) — previously read and discarded.
  • The ECDH ephemeral key signature is verified on ECC profiles before the key is accepted for nonce derivation.
  • Server certificate ↔ endpoint ApplicationUri binding, with the verifyApplicationUri(bool) opt-out (Step 3).
  • Secure channel headers are validatedchannelId / tokenId must match the negotiated values and sequence numbers must increase strictly (anti-replay, Part 6 §6.7.2.4).
  • Trust store decisions no longer rely on SHA-1 aloneFileTrustStore compares stored DER via SHA-256, keeping SHA-1 only for file naming.
  • PublishResult::$notifications holds typed objects (Step 2), and the wire DTOs (NodeId, DataValue, Variant, EndpointDescription, the module result DTOs, …) are now final.
  • EndpointDescription gained a nullable applicationUri, round-tripped across IPC by TypeSerializer.
  • PHPStan level 9 on the core's src/, no baseline.

Added in opcua-session-manager v4.5.0

  • TypeSerializer handles the typed notifications in both directions. Without this a Publish response carrying any notification aborted the daemon's reply with SerializationException.
  • ManagedClient::verifyApplicationUri() plus SessionConfig::$verifyApplicationUri and the matching ClientBuilder wiring in CommandHandler::buildClientFromConfig().
  • EndpointDescription::$applicationUri round-trips across IPC, so getEndpoints() results carry it.
  • SessionManagerDaemon::VERSION bumped to '4.5.0'.

See the full CHANGELOG for the line-by-line list.

Compatibility note — client / daemon version skew

Because the notification payload on the wire is unchanged, skew works in both directions:

  • A v4.5 ManagedClient against a v4.4 daemon decodes the daemon's Publish reply into typed objects — the daemon emits the same {type, …} envelope either way.
  • A v4.4 ManagedClient against a v4.5 daemon keeps receiving arrays, exactly as before.

The one asymmetry is verifyApplicationUri: a pre-v4.5 daemon ignores the config key (SessionConfig::fromArray() has always dropped unknown keys), so the opt-out silently does nothing there. That is safe — a v4.4 daemon does not perform the check in the first place.

Upgrade order: daemon first, then ManagedClient instances, so the security checks are active before application code starts relying on the typed notifications.

Rollback

Rolling back to v4.4 is safe at the protocol level. At the application level, revert the Step 2 migration first — a v4.4 ManagedClient hands back arrays, so instanceof checks silently stop matching rather than failing loudly.

bash terminal — rollback
composer require php-opcua/opcua-session-manager:^4.4