Eclipse Milo、UaExpert:没有匹配会话安全设置的端点

Eclipse Milo, UaExpert: no endpoint matching the session security settings

我想用 UaExpert 测试一个简单的 OPC-UA 服务器。服务器已启动,当我尝试使用 UaExpert 连接服务器时,我不断收到以下消息

18:18:48.633 | Server Node        | test                    | Endpoint: 'opc.tcp://DESKTOP-ss:12686/test'
18:18:48.633 | Server Node        | test                    | Security policy: 'http://opcfoundation.org/UA/SecurityPolicy#None'
18:18:48.633 | Server Node        | test                    | ApplicationUri: 'com:test'
18:18:48.633 | Server Node        | test                    | Used UserTokenType: Anonymous
18:18:48.633 | Server Node        | test                    | The server returned no certificate, all certificate checks will be skipped.
18:18:48.664 | General            |                         | Error: UaSessionPrivate::activateSession - no endpoint matching the session security settings
18:18:48.664 | Server Node        | test                    | Error 'BadConfigurationError' was returned during ActivateSession
18:18:48.664 | Server Node        | test                    | Connection status of server 'test' changed to 'Disconnected'.

我正在使用提供的 ExampleServer,并连接到没有安全和匿名策略的服务器。

有人可以帮忙吗?

编辑 - 2018 年 1 月 12 日

我的代码如下:

OPCUA接口Class

public class OPCUAInterface {

    private static final String OPCUA_APP_URI = "com:test";

    private final OpcUaServer server;

    public static void main(String[] args) throws Exception {
        OPCUAInterface server = new OPCUAInterface();

        server.startup().get();

        final CompletableFuture<Void> future = new CompletableFuture<>();

        Runtime.getRuntime().addShutdownHook(new Thread(() -> future.complete(null)));

        future.get();
    }

    public OPCUAInterface() throws Exception {
        File securityTempDir = new File(System.getProperty("java.io.tmpdir"), "security");
        if (!securityTempDir.exists() && !securityTempDir.mkdirs()) {
            throw new Exception("unable to create security temp dir: " + securityTempDir);
        }
        LoggerFactory.getLogger(getClass()).info("security temp dir: {}", securityTempDir.getAbsolutePath());

//        KeyStoreLoader loader = new KeyStoreLoader().load(securityTempDir);

        DefaultCertificateManager certificateManager = new DefaultCertificateManager(
//            loader.getServerKeyPair(),
//            loader.getServerCertificateChain()
        );

        File pkiDir = securityTempDir.toPath().resolve("pki").toFile();
        DirectoryCertificateValidator certificateValidator = new DirectoryCertificateValidator(pkiDir);

        UsernameIdentityValidator identityValidator = new UsernameIdentityValidator(
                true,
                authChallenge -> {
                    String username = authChallenge.getUsername();
                    String password = authChallenge.getPassword();

                    boolean userOk = "test".equals(username) && "test".equals(password);
                    boolean adminOk = "admin".equals(username) && "password2".equals(password);

                    return userOk || adminOk;
                }
            );

        X509IdentityValidator x509IdentityValidator = new X509IdentityValidator(c -> true);

        List<String> bindAddresses = new ArrayList<>();
        bindAddresses.add("0.0.0.0");

        List<String> endpointAddresses = new ArrayList<>();
        endpointAddresses.add(HostnameUtil.getHostname());
        endpointAddresses.addAll(HostnameUtil.getHostnames("0.0.0.0"));

        String applicationUri = OPCUA_APP_URI;
        OpcUaServerConfig serverConfig = OpcUaServerConfig.builder()
            .setApplicationUri(applicationUri)
            .setApplicationName(LocalizedText.english("test program"))
            .setBindPort(62547)
            .setBindAddresses(bindAddresses)
            .setEndpointAddresses(endpointAddresses)
            .setBuildInfo(
                new BuildInfo(
                    applicationUri,
                    "test",
                    "test program",
                    OpcUaServer.SDK_VERSION,
                    "0.1", DateTime.now()))
            .setCertificateManager(certificateManager)
            .setCertificateValidator(certificateValidator)
            .setIdentityValidator(new CompositeValidator(identityValidator, x509IdentityValidator,
                    AnonymousIdentityValidator.INSTANCE))
            .setProductUri(applicationUri)
            .setServerName("test")
            .setSecurityPolicies(
                EnumSet.of(
                    SecurityPolicy.None,
                    SecurityPolicy.Basic128Rsa15,
                    SecurityPolicy.Basic256,
                    SecurityPolicy.Basic256Sha256,
                    SecurityPolicy.Aes128_Sha256_RsaOaep,
                    SecurityPolicy.Aes256_Sha256_RsaPss
                    ))
            .setUserTokenPolicies(
                ImmutableList.of(
                    USER_TOKEN_POLICY_ANONYMOUS,
                    USER_TOKEN_POLICY_USERNAME,
                    USER_TOKEN_POLICY_X509
                    ))
            .build();


        server = new OpcUaServer(serverConfig);

        server.getNamespaceManager().registerAndAdd(
            TestNameSpace.NAMESPACE_URI,
            idx -> new TestNameSpace(server, idx));
    }

    public OpcUaServer getServer() {
        return server;
    }

    public CompletableFuture<OpcUaServer> startup() {
        return server.startup();
    }

    public CompletableFuture<OpcUaServer> shutdown() {
        return server.shutdown();
    }
}

测试名称空间Class

public class TestNameSpace implements Namespace {
    final static Logger logger = LogManager.getLogger(TestNameSpace.class);
    public static final String NAMESPACE_URI = "com:test:mytest";
    private OpcUaServer server;
    private UShort namespaceIndex;
    private SubscriptionModel subscriptionModel;
    private NodeFactory nodeFactory;

    public TestNameSpace(OpcUaServer server, UShort namespaceIndex) {
        this.server = server;
        this.namespaceIndex = namespaceIndex;

        subscriptionModel = new SubscriptionModel(server, this);

        nodeFactory = new NodeFactory(
                server.getNodeMap(),
                server.getObjectTypeManager(),
                server.getVariableTypeManager()
            );
        try {
            NodeId folderNodeId = new NodeId(namespaceIndex, "test");

            UaFolderNode folderNode = new UaFolderNode(
                    server.getNodeMap(),
                    folderNodeId,
                    new QualifiedName(namespaceIndex, "test"),
                    LocalizedText.english("test")
                );

            server.getNodeMap().addNode(folderNode);

            // Make sure our new folder shows up under the server's Objects folder
            server.getUaNamespace().addReference(
                Identifiers.ObjectsFolder,
                Identifiers.Organizes,
                true,
                folderNodeId.expanded(),
                NodeClass.Object
            );
        } catch (UaException e) {
            logger.error("Error loading nodes: " + e.getMessage() + " " + e);
        }
    }

    @Override
    public void read(ReadContext context, Double maxAge, TimestampsToReturn timestamps, List<ReadValueId> readValueIds) {
        // TODO Auto-generated method stub

    }

    @Override
    public void write(WriteContext context, List<WriteValue> writeValues) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onDataItemsCreated(List<DataItem> dataItems) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onDataItemsModified(List<DataItem> dataItems) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onDataItemsDeleted(List<DataItem> dataItems) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onMonitoringModeChanged(List<MonitoredItem> monitoredItems) {
        // TODO Auto-generated method stub

    }

    @Override
    public CompletableFuture<List<Reference>> browse(AccessContext context, NodeId nodeId) {
        ServerNode node = server.getNodeMap().get(nodeId);

        if (node != null) {
            return CompletableFuture.completedFuture(node.getReferences());
        } else {
            return FutureUtils.failedFuture(new UaException(StatusCodes.Bad_NodeIdUnknown));
        }
    }

    @Override
    public UShort getNamespaceIndex() {
        // TODO Auto-generated method stub
        return namespaceIndex;
    }

    @Override
    public String getNamespaceUri() {
        // TODO Auto-generated method stub
        return NAMESPACE_URI;
    }

}

我无法复制您所看到的确切问题。使用未修改的示例服务器和命名空间 UaExpert 连接没有问题。

使用您的代码会出现一堆超时错误,因为您的命名空间实现不完整。