org.eclipse.milo.opcua.sdk.server.SessionManager.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.milo.opcua.sdk.server.SessionManager.java

Source

/*
 * Copyright (c) 2019 the Eclipse Milo Authors
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 */

package org.eclipse.milo.opcua.sdk.server;

import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.math.DoubleMath;
import com.google.common.primitives.Bytes;
import org.eclipse.milo.opcua.sdk.server.identity.IdentityValidator;
import org.eclipse.milo.opcua.sdk.server.services.ServiceAttributes;
import org.eclipse.milo.opcua.stack.core.StatusCodes;
import org.eclipse.milo.opcua.stack.core.UaException;
import org.eclipse.milo.opcua.stack.core.UaRuntimeException;
import org.eclipse.milo.opcua.stack.core.security.CertificateValidator;
import org.eclipse.milo.opcua.stack.core.security.SecurityAlgorithm;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.OpcUaDataTypeManager;
import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString;
import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode;
import org.eclipse.milo.opcua.stack.core.types.structured.ActivateSessionRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.ActivateSessionResponse;
import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionResponse;
import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription;
import org.eclipse.milo.opcua.stack.core.types.structured.SignatureData;
import org.eclipse.milo.opcua.stack.core.types.structured.SignedSoftwareCertificate;
import org.eclipse.milo.opcua.stack.core.types.structured.UserIdentityToken;
import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy;
import org.eclipse.milo.opcua.stack.core.util.CertificateUtil;
import org.eclipse.milo.opcua.stack.core.util.CertificateValidationUtil;
import org.eclipse.milo.opcua.stack.core.util.EndpointUtil;
import org.eclipse.milo.opcua.stack.core.util.NonceUtil;
import org.eclipse.milo.opcua.stack.core.util.SignatureUtil;
import org.eclipse.milo.opcua.stack.server.services.AttributeHistoryServiceSet;
import org.eclipse.milo.opcua.stack.server.services.AttributeServiceSet;
import org.eclipse.milo.opcua.stack.server.services.MethodServiceSet;
import org.eclipse.milo.opcua.stack.server.services.MonitoredItemServiceSet;
import org.eclipse.milo.opcua.stack.server.services.NodeManagementServiceSet;
import org.eclipse.milo.opcua.stack.server.services.QueryServiceSet;
import org.eclipse.milo.opcua.stack.server.services.ServiceRequest;
import org.eclipse.milo.opcua.stack.server.services.SessionServiceSet;
import org.eclipse.milo.opcua.stack.server.services.SubscriptionServiceSet;
import org.eclipse.milo.opcua.stack.server.services.ViewServiceSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.collect.Lists.newCopyOnWriteArrayList;
import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint;
import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l;
import static org.eclipse.milo.opcua.stack.core.util.DigestUtil.sha1;

public class SessionManager
        implements AttributeServiceSet, AttributeHistoryServiceSet, MethodServiceSet, MonitoredItemServiceSet,
        NodeManagementServiceSet, QueryServiceSet, SessionServiceSet, SubscriptionServiceSet, ViewServiceSet {

    private static final int MAX_SESSION_TIMEOUT_MS = 120000;

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final Map<NodeId, Session> createdSessions = Maps.newConcurrentMap();
    private final Map<NodeId, Session> activeSessions = Maps.newConcurrentMap();
    private final Map<NodeId, Session> inactiveSessions = Maps.newConcurrentMap();

    /**
     * Store the last N client nonces and to make sure they aren't re-used.
     * <p>
     * This number is arbitrary; trying to prevent clients from re-using nonces is merely to satisfy the CTT.
     */
    private final List<ByteString> clientNonces = newCopyOnWriteArrayList();

    private final OpcUaServer server;

    public SessionManager(OpcUaServer server) {
        this.server = server;
    }

    public List<Session> getActiveSessions() {
        return Lists.newArrayList(activeSessions.values());
    }

    public List<Session> getInactiveSessions() {
        return Lists.newArrayList(inactiveSessions.values());
    }

    public void killSession(NodeId nodeId, boolean deleteSubscriptions) {
        activeSessions.values().stream().filter(s -> s.getSessionId().equals(nodeId)).findFirst()
                .ifPresent(s -> s.close(deleteSubscriptions));
    }

    private Session session(ServiceRequest service) throws UaException {
        long secureChannelId = service.getSecureChannelId();
        NodeId authToken = service.getRequest().getRequestHeader().getAuthenticationToken();

        Session session = activeSessions.get(authToken);

        if (session == null) {
            session = createdSessions.remove(authToken);

            if (session == null) {
                throw new UaException(StatusCodes.Bad_SessionIdInvalid);
            } else {
                if (session.getSecureChannelId() != secureChannelId) {
                    createdSessions.put(authToken, session);
                    throw new UaException(StatusCodes.Bad_SecurityChecksFailed);
                } else {
                    throw new UaException(StatusCodes.Bad_SessionNotActivated);
                }
            }
        }

        if (session.getSecureChannelId() != secureChannelId) {
            throw new UaException(StatusCodes.Bad_SecureChannelIdInvalid);
        }

        session.updateLastActivity();

        service.attr(ServiceAttributes.SERVER_KEY).set(server);
        service.attr(ServiceAttributes.SESSION_KEY).set(session);

        return session;
    }

    //region Session Services
    @Override
    public void onCreateSession(ServiceRequest serviceRequest) throws UaException {
        CreateSessionRequest request = (CreateSessionRequest) serviceRequest.getRequest();

        long maxSessionCount = server.getConfig().getLimits().getMaxSessionCount().longValue();
        if (createdSessions.size() + activeSessions.size() >= maxSessionCount) {
            serviceRequest.setServiceFault(StatusCodes.Bad_TooManySessions);
            return;
        }

        ByteString serverNonce = NonceUtil.generateNonce(32);
        NodeId authenticationToken = new NodeId(0, NonceUtil.generateNonce(32));
        long maxRequestMessageSize = serviceRequest.getServer().getConfig().getMessageLimits().getMaxMessageSize();
        double revisedSessionTimeout = Math.max(5000,
                Math.min(MAX_SESSION_TIMEOUT_MS, request.getRequestedSessionTimeout()));

        long secureChannelId = serviceRequest.getSecureChannelId();
        EndpointDescription endpoint = serviceRequest.getEndpoint();

        SecurityPolicy securityPolicy = SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri());

        EndpointDescription[] serverEndpoints = server.getEndpointDescriptions().stream()
                .filter(ed -> endpointMatchesUrl(ed, request.getEndpointUrl())).toArray(EndpointDescription[]::new);

        ByteString clientNonce = request.getClientNonce();

        if (clientNonce.isNotNull() && (clientNonce.length() < 32)) {
            throw new UaException(StatusCodes.Bad_NonceInvalid);
        }

        if (securityPolicy != SecurityPolicy.None && clientNonces.contains(clientNonce)) {
            throw new UaException(StatusCodes.Bad_NonceInvalid);
        }

        if (securityPolicy != SecurityPolicy.None && clientNonce.isNotNull()) {
            clientNonces.add(clientNonce);
            while (clientNonces.size() > 64) {
                clientNonces.remove(0);
            }
        }

        ByteString clientCertificateBytes = request.getClientCertificate();

        if (securityPolicy != SecurityPolicy.None && serviceRequest.getClientCertificateBytes() != null) {

            if (!Objects.equal(clientCertificateBytes, serviceRequest.getClientCertificateBytes())) {

                throw new UaException(StatusCodes.Bad_SecurityChecksFailed,
                        "certificate used to open secure channel "
                                + "differs from certificate used to create session");
            }
        }

        SecurityConfiguration securityConfiguration = createSecurityConfiguration(endpoint, clientCertificateBytes);

        if (securityPolicy != SecurityPolicy.None) {
            X509Certificate clientCertificate = securityConfiguration.getClientCertificate();

            List<X509Certificate> clientCertificateChain = securityConfiguration.getClientCertificateChain();

            if (clientCertificate == null || clientCertificateChain == null) {
                throw new UaException(StatusCodes.Bad_SecurityChecksFailed, "client certificate must be non-null");
            }

            String applicationUri = request.getClientDescription().getApplicationUri();

            CertificateValidationUtil.validateApplicationUri(clientCertificate, applicationUri);

            CertificateValidator certificateValidator = server.getConfig().getCertificateValidator();

            certificateValidator.validate(clientCertificate);
            certificateValidator.verifyTrustChain(clientCertificateChain);
        }

        // SignatureData must be created using only the bytes of the client
        // leaf certificate, not the bytes of the client certificate chain.
        SignatureData serverSignature = getServerSignature(securityPolicy, securityConfiguration.getKeyPair(),
                clientNonce, securityConfiguration.getClientCertificateBytes());

        NodeId sessionId = new NodeId(1, "Session:" + UUID.randomUUID());
        String sessionName = request.getSessionName();
        Duration sessionTimeout = Duration.ofMillis(DoubleMath.roundToLong(revisedSessionTimeout, RoundingMode.UP));

        Session session = new Session(server, sessionId, sessionName, sessionTimeout, secureChannelId, endpoint,
                securityConfiguration);

        session.setLastNonce(serverNonce);

        session.addLifecycleListener((s, remove) -> {
            createdSessions.remove(authenticationToken);
            activeSessions.remove(authenticationToken);
        });

        createdSessions.put(authenticationToken, session);

        CreateSessionResponse response = new CreateSessionResponse(serviceRequest.createResponseHeader(), sessionId,
                authenticationToken, revisedSessionTimeout, serverNonce, endpoint.getServerCertificate(),
                serverEndpoints, new SignedSoftwareCertificate[0], serverSignature, uint(maxRequestMessageSize));

        serviceRequest.setResponse(response);
    }

    private SecurityConfiguration createSecurityConfiguration(EndpointDescription endpoint,
            ByteString clientCertificateBytes) throws UaException {

        SecurityPolicy securityPolicy = SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri());
        MessageSecurityMode securityMode = endpoint.getSecurityMode();

        X509Certificate clientCertificate = null;
        List<X509Certificate> clientCertificateChain = null;

        KeyPair keyPair = null;
        X509Certificate serverCertificate = null;
        List<X509Certificate> serverCertificateChain = null;

        if (securityPolicy != SecurityPolicy.None) {
            clientCertificate = CertificateUtil.decodeCertificate(clientCertificateBytes.bytes());

            clientCertificateChain = CertificateUtil.decodeCertificates(clientCertificateBytes.bytes());

            ByteString thumbprint = ByteString.of(sha1(endpoint.getServerCertificate().bytesOrEmpty()));

            keyPair = server.getConfig().getCertificateManager().getKeyPair(thumbprint)
                    .orElseThrow(() -> new UaException(StatusCodes.Bad_ConfigurationError));

            serverCertificate = server.getConfig().getCertificateManager().getCertificate(thumbprint)
                    .orElseThrow(() -> new UaException(StatusCodes.Bad_ConfigurationError));

            serverCertificateChain = server.getConfig().getCertificateManager().getCertificateChain(thumbprint)
                    .map(Lists::newArrayList)
                    .orElseThrow(() -> new UaException(StatusCodes.Bad_ConfigurationError));
        }

        return new SecurityConfiguration(securityPolicy, securityMode, keyPair, serverCertificate,
                serverCertificateChain, clientCertificate, clientCertificateChain);
    }

    private boolean endpointMatchesUrl(EndpointDescription endpoint, String requestedEndpointUrl) {
        try {
            String requestedHost = EndpointUtil.getHost(requestedEndpointUrl);
            String endpointHost = EndpointUtil.getHost(endpoint.getEndpointUrl());

            return Strings.nullToEmpty(requestedHost).equalsIgnoreCase(Strings.nullToEmpty(endpointHost));
        } catch (Throwable e) {
            logger.warn("Unable to create URI.", e);
            return false;
        }
    }

    @Override
    public void onActivateSession(ServiceRequest serviceRequest) throws UaException {

        ActivateSessionRequest request = (ActivateSessionRequest) serviceRequest.getRequest();

        // ServerSecureChannel secureChannel = serviceRequest.getSecureChannel();

        long secureChannelId = serviceRequest.getSecureChannelId();
        NodeId authToken = request.getRequestHeader().getAuthenticationToken();
        List<SignedSoftwareCertificate> clientSoftwareCertificates = l(request.getClientSoftwareCertificates());

        Session session = createdSessions.get(authToken);

        if (session == null) {
            session = activeSessions.get(authToken);

            if (session == null) {
                throw new UaException(StatusCodes.Bad_SessionIdInvalid);
            } else {
                verifyClientSignature(session, request);

                SecurityConfiguration securityConfiguration = session.getSecurityConfiguration();

                if (session.getSecureChannelId() == secureChannelId) {
                    /*
                     * Identity change
                     */
                    Object tokenObject = request.getUserIdentityToken()
                            .decode(server.getConfig().getEncodingLimits(), OpcUaDataTypeManager.getInstance());

                    Object identityObject = validateIdentityToken(session, tokenObject,
                            request.getUserTokenSignature());

                    StatusCode[] results = new StatusCode[clientSoftwareCertificates.size()];
                    Arrays.fill(results, StatusCode.GOOD);

                    ByteString serverNonce = NonceUtil.generateNonce(32);

                    session.setClientAddress(serviceRequest.getClientAddress());
                    session.setIdentityObject(identityObject);
                    session.setLastNonce(serverNonce);
                    session.setLocaleIds(request.getLocaleIds());

                    ActivateSessionResponse response = new ActivateSessionResponse(
                            serviceRequest.createResponseHeader(), serverNonce, results, new DiagnosticInfo[0]);

                    serviceRequest.setResponse(response);
                } else {
                    /*
                     * Associate session with new secure channel if client certificate and identity token match.
                     */
                    ByteString clientCertificateBytes = serviceRequest.getClientCertificateBytes();

                    if (request.getUserIdentityToken() == null || request.getUserIdentityToken().decode() == null) {
                        throw new UaException(StatusCodes.Bad_IdentityTokenInvalid, "identity token not provided");
                    }

                    Object tokenObject = request.getUserIdentityToken()
                            .decode(server.getConfig().getEncodingLimits(), OpcUaDataTypeManager.getInstance());

                    Object identityObject = validateIdentityToken(session, tokenObject,
                            request.getUserTokenSignature());

                    boolean sameIdentity = Objects.equal(identityObject, session.getIdentityObject());

                    boolean sameCertificate = Objects.equal(clientCertificateBytes,
                            securityConfiguration.getClientCertificateBytes());

                    if (sameIdentity && sameCertificate) {
                        SecurityConfiguration newSecurityConfiguration = createSecurityConfiguration(
                                serviceRequest.getEndpoint(), clientCertificateBytes);

                        session.setEndpoint(serviceRequest.getEndpoint());
                        session.setSecureChannelId(secureChannelId);
                        session.setSecurityConfiguration(newSecurityConfiguration);

                        logger.debug("Session id={} is now associated with secureChannelId={}",
                                session.getSessionId(), secureChannelId);

                        StatusCode[] results = new StatusCode[clientSoftwareCertificates.size()];
                        Arrays.fill(results, StatusCode.GOOD);

                        ByteString serverNonce = NonceUtil.generateNonce(32);

                        session.setClientAddress(serviceRequest.getClientAddress());
                        session.setLastNonce(serverNonce);
                        session.setLocaleIds(request.getLocaleIds());

                        ActivateSessionResponse response = new ActivateSessionResponse(
                                serviceRequest.createResponseHeader(), serverNonce, results, new DiagnosticInfo[0]);

                        serviceRequest.setResponse(response);
                    } else {
                        throw new UaException(StatusCodes.Bad_SecurityChecksFailed);
                    }
                }
            }
        } else {
            if (secureChannelId != session.getSecureChannelId()) {
                throw new UaException(StatusCodes.Bad_SecurityChecksFailed);
            }

            if (request.getUserIdentityToken() == null || request.getUserIdentityToken().decode() == null) {
                throw new UaException(StatusCodes.Bad_IdentityTokenInvalid, "identity token not provided");
            }

            verifyClientSignature(session, request);

            Object tokenObject = request.getUserIdentityToken().decode(server.getConfig().getEncodingLimits(),
                    OpcUaDataTypeManager.getInstance());

            Object identityObject = validateIdentityToken(session, tokenObject, request.getUserTokenSignature());

            createdSessions.remove(authToken);
            activeSessions.put(authToken, session);

            StatusCode[] results = new StatusCode[clientSoftwareCertificates.size()];
            Arrays.fill(results, StatusCode.GOOD);

            ByteString serverNonce = NonceUtil.generateNonce(32);

            session.setClientAddress(serviceRequest.getClientAddress());
            session.setIdentityObject(identityObject);
            session.setLocaleIds(request.getLocaleIds());
            session.setLastNonce(serverNonce);

            ActivateSessionResponse response = new ActivateSessionResponse(serviceRequest.createResponseHeader(),
                    serverNonce, results, new DiagnosticInfo[0]);

            serviceRequest.setResponse(response);
        }
    }

    private static void verifyClientSignature(Session session, ActivateSessionRequest request) throws UaException {
        SecurityConfiguration securityConfiguration = session.getSecurityConfiguration();

        if (securityConfiguration.getSecurityPolicy() != SecurityPolicy.None) {
            SignatureData clientSignature = request.getClientSignature();

            byte[] dataBytes = Bytes.concat(securityConfiguration.getServerCertificateBytes().bytesOrEmpty(),
                    session.getLastNonce().bytesOrEmpty());

            byte[] signatureBytes = clientSignature.getSignature().bytesOrEmpty();

            SignatureUtil.verify(SecurityAlgorithm.fromUri(clientSignature.getAlgorithm()),
                    securityConfiguration.getClientCertificate(), dataBytes, signatureBytes);
        }
    }

    private Object validateIdentityToken(Session session, Object tokenObject, SignatureData tokenSignature)
            throws UaException {

        IdentityValidator identityValidator = server.getConfig().getIdentityValidator();
        UserTokenPolicy tokenPolicy = validatePolicyId(session, tokenObject);

        if (tokenObject instanceof UserIdentityToken) {
            return identityValidator.validateIdentityToken(session, (UserIdentityToken) tokenObject, tokenPolicy,
                    tokenSignature);
        } else {
            throw new UaException(StatusCodes.Bad_IdentityTokenInvalid);
        }
    }

    /**
     * Validates the policyId on a {@link UserIdentityToken} Object is a policyId that exists on the Endpoint that
     * {@code session} is connected to.
     *
     * @param session     the current {@link Session}
     * @param tokenObject the {@link UserIdentityToken} Object from the client.
     * @return the first {@link UserTokenPolicy} on the Endpoint matching the policyId.
     * @throws UaException if the token object is invalid or no matching policy is found.
     */
    private UserTokenPolicy validatePolicyId(Session session, Object tokenObject) throws UaException {
        if (tokenObject instanceof UserIdentityToken) {
            UserIdentityToken token = (UserIdentityToken) tokenObject;
            String policyId = token.getPolicyId();

            List<UserTokenPolicy> userIdentityTokens = l(session.getEndpoint().getUserIdentityTokens());

            Optional<UserTokenPolicy> policy = userIdentityTokens.stream()
                    .filter(t -> Objects.equal(policyId, t.getPolicyId())).findFirst();

            return policy.orElseThrow(
                    () -> new UaException(StatusCodes.Bad_IdentityTokenInvalid, "policy not found: " + policyId));
        } else {
            throw new UaException(StatusCodes.Bad_IdentityTokenInvalid);
        }
    }

    @Override
    public void onCloseSession(ServiceRequest service) throws UaException {
        long secureChannelId = service.getSecureChannelId();
        NodeId authToken = service.getRequest().getRequestHeader().getAuthenticationToken();

        Session session = activeSessions.get(authToken);

        if (session != null) {
            if (session.getSecureChannelId() != secureChannelId) {
                throw new UaException(StatusCodes.Bad_SecureChannelIdInvalid);
            } else {
                activeSessions.remove(authToken);
                session.onCloseSession(service);
            }
        } else {
            session = createdSessions.get(authToken);

            if (session == null) {
                throw new UaException(StatusCodes.Bad_SessionIdInvalid);
            } else if (session.getSecureChannelId() != secureChannelId) {
                throw new UaException(StatusCodes.Bad_SecureChannelIdInvalid);
            } else {
                createdSessions.remove(authToken);
                session.onCloseSession(service);
            }
        }
    }

    @Override
    public void onCancel(ServiceRequest service) throws UaException {
        session(service).onCancel(service);
    }

    private SignatureData getServerSignature(SecurityPolicy securityPolicy, KeyPair keyPair, ByteString clientNonce,
            ByteString clientCertificate) throws UaException {

        if (securityPolicy == SecurityPolicy.None) {
            return new SignatureData(null, null);
        } else {
            try {
                SecurityAlgorithm algorithm = securityPolicy.getAsymmetricSignatureAlgorithm();

                byte[] data = Bytes.concat(clientCertificate.bytes(), clientNonce.bytes());

                byte[] signature = SignatureUtil.sign(algorithm, keyPair.getPrivate(), ByteBuffer.wrap(data));

                return new SignatureData(algorithm.getUri(), ByteString.of(signature));
            } catch (UaRuntimeException e) {
                throw new UaException(StatusCodes.Bad_SecurityChecksFailed);
            }
        }
    }
    //endregion

    //region Attribute Services
    @Override
    public void onRead(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getAttributeServiceSet().onRead(service);
    }

    @Override
    public void onWrite(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getAttributeServiceSet().onWrite(service);
    }

    @Override
    public void onHistoryRead(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getAttributeHistoryServiceSet().onHistoryRead(service);
    }

    @Override
    public void onHistoryUpdate(ServiceRequest service) throws UaException {

        Session session = session(service);

        session.getAttributeHistoryServiceSet().onHistoryUpdate(service);
    }
    //endregion

    //region View Services
    @Override
    public void onBrowse(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getViewServiceSet().onBrowse(service);
    }

    @Override
    public void onBrowseNext(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getViewServiceSet().onBrowseNext(service);
    }

    @Override
    public void onTranslateBrowsePaths(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getViewServiceSet().onTranslateBrowsePaths(service);
    }

    @Override
    public void onRegisterNodes(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getViewServiceSet().onRegisterNodes(service);
    }

    @Override
    public void onUnregisterNodes(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getViewServiceSet().onUnregisterNodes(service);
    }
    //endregion

    //region NodeManagement Services
    @Override
    public void onAddNodes(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getNodeManagementServiceSet().onAddNodes(service);
    }

    @Override
    public void onAddReferences(ServiceRequest service) throws UaException {

        Session session = session(service);

        session.getNodeManagementServiceSet().onAddReferences(service);
    }

    @Override
    public void onDeleteNodes(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getNodeManagementServiceSet().onDeleteNodes(service);
    }

    @Override
    public void onDeleteReferences(ServiceRequest service) throws UaException {

        Session session = session(service);

        session.getNodeManagementServiceSet().onDeleteReferences(service);
    }
    //endregion

    //region Subscription Services
    @Override
    public void onCreateSubscription(ServiceRequest service) throws UaException {

        Session session = session(service);

        session.getSubscriptionServiceSet().onCreateSubscription(service);
    }

    @Override
    public void onModifySubscription(ServiceRequest service) throws UaException {

        Session session = session(service);

        session.getSubscriptionServiceSet().onModifySubscription(service);
    }

    @Override
    public void onSetPublishingMode(ServiceRequest service) throws UaException {

        Session session = session(service);

        session.getSubscriptionServiceSet().onSetPublishingMode(service);
    }

    @Override
    public void onPublish(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getSubscriptionServiceSet().onPublish(service);
    }

    @Override
    public void onRepublish(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getSubscriptionServiceSet().onRepublish(service);
    }

    @Override
    public void onTransferSubscriptions(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getSubscriptionServiceSet().onTransferSubscriptions(service);
    }

    @Override
    public void onDeleteSubscriptions(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getSubscriptionServiceSet().onDeleteSubscriptions(service);
    }
    //endregion

    //region MonitoredItem Services
    @Override
    public void onCreateMonitoredItems(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getMonitoredItemServiceSet().onCreateMonitoredItems(service);
    }

    @Override
    public void onModifyMonitoredItems(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getMonitoredItemServiceSet().onModifyMonitoredItems(service);
    }

    @Override
    public void onSetMonitoringMode(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getMonitoredItemServiceSet().onSetMonitoringMode(service);
    }

    @Override
    public void onSetTriggering(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getMonitoredItemServiceSet().onSetTriggering(service);
    }

    @Override
    public void onDeleteMonitoredItems(ServiceRequest service) throws UaException {

        Session session = session(service);

        session.getMonitoredItemServiceSet().onDeleteMonitoredItems(service);
    }
    //endregion

    //region Method Services
    @Override
    public void onCall(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getMethodServiceSet().onCall(service);
    }
    //endregion

    //region Query Services
    @Override
    public void onQueryFirst(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getQueryServiceSet().onQueryFirst(service);
    }

    @Override
    public void onQueryNext(ServiceRequest service) throws UaException {
        Session session = session(service);

        session.getQueryServiceSet().onQueryNext(service);
    }
    //endregion

}