diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milo-browse.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milo-browse.json index 5994b4e3f3044..ccd89d0aff60b 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milo-browse.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milo-browse.json @@ -48,7 +48,10 @@ "requestedPublishingInterval": { "index": 21, "kind": "property", "displayName": "Requested Publishing Interval", "group": "client", "label": "client", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1_000.0", "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The requested publishing interval in milliseconds" }, "requestTimeout": { "index": 22, "kind": "property", "displayName": "Request Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, "sessionName": { "index": 23, "kind": "property", "displayName": "Session Name", "group": "client", "label": "client", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session name" }, - "sessionTimeout": { "index": 24, "kind": "property", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" } + "sessionTimeout": { "index": 24, "kind": "property", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" }, + "certificateValidator": { "index": 25, "kind": "property", "displayName": "Certificate Validator", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.security.CertificateValidator", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "A custom validator for the certificate of the OPC UA server. When set, it is used instead of the trust list configured with trustListDirectory. Endpoints share a connection only when they use the same validator instance." }, + "trustAllCertificates": { "index": 26, "kind": "property", "displayName": "Trust All Certificates", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Whether to accept any certificate presented by the OPC UA server. This is insecure: the connection is encrypted, but the client does not authenticate the server it talks to. It only applies when neither certificateValidator nor trustListDirectory is configured." }, + "trustListDirectory": { "index": 27, "kind": "property", "displayName": "Trust List Directory", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The directory holding the trust list used to validate the certificate of the OPC UA server, in the layout used by Eclipse Milo: trusted certificates in trusted\/certs, CRLs of trusted certificates in trusted\/crl, certificates of issuing CAs in issuer\/certs and their CRLs in issuer\/crl. The directories are created if they do not exist. Besides the chain of trust, the validity period, the revocation by a CRL of the trust list and the application URI of the server certificate are checked. A certificate issued by a CA is refused when the trust list holds no CRL of that CA; an empty CRL is enough. A server certificate that does not chain up to a trusted certificate is written to rejected\/certs, from where it can be moved to trusted\/certs once it has been checked." } }, "headers": { "CamelMiloNodeIds": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The node ids.", "constantName": "org.apache.camel.component.milo.MiloConstants#HEADER_NODE_IDS" } @@ -84,6 +87,9 @@ "requestedPublishingInterval": { "index": 27, "kind": "parameter", "displayName": "Requested Publishing Interval", "group": "client", "label": "client", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1_000.0", "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The requested publishing interval in milliseconds" }, "requestTimeout": { "index": 28, "kind": "parameter", "displayName": "Request Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, "sessionName": { "index": 29, "kind": "parameter", "displayName": "Session Name", "group": "client", "label": "client", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session name" }, - "sessionTimeout": { "index": 30, "kind": "parameter", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" } + "sessionTimeout": { "index": 30, "kind": "parameter", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" }, + "certificateValidator": { "index": 31, "kind": "parameter", "displayName": "Certificate Validator", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.security.CertificateValidator", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "A custom validator for the certificate of the OPC UA server. When set, it is used instead of the trust list configured with trustListDirectory. Endpoints share a connection only when they use the same validator instance." }, + "trustAllCertificates": { "index": 32, "kind": "parameter", "displayName": "Trust All Certificates", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Whether to accept any certificate presented by the OPC UA server. This is insecure: the connection is encrypted, but the client does not authenticate the server it talks to. It only applies when neither certificateValidator nor trustListDirectory is configured." }, + "trustListDirectory": { "index": 33, "kind": "parameter", "displayName": "Trust List Directory", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The directory holding the trust list used to validate the certificate of the OPC UA server, in the layout used by Eclipse Milo: trusted certificates in trusted\/certs, CRLs of trusted certificates in trusted\/crl, certificates of issuing CAs in issuer\/certs and their CRLs in issuer\/crl. The directories are created if they do not exist. Besides the chain of trust, the validity period, the revocation by a CRL of the trust list and the application URI of the server certificate are checked. A certificate issued by a CA is refused when the trust list holds no CRL of that CA; an empty CRL is enough. A server certificate that does not chain up to a trusted certificate is written to rejected\/certs, from where it can be moved to trusted\/certs once it has been checked." } } } diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milo-client.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milo-client.json index 7ff0b561032f5..d411080554fa2 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milo-client.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milo-client.json @@ -49,7 +49,10 @@ "requestedPublishingInterval": { "index": 22, "kind": "property", "displayName": "Requested Publishing Interval", "group": "client", "label": "client", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1_000.0", "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The requested publishing interval in milliseconds" }, "requestTimeout": { "index": 23, "kind": "property", "displayName": "Request Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, "sessionName": { "index": 24, "kind": "property", "displayName": "Session Name", "group": "client", "label": "client", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session name" }, - "sessionTimeout": { "index": 25, "kind": "property", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" } + "sessionTimeout": { "index": 25, "kind": "property", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" }, + "certificateValidator": { "index": 26, "kind": "property", "displayName": "Certificate Validator", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.security.CertificateValidator", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "A custom validator for the certificate of the OPC UA server. When set, it is used instead of the trust list configured with trustListDirectory. Endpoints share a connection only when they use the same validator instance." }, + "trustAllCertificates": { "index": 27, "kind": "property", "displayName": "Trust All Certificates", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Whether to accept any certificate presented by the OPC UA server. This is insecure: the connection is encrypted, but the client does not authenticate the server it talks to. It only applies when neither certificateValidator nor trustListDirectory is configured." }, + "trustListDirectory": { "index": 28, "kind": "property", "displayName": "Trust List Directory", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The directory holding the trust list used to validate the certificate of the OPC UA server, in the layout used by Eclipse Milo: trusted certificates in trusted\/certs, CRLs of trusted certificates in trusted\/crl, certificates of issuing CAs in issuer\/certs and their CRLs in issuer\/crl. The directories are created if they do not exist. Besides the chain of trust, the validity period, the revocation by a CRL of the trust list and the application URI of the server certificate are checked. A certificate issued by a CA is refused when the trust list holds no CRL of that CA; an empty CRL is enough. A server certificate that does not chain up to a trusted certificate is written to rejected\/certs, from where it can be moved to trusted\/certs once it has been checked." } }, "headers": { "CamelMiloNodeIds": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The node ids.", "constantName": "org.apache.camel.component.milo.MiloConstants#HEADER_NODE_IDS" }, @@ -90,6 +93,9 @@ "requestedPublishingInterval": { "index": 31, "kind": "parameter", "displayName": "Requested Publishing Interval", "group": "client", "label": "client", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1_000.0", "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The requested publishing interval in milliseconds" }, "requestTimeout": { "index": 32, "kind": "parameter", "displayName": "Request Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, "sessionName": { "index": 33, "kind": "parameter", "displayName": "Session Name", "group": "client", "label": "client", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session name" }, - "sessionTimeout": { "index": 34, "kind": "parameter", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" } + "sessionTimeout": { "index": 34, "kind": "parameter", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" }, + "certificateValidator": { "index": 35, "kind": "parameter", "displayName": "Certificate Validator", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.security.CertificateValidator", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "A custom validator for the certificate of the OPC UA server. When set, it is used instead of the trust list configured with trustListDirectory. Endpoints share a connection only when they use the same validator instance." }, + "trustAllCertificates": { "index": 36, "kind": "parameter", "displayName": "Trust All Certificates", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Whether to accept any certificate presented by the OPC UA server. This is insecure: the connection is encrypted, but the client does not authenticate the server it talks to. It only applies when neither certificateValidator nor trustListDirectory is configured." }, + "trustListDirectory": { "index": 37, "kind": "parameter", "displayName": "Trust List Directory", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The directory holding the trust list used to validate the certificate of the OPC UA server, in the layout used by Eclipse Milo: trusted certificates in trusted\/certs, CRLs of trusted certificates in trusted\/crl, certificates of issuing CAs in issuer\/certs and their CRLs in issuer\/crl. The directories are created if they do not exist. Besides the chain of trust, the validity period, the revocation by a CRL of the trust list and the application URI of the server certificate are checked. A certificate issued by a CA is refused when the trust list holds no CRL of that CA; an empty CRL is enough. A server certificate that does not chain up to a trusted certificate is written to rejected\/certs, from where it can be moved to trusted\/certs once it has been checked." } } } diff --git a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseComponentConfigurer.java b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseComponentConfigurer.java index 6354a32100ef7..180ba22add871 100644 --- a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseComponentConfigurer.java +++ b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseComponentConfigurer.java @@ -38,6 +38,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "applicationUri": getOrCreateConfiguration(target).setApplicationUri(property(camelContext, java.lang.String.class, value)); return true; case "autowiredenabled": case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true; + case "certificatevalidator": + case "certificateValidator": getOrCreateConfiguration(target).setCertificateValidator(property(camelContext, org.eclipse.milo.opcua.stack.core.security.CertificateValidator.class, value)); return true; case "channellifetime": case "channelLifetime": getOrCreateConfiguration(target).setChannelLifetime(property(camelContext, java.lang.Long.class, value)); return true; case "clientid": @@ -79,6 +81,10 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "sessionName": getOrCreateConfiguration(target).setSessionName(property(camelContext, java.lang.String.class, value)); return true; case "sessiontimeout": case "sessionTimeout": getOrCreateConfiguration(target).setSessionTimeout(property(camelContext, java.lang.Long.class, value)); return true; + case "trustallcertificates": + case "trustAllCertificates": getOrCreateConfiguration(target).setTrustAllCertificates(property(camelContext, boolean.class, value)); return true; + case "trustlistdirectory": + case "trustListDirectory": getOrCreateConfiguration(target).setTrustListDirectory(property(camelContext, java.lang.String.class, value)); return true; default: return false; } } @@ -99,6 +105,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "applicationUri": return java.lang.String.class; case "autowiredenabled": case "autowiredEnabled": return boolean.class; + case "certificatevalidator": + case "certificateValidator": return org.eclipse.milo.opcua.stack.core.security.CertificateValidator.class; case "channellifetime": case "channelLifetime": return java.lang.Long.class; case "clientid": @@ -140,6 +148,10 @@ public Class getOptionType(String name, boolean ignoreCase) { case "sessionName": return java.lang.String.class; case "sessiontimeout": case "sessionTimeout": return java.lang.Long.class; + case "trustallcertificates": + case "trustAllCertificates": return boolean.class; + case "trustlistdirectory": + case "trustListDirectory": return java.lang.String.class; default: return null; } } @@ -156,6 +168,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "applicationUri": return getOrCreateConfiguration(target).getApplicationUri(); case "autowiredenabled": case "autowiredEnabled": return target.isAutowiredEnabled(); + case "certificatevalidator": + case "certificateValidator": return getOrCreateConfiguration(target).getCertificateValidator(); case "channellifetime": case "channelLifetime": return getOrCreateConfiguration(target).getChannelLifetime(); case "clientid": @@ -197,6 +211,10 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "sessionName": return getOrCreateConfiguration(target).getSessionName(); case "sessiontimeout": case "sessionTimeout": return getOrCreateConfiguration(target).getSessionTimeout(); + case "trustallcertificates": + case "trustAllCertificates": return getOrCreateConfiguration(target).isTrustAllCertificates(); + case "trustlistdirectory": + case "trustListDirectory": return getOrCreateConfiguration(target).getTrustListDirectory(); default: return null; } } diff --git a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseEndpointConfigurer.java b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseEndpointConfigurer.java index 708c394aee225..bc13d5bc47519 100644 --- a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseEndpointConfigurer.java +++ b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseEndpointConfigurer.java @@ -29,6 +29,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "applicationName": target.getConfiguration().setApplicationName(property(camelContext, java.lang.String.class, value)); return true; case "applicationuri": case "applicationUri": target.getConfiguration().setApplicationUri(property(camelContext, java.lang.String.class, value)); return true; + case "certificatevalidator": + case "certificateValidator": target.getConfiguration().setCertificateValidator(property(camelContext, org.eclipse.milo.opcua.stack.core.security.CertificateValidator.class, value)); return true; case "channellifetime": case "channelLifetime": target.getConfiguration().setChannelLifetime(property(camelContext, java.lang.Long.class, value)); return true; case "clientid": @@ -78,6 +80,10 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "sessionName": target.getConfiguration().setSessionName(property(camelContext, java.lang.String.class, value)); return true; case "sessiontimeout": case "sessionTimeout": target.getConfiguration().setSessionTimeout(property(camelContext, java.lang.Long.class, value)); return true; + case "trustallcertificates": + case "trustAllCertificates": target.getConfiguration().setTrustAllCertificates(property(camelContext, boolean.class, value)); return true; + case "trustlistdirectory": + case "trustListDirectory": target.getConfiguration().setTrustListDirectory(property(camelContext, java.lang.String.class, value)); return true; default: return false; } } @@ -91,6 +97,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "applicationName": return java.lang.String.class; case "applicationuri": case "applicationUri": return java.lang.String.class; + case "certificatevalidator": + case "certificateValidator": return org.eclipse.milo.opcua.stack.core.security.CertificateValidator.class; case "channellifetime": case "channelLifetime": return java.lang.Long.class; case "clientid": @@ -140,6 +148,10 @@ public Class getOptionType(String name, boolean ignoreCase) { case "sessionName": return java.lang.String.class; case "sessiontimeout": case "sessionTimeout": return java.lang.Long.class; + case "trustallcertificates": + case "trustAllCertificates": return boolean.class; + case "trustlistdirectory": + case "trustListDirectory": return java.lang.String.class; default: return null; } } @@ -154,6 +166,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "applicationName": return target.getConfiguration().getApplicationName(); case "applicationuri": case "applicationUri": return target.getConfiguration().getApplicationUri(); + case "certificatevalidator": + case "certificateValidator": return target.getConfiguration().getCertificateValidator(); case "channellifetime": case "channelLifetime": return target.getConfiguration().getChannelLifetime(); case "clientid": @@ -203,6 +217,10 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "sessionName": return target.getConfiguration().getSessionName(); case "sessiontimeout": case "sessionTimeout": return target.getConfiguration().getSessionTimeout(); + case "trustallcertificates": + case "trustAllCertificates": return target.getConfiguration().isTrustAllCertificates(); + case "trustlistdirectory": + case "trustListDirectory": return target.getConfiguration().getTrustListDirectory(); default: return null; } } diff --git a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseEndpointUriFactory.java b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseEndpointUriFactory.java index 634fb4f4e9fd8..c7588b62882cc 100644 --- a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseEndpointUriFactory.java +++ b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/browse/MiloBrowseEndpointUriFactory.java @@ -23,10 +23,11 @@ public class MiloBrowseEndpointUriFactory extends org.apache.camel.support.compo private static final Set SECRET_PROPERTY_NAMES; private static final Map MULTI_VALUE_PREFIXES; static { - Set props = new HashSet<>(31); + Set props = new HashSet<>(34); props.add("allowedSecurityPolicies"); props.add("applicationName"); props.add("applicationUri"); + props.add("certificateValidator"); props.add("channelLifetime"); props.add("clientId"); props.add("depth"); @@ -55,6 +56,8 @@ public class MiloBrowseEndpointUriFactory extends org.apache.camel.support.compo props.add("requestedPublishingInterval"); props.add("sessionName"); props.add("sessionTimeout"); + props.add("trustAllCertificates"); + props.add("trustListDirectory"); PROPERTY_NAMES = Collections.unmodifiableSet(props); Set secretProps = new HashSet<>(2); secretProps.add("keyPassword"); diff --git a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientComponentConfigurer.java b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientComponentConfigurer.java index b28d4fe4fc692..0cc55b55642e0 100644 --- a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientComponentConfigurer.java +++ b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientComponentConfigurer.java @@ -40,6 +40,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true; case "bridgeerrorhandler": case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "certificatevalidator": + case "certificateValidator": getOrCreateConfiguration(target).setCertificateValidator(property(camelContext, org.eclipse.milo.opcua.stack.core.security.CertificateValidator.class, value)); return true; case "channellifetime": case "channelLifetime": getOrCreateConfiguration(target).setChannelLifetime(property(camelContext, java.lang.Long.class, value)); return true; case "clientid": @@ -81,6 +83,10 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "sessionName": getOrCreateConfiguration(target).setSessionName(property(camelContext, java.lang.String.class, value)); return true; case "sessiontimeout": case "sessionTimeout": getOrCreateConfiguration(target).setSessionTimeout(property(camelContext, java.lang.Long.class, value)); return true; + case "trustallcertificates": + case "trustAllCertificates": getOrCreateConfiguration(target).setTrustAllCertificates(property(camelContext, boolean.class, value)); return true; + case "trustlistdirectory": + case "trustListDirectory": getOrCreateConfiguration(target).setTrustListDirectory(property(camelContext, java.lang.String.class, value)); return true; default: return false; } } @@ -103,6 +109,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "autowiredEnabled": return boolean.class; case "bridgeerrorhandler": case "bridgeErrorHandler": return boolean.class; + case "certificatevalidator": + case "certificateValidator": return org.eclipse.milo.opcua.stack.core.security.CertificateValidator.class; case "channellifetime": case "channelLifetime": return java.lang.Long.class; case "clientid": @@ -144,6 +152,10 @@ public Class getOptionType(String name, boolean ignoreCase) { case "sessionName": return java.lang.String.class; case "sessiontimeout": case "sessionTimeout": return java.lang.Long.class; + case "trustallcertificates": + case "trustAllCertificates": return boolean.class; + case "trustlistdirectory": + case "trustListDirectory": return java.lang.String.class; default: return null; } } @@ -162,6 +174,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "autowiredEnabled": return target.isAutowiredEnabled(); case "bridgeerrorhandler": case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "certificatevalidator": + case "certificateValidator": return getOrCreateConfiguration(target).getCertificateValidator(); case "channellifetime": case "channelLifetime": return getOrCreateConfiguration(target).getChannelLifetime(); case "clientid": @@ -203,6 +217,10 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "sessionName": return getOrCreateConfiguration(target).getSessionName(); case "sessiontimeout": case "sessionTimeout": return getOrCreateConfiguration(target).getSessionTimeout(); + case "trustallcertificates": + case "trustAllCertificates": return getOrCreateConfiguration(target).isTrustAllCertificates(); + case "trustlistdirectory": + case "trustListDirectory": return getOrCreateConfiguration(target).getTrustListDirectory(); default: return null; } } diff --git a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientEndpointConfigurer.java b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientEndpointConfigurer.java index d5f5c46560e7c..77535b46e0590 100644 --- a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientEndpointConfigurer.java +++ b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientEndpointConfigurer.java @@ -31,6 +31,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "applicationUri": target.getConfiguration().setApplicationUri(property(camelContext, java.lang.String.class, value)); return true; case "bridgeerrorhandler": case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "certificatevalidator": + case "certificateValidator": target.getConfiguration().setCertificateValidator(property(camelContext, org.eclipse.milo.opcua.stack.core.security.CertificateValidator.class, value)); return true; case "channellifetime": case "channelLifetime": target.getConfiguration().setChannelLifetime(property(camelContext, java.lang.Long.class, value)); return true; case "clientid": @@ -89,6 +91,10 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "sessionName": target.getConfiguration().setSessionName(property(camelContext, java.lang.String.class, value)); return true; case "sessiontimeout": case "sessionTimeout": target.getConfiguration().setSessionTimeout(property(camelContext, java.lang.Long.class, value)); return true; + case "trustallcertificates": + case "trustAllCertificates": target.getConfiguration().setTrustAllCertificates(property(camelContext, boolean.class, value)); return true; + case "trustlistdirectory": + case "trustListDirectory": target.getConfiguration().setTrustListDirectory(property(camelContext, java.lang.String.class, value)); return true; default: return false; } } @@ -104,6 +110,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "applicationUri": return java.lang.String.class; case "bridgeerrorhandler": case "bridgeErrorHandler": return boolean.class; + case "certificatevalidator": + case "certificateValidator": return org.eclipse.milo.opcua.stack.core.security.CertificateValidator.class; case "channellifetime": case "channelLifetime": return java.lang.Long.class; case "clientid": @@ -162,6 +170,10 @@ public Class getOptionType(String name, boolean ignoreCase) { case "sessionName": return java.lang.String.class; case "sessiontimeout": case "sessionTimeout": return java.lang.Long.class; + case "trustallcertificates": + case "trustAllCertificates": return boolean.class; + case "trustlistdirectory": + case "trustListDirectory": return java.lang.String.class; default: return null; } } @@ -178,6 +190,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "applicationUri": return target.getConfiguration().getApplicationUri(); case "bridgeerrorhandler": case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "certificatevalidator": + case "certificateValidator": return target.getConfiguration().getCertificateValidator(); case "channellifetime": case "channelLifetime": return target.getConfiguration().getChannelLifetime(); case "clientid": @@ -236,6 +250,10 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "sessionName": return target.getConfiguration().getSessionName(); case "sessiontimeout": case "sessionTimeout": return target.getConfiguration().getSessionTimeout(); + case "trustallcertificates": + case "trustAllCertificates": return target.getConfiguration().isTrustAllCertificates(); + case "trustlistdirectory": + case "trustListDirectory": return target.getConfiguration().getTrustListDirectory(); default: return null; } } diff --git a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientEndpointUriFactory.java b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientEndpointUriFactory.java index 620430d4a19cf..292289503ff34 100644 --- a/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientEndpointUriFactory.java +++ b/components/camel-milo/src/generated/java/org/apache/camel/component/milo/client/MiloClientEndpointUriFactory.java @@ -23,11 +23,12 @@ public class MiloClientEndpointUriFactory extends org.apache.camel.support.compo private static final Set SECRET_PROPERTY_NAMES; private static final Map MULTI_VALUE_PREFIXES; static { - Set props = new HashSet<>(35); + Set props = new HashSet<>(38); props.add("allowedSecurityPolicies"); props.add("applicationName"); props.add("applicationUri"); props.add("bridgeErrorHandler"); + props.add("certificateValidator"); props.add("channelLifetime"); props.add("clientId"); props.add("dataChangeFilterDeadbandType"); @@ -59,6 +60,8 @@ public class MiloClientEndpointUriFactory extends org.apache.camel.support.compo props.add("samplingInterval"); props.add("sessionName"); props.add("sessionTimeout"); + props.add("trustAllCertificates"); + props.add("trustListDirectory"); PROPERTY_NAMES = Collections.unmodifiableSet(props); Set secretProps = new HashSet<>(2); secretProps.add("keyPassword"); diff --git a/components/camel-milo/src/generated/resources/META-INF/org/apache/camel/component/milo/browse/milo-browse.json b/components/camel-milo/src/generated/resources/META-INF/org/apache/camel/component/milo/browse/milo-browse.json index 5994b4e3f3044..ccd89d0aff60b 100644 --- a/components/camel-milo/src/generated/resources/META-INF/org/apache/camel/component/milo/browse/milo-browse.json +++ b/components/camel-milo/src/generated/resources/META-INF/org/apache/camel/component/milo/browse/milo-browse.json @@ -48,7 +48,10 @@ "requestedPublishingInterval": { "index": 21, "kind": "property", "displayName": "Requested Publishing Interval", "group": "client", "label": "client", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1_000.0", "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The requested publishing interval in milliseconds" }, "requestTimeout": { "index": 22, "kind": "property", "displayName": "Request Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, "sessionName": { "index": 23, "kind": "property", "displayName": "Session Name", "group": "client", "label": "client", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session name" }, - "sessionTimeout": { "index": 24, "kind": "property", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" } + "sessionTimeout": { "index": 24, "kind": "property", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" }, + "certificateValidator": { "index": 25, "kind": "property", "displayName": "Certificate Validator", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.security.CertificateValidator", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "A custom validator for the certificate of the OPC UA server. When set, it is used instead of the trust list configured with trustListDirectory. Endpoints share a connection only when they use the same validator instance." }, + "trustAllCertificates": { "index": 26, "kind": "property", "displayName": "Trust All Certificates", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Whether to accept any certificate presented by the OPC UA server. This is insecure: the connection is encrypted, but the client does not authenticate the server it talks to. It only applies when neither certificateValidator nor trustListDirectory is configured." }, + "trustListDirectory": { "index": 27, "kind": "property", "displayName": "Trust List Directory", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The directory holding the trust list used to validate the certificate of the OPC UA server, in the layout used by Eclipse Milo: trusted certificates in trusted\/certs, CRLs of trusted certificates in trusted\/crl, certificates of issuing CAs in issuer\/certs and their CRLs in issuer\/crl. The directories are created if they do not exist. Besides the chain of trust, the validity period, the revocation by a CRL of the trust list and the application URI of the server certificate are checked. A certificate issued by a CA is refused when the trust list holds no CRL of that CA; an empty CRL is enough. A server certificate that does not chain up to a trusted certificate is written to rejected\/certs, from where it can be moved to trusted\/certs once it has been checked." } }, "headers": { "CamelMiloNodeIds": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The node ids.", "constantName": "org.apache.camel.component.milo.MiloConstants#HEADER_NODE_IDS" } @@ -84,6 +87,9 @@ "requestedPublishingInterval": { "index": 27, "kind": "parameter", "displayName": "Requested Publishing Interval", "group": "client", "label": "client", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1_000.0", "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The requested publishing interval in milliseconds" }, "requestTimeout": { "index": 28, "kind": "parameter", "displayName": "Request Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, "sessionName": { "index": 29, "kind": "parameter", "displayName": "Session Name", "group": "client", "label": "client", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session name" }, - "sessionTimeout": { "index": 30, "kind": "parameter", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" } + "sessionTimeout": { "index": 30, "kind": "parameter", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" }, + "certificateValidator": { "index": 31, "kind": "parameter", "displayName": "Certificate Validator", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.security.CertificateValidator", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "A custom validator for the certificate of the OPC UA server. When set, it is used instead of the trust list configured with trustListDirectory. Endpoints share a connection only when they use the same validator instance." }, + "trustAllCertificates": { "index": 32, "kind": "parameter", "displayName": "Trust All Certificates", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Whether to accept any certificate presented by the OPC UA server. This is insecure: the connection is encrypted, but the client does not authenticate the server it talks to. It only applies when neither certificateValidator nor trustListDirectory is configured." }, + "trustListDirectory": { "index": 33, "kind": "parameter", "displayName": "Trust List Directory", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The directory holding the trust list used to validate the certificate of the OPC UA server, in the layout used by Eclipse Milo: trusted certificates in trusted\/certs, CRLs of trusted certificates in trusted\/crl, certificates of issuing CAs in issuer\/certs and their CRLs in issuer\/crl. The directories are created if they do not exist. Besides the chain of trust, the validity period, the revocation by a CRL of the trust list and the application URI of the server certificate are checked. A certificate issued by a CA is refused when the trust list holds no CRL of that CA; an empty CRL is enough. A server certificate that does not chain up to a trusted certificate is written to rejected\/certs, from where it can be moved to trusted\/certs once it has been checked." } } } diff --git a/components/camel-milo/src/generated/resources/META-INF/org/apache/camel/component/milo/client/milo-client.json b/components/camel-milo/src/generated/resources/META-INF/org/apache/camel/component/milo/client/milo-client.json index 7ff0b561032f5..d411080554fa2 100644 --- a/components/camel-milo/src/generated/resources/META-INF/org/apache/camel/component/milo/client/milo-client.json +++ b/components/camel-milo/src/generated/resources/META-INF/org/apache/camel/component/milo/client/milo-client.json @@ -49,7 +49,10 @@ "requestedPublishingInterval": { "index": 22, "kind": "property", "displayName": "Requested Publishing Interval", "group": "client", "label": "client", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1_000.0", "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The requested publishing interval in milliseconds" }, "requestTimeout": { "index": 23, "kind": "property", "displayName": "Request Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, "sessionName": { "index": 24, "kind": "property", "displayName": "Session Name", "group": "client", "label": "client", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session name" }, - "sessionTimeout": { "index": 25, "kind": "property", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" } + "sessionTimeout": { "index": 25, "kind": "property", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" }, + "certificateValidator": { "index": 26, "kind": "property", "displayName": "Certificate Validator", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.security.CertificateValidator", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "A custom validator for the certificate of the OPC UA server. When set, it is used instead of the trust list configured with trustListDirectory. Endpoints share a connection only when they use the same validator instance." }, + "trustAllCertificates": { "index": 27, "kind": "property", "displayName": "Trust All Certificates", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Whether to accept any certificate presented by the OPC UA server. This is insecure: the connection is encrypted, but the client does not authenticate the server it talks to. It only applies when neither certificateValidator nor trustListDirectory is configured." }, + "trustListDirectory": { "index": 28, "kind": "property", "displayName": "Trust List Directory", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The directory holding the trust list used to validate the certificate of the OPC UA server, in the layout used by Eclipse Milo: trusted certificates in trusted\/certs, CRLs of trusted certificates in trusted\/crl, certificates of issuing CAs in issuer\/certs and their CRLs in issuer\/crl. The directories are created if they do not exist. Besides the chain of trust, the validity period, the revocation by a CRL of the trust list and the application URI of the server certificate are checked. A certificate issued by a CA is refused when the trust list holds no CRL of that CA; an empty CRL is enough. A server certificate that does not chain up to a trusted certificate is written to rejected\/certs, from where it can be moved to trusted\/certs once it has been checked." } }, "headers": { "CamelMiloNodeIds": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The node ids.", "constantName": "org.apache.camel.component.milo.MiloConstants#HEADER_NODE_IDS" }, @@ -90,6 +93,9 @@ "requestedPublishingInterval": { "index": 31, "kind": "parameter", "displayName": "Requested Publishing Interval", "group": "client", "label": "client", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1_000.0", "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The requested publishing interval in milliseconds" }, "requestTimeout": { "index": 32, "kind": "parameter", "displayName": "Request Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, "sessionName": { "index": 33, "kind": "parameter", "displayName": "Session Name", "group": "client", "label": "client", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session name" }, - "sessionTimeout": { "index": 34, "kind": "parameter", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" } + "sessionTimeout": { "index": 34, "kind": "parameter", "displayName": "Session Timeout", "group": "client", "label": "client", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Session timeout in milliseconds" }, + "certificateValidator": { "index": 35, "kind": "parameter", "displayName": "Certificate Validator", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.eclipse.milo.opcua.stack.core.security.CertificateValidator", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "A custom validator for the certificate of the OPC UA server. When set, it is used instead of the trust list configured with trustListDirectory. Endpoints share a connection only when they use the same validator instance." }, + "trustAllCertificates": { "index": 36, "kind": "parameter", "displayName": "Trust All Certificates", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "Whether to accept any certificate presented by the OPC UA server. This is insecure: the connection is encrypted, but the client does not authenticate the server it talks to. It only applies when neither certificateValidator nor trustListDirectory is configured." }, + "trustListDirectory": { "index": 37, "kind": "parameter", "displayName": "Trust List Directory", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.milo.client.MiloClientConfiguration", "configurationField": "configuration", "description": "The directory holding the trust list used to validate the certificate of the OPC UA server, in the layout used by Eclipse Milo: trusted certificates in trusted\/certs, CRLs of trusted certificates in trusted\/crl, certificates of issuing CAs in issuer\/certs and their CRLs in issuer\/crl. The directories are created if they do not exist. Besides the chain of trust, the validity period, the revocation by a CRL of the trust list and the application URI of the server certificate are checked. A certificate issued by a CA is refused when the trust list holds no CRL of that CA; an empty CRL is enough. A server certificate that does not chain up to a trusted certificate is written to rejected\/certs, from where it can be moved to trusted\/certs once it has been checked." } } } diff --git a/components/camel-milo/src/main/docs/milo-browse-component.adoc b/components/camel-milo/src/main/docs/milo-browse-component.adoc index e1d0e997b38c4..38ffc11d309af 100644 --- a/components/camel-milo/src/main/docs/milo-browse-component.adoc +++ b/components/camel-milo/src/main/docs/milo-browse-component.adoc @@ -56,7 +56,7 @@ include::partial$component-endpoint-headers.adoc[] === Client The browse component shares the same base options like the Camel Milo Client component, e.g. concerning topics like discovery, -security policies, the construction of node ids, etc. +security policies, the validation of the server certificate, the construction of node ids, etc. Please refer to the documentation of the Camel Milo Client component for further details. diff --git a/components/camel-milo/src/main/docs/milo-client-component.adoc b/components/camel-milo/src/main/docs/milo-client-component.adoc index aabf96826b4b5..8e8181dbd2604 100644 --- a/components/camel-milo/src/main/docs/milo-client-component.adoc +++ b/components/camel-milo/src/main/docs/milo-client-component.adoc @@ -155,13 +155,63 @@ The known security policy URIs and enum literals are can be seen here: https://g NOTE: In any case security policies are considered case sensitive. +When `allowedSecurityPolicies` is not set, the client accepts every security policy the server offers and uses the +endpoint with the highest security level reported by the server, which can be `None`. To make sure the connection is +secured, set `allowedSecurityPolicies` to the secured policies you expect the server to offer. + +=== Validating the server certificate + +When the selected endpoint uses a security policy other than `None`, the client validates the certificate of the +server when it opens the secure channel and the session. Configure the trusted certificates with one of these options: + +* `trustListDirectory`: a directory holding the trust list, in the layout used by Eclipse Milo. Put the certificate of +the server, or the certificate of the CA that issued it, in `trusted/certs`. Certificates of intermediate CAs that are +only used to build the chain go in `issuer/certs`, and certificate revocation lists in `trusted/crl` and `issuer/crl`. +The directories are created if they do not exist. +* `certificateValidator`: a custom `org.eclipse.milo.opcua.stack.core.security.CertificateValidator`. It is used +instead of `trustListDirectory` when both are set. Endpoints share a connection only when they use the same validator +instance. + +With `trustListDirectory`, the client refuses a server certificate that: + +* does not chain up to a certificate in `trusted/certs`, possibly through the certificates in `issuer/certs`, +* is outside its validity period, +* is revoked by a certificate revocation list in `trusted/crl` or `issuer/crl`. A certificate issued by a CA is also +refused, with `Bad_CertificateRevocationUnknown`, when the trust list holds no revocation list of that CA. An empty +CRL signed by the CA is enough. A self-signed certificate in `trusted/certs` is not checked for revocation, +* or holds an application URI that differs from the one the server announces in its endpoint description. + +A failed host name, key usage or extended key usage check is only logged. A certificate that does not chain up to a +trusted certificate is written to `rejected/certs`, from where it can be moved to `trusted/certs` once it has been +checked. A certificate refused for another reason is not written there. To use other checks, configure a +`certificateValidator`, for example a `DefaultClientCertificateValidator` created with the `ValidationCheck` set you +need. + +If neither option is configured, the client does not connect to an endpoint that uses a security policy other than +`None`. Setting `trustAllCertificates` to `true` makes the client accept any server certificate instead. This is +insecure: the connection is encrypted, but the client does not authenticate the server it talks to. + +When the server certificate cannot be validated, the client logs a `WARN` message that starts with `Failed to +connect`, and tries again every 10 seconds, so a certificate moved to `trusted/certs` is used at the next attempt. A +producer fails with `IllegalStateException: No connected`, whose cause gives the reason. + +The same validator checks the server certificate that the user name and password are encrypted with. With the +security policy `None`, the server is not authenticated, whatever the configuration. + +A secured policy also requires a client certificate and key, configured with `keyStoreUrl` and the related options. +For example: + +---- +milo-client:opc.tcp://localhost:4840?node=RAW(ns=2;s=Temperature)&allowedSecurityPolicies=Basic256Sha256&keyStoreUrl=file:/etc/opcua/client.p12&keyStorePassword=RAW(changeit)&keyAlias=client&keyPassword=RAW(changeit)&trustListDirectory=/etc/opcua/pki +---- + ==== Milo 1.0.5 Migration Notes With Milo 1.0.5, several security-related API changes were introduced: * The `ServerCertificateValidator` class has been replaced with `CertificateValidator` in the core security package * Certificate validation now uses `org.eclipse.milo.opcua.stack.core.security.CertificateValidator` -* When configuring custom certificate validators, ensure you're using the updated API +* A validator configured with the `certificateValidator` option must implement this interface include::spring-boot:partial$starter.adoc[] diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConfiguration.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConfiguration.java index 1cafb8cd5f2ce..60fa4a2e9d179 100644 --- a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConfiguration.java +++ b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConfiguration.java @@ -30,6 +30,7 @@ import org.apache.camel.spi.UriParam; import org.apache.camel.spi.UriParams; import org.eclipse.milo.opcua.sdk.client.OpcUaClientConfigBuilder; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; @@ -113,6 +114,15 @@ public class MiloClientConfiguration implements Cloneable { @UriParam(label = "client", defaultValue = "1_000.0") private Double requestedPublishingInterval = DEFAULT_REQUESTED_PUBLISHING_INTERVAL; + @UriParam(label = "security") + private String trustListDirectory; + + @UriParam(label = "security") + private CertificateValidator certificateValidator; + + @UriParam(label = "security") + private boolean trustAllCertificates; + public MiloClientConfiguration() { } @@ -138,6 +148,9 @@ public MiloClientConfiguration(final MiloClientConfiguration other) { this.overrideHost = other.overrideHost; this.overridePort = other.overridePort; this.requestedPublishingInterval = other.requestedPublishingInterval; + this.trustListDirectory = other.trustListDirectory; + this.certificateValidator = other.certificateValidator; + this.trustAllCertificates = other.trustAllCertificates; } /** @@ -419,17 +432,76 @@ public Double getRequestedPublishingInterval() { return requestedPublishingInterval; } + /** + * The directory holding the trust list used to validate the certificate of the OPC UA server, in the layout used by + * Eclipse Milo: trusted certificates in trusted/certs, CRLs of trusted certificates in trusted/crl, certificates of + * issuing CAs in issuer/certs and their CRLs in issuer/crl. The directories are created if they do not exist. + * Besides the chain of trust, the validity period, the revocation by a CRL of the trust list and the application + * URI of the server certificate are checked. A certificate issued by a CA is refused when the trust list holds no + * CRL of that CA; an empty CRL is enough. A server certificate that does not chain up to a trusted certificate is + * written to rejected/certs, from where it can be moved to trusted/certs once it has been checked. + */ + public void setTrustListDirectory(final String trustListDirectory) { + this.trustListDirectory = trustListDirectory; + } + + public String getTrustListDirectory() { + return this.trustListDirectory; + } + + /** + * A custom validator for the certificate of the OPC UA server. When set, it is used instead of the trust list + * configured with trustListDirectory. Endpoints share a connection only when they use the same validator instance. + */ + public void setCertificateValidator(final CertificateValidator certificateValidator) { + this.certificateValidator = certificateValidator; + } + + public CertificateValidator getCertificateValidator() { + return this.certificateValidator; + } + + /** + * Whether to accept any certificate presented by the OPC UA server. This is insecure: the connection is encrypted, + * but the client does not authenticate the server it talks to. It only applies when neither certificateValidator + * nor trustListDirectory is configured. + */ + public void setTrustAllCertificates(final boolean trustAllCertificates) { + this.trustAllCertificates = trustAllCertificates; + } + + public boolean isTrustAllCertificates() { + return this.trustAllCertificates; + } + @Override public MiloClientConfiguration clone() { return new MiloClientConfiguration(this); } public String toCacheId() { + final String cacheId; if (this.clientId != null && !this.clientId.isEmpty()) { - return this.endpointUri + "|" + this.clientId; + cacheId = this.endpointUri + "|" + this.clientId; } else { - return this.endpointUri; + cacheId = this.endpointUri; + } + // endpoints that validate the server certificate differently must not share a connection + return cacheId + serverCertificateTrustCacheId(); + } + + private String serverCertificateTrustCacheId() { + if (this.certificateValidator != null) { + return "|certificateValidator=" + this.certificateValidator.getClass().getName() + "@" + + Integer.toHexString(System.identityHashCode(this.certificateValidator)); + } + if (this.trustListDirectory != null && !this.trustListDirectory.isEmpty()) { + return "|trustListDirectory=" + this.trustListDirectory; + } + if (this.trustAllCertificates) { + return "|trustAllCertificates"; } + return ""; } public OpcUaClientConfigBuilder newBuilder() { diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/ServerCertificateTrust.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/ServerCertificateTrust.java new file mode 100644 index 0000000000000..5e3d92a0459c4 --- /dev/null +++ b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/ServerCertificateTrust.java @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.milo.client.internal; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.apache.camel.component.milo.client.MiloClientConfiguration; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.security.CertificateQuarantine; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.DefaultClientCertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.FileBasedCertificateQuarantine; +import org.eclipse.milo.opcua.stack.core.security.FileBasedTrustListManager; +import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.util.validation.ValidationCheck; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Selects the validator for the certificate of the OPC UA server, and owns the file based trust list when one is + * configured. The trust list is created on first use and kept until {@link #close()}, so a reconnect reuses it. + */ +final class ServerCertificateTrust implements Closeable { + + /** + * The checks of the trust list validator besides the chain of trust. As OPC UA requires, a certificate issued by a + * CA is refused when the trust list holds no revocation list of that CA. A self-signed certificate of the trust + * list is not checked for revocation. + */ + static final Set TRUST_LIST_CHECKS + = Set.of(ValidationCheck.APPLICATION_URI, ValidationCheck.VALIDITY, ValidationCheck.REVOCATION); + + private static final Set CERTIFICATE_STATUS_CODES = Set.of( + StatusCodes.Bad_SecurityChecksFailed, + StatusCodes.Bad_CertificateInvalid, + StatusCodes.Bad_CertificateUntrusted, + StatusCodes.Bad_CertificateTimeInvalid, + StatusCodes.Bad_CertificateIssuerTimeInvalid, + StatusCodes.Bad_CertificateHostNameInvalid, + StatusCodes.Bad_CertificateUriInvalid, + StatusCodes.Bad_CertificateUseNotAllowed, + StatusCodes.Bad_CertificateIssuerUseNotAllowed, + StatusCodes.Bad_CertificateRevocationUnknown, + StatusCodes.Bad_CertificateIssuerRevocationUnknown, + StatusCodes.Bad_CertificateRevoked, + StatusCodes.Bad_CertificateIssuerRevoked, + StatusCodes.Bad_CertificateChainIncomplete, + StatusCodes.Bad_CertificatePolicyCheckFailed); + + private static final Logger LOG = LoggerFactory.getLogger(ServerCertificateTrust.class); + + private final MiloClientConfiguration configuration; + private final Lock lock = new ReentrantLock(); + + private FileBasedTrustListManager trustListManager; + private CertificateValidator trustListValidator; + private boolean trustAllLogged; + private boolean closed; + + ServerCertificateTrust(final MiloClientConfiguration configuration) { + this.configuration = configuration; + } + + /** + * Returns the validator for the certificate of the server that provides the given endpoint. + * + * @param endpoint the endpoint selected from the discovery result, may be {@code null} + * @return the validator to use for the secure channel, the session and the identity token + * @throws NotConfiguredException if the endpoint uses a security policy other than None and no way to validate the + * server certificate is configured + * @throws IOException if the trust list directory cannot be read or created + */ + CertificateValidator validatorFor(final EndpointDescription endpoint) throws IOException { + if (this.configuration.getCertificateValidator() != null) { + return this.configuration.getCertificateValidator(); + } + + final String trustListDirectory = this.configuration.getTrustListDirectory(); + if (trustListDirectory != null && !trustListDirectory.isEmpty()) { + return trustListValidator(Paths.get(trustListDirectory)); + } + + if (this.configuration.isTrustAllCertificates()) { + if (isSecured(endpoint)) { + logTrustAllOnce(); + } + return new CertificateValidator.InsecureCertificateValidator(); + } + + if (isSecured(endpoint)) { + throw new NotConfiguredException( + "The certificate of the OPC UA server cannot be validated: endpoint " + endpoint.getEndpointUrl() + + " uses security policy " + endpoint.getSecurityPolicyUri() + + ", but neither trustListDirectory nor certificateValidator is configured." + + " Configure one of them, or set trustAllCertificates=true to accept any" + + " server certificate (insecure)."); + } + + // SecurityPolicy None: the server is not authenticated in any case, and its certificate is at most used to + // encrypt the user identity token + return new CertificateValidator.InsecureCertificateValidator(); + } + + /** + * Whether the endpoint uses a security policy other than None, in which case the server certificate is validated. + */ + static boolean isSecured(final EndpointDescription endpoint) { + return endpoint != null && !SecurityPolicy.None.getUri().equals(endpoint.getSecurityPolicyUri()); + } + + /** + * Finds the reason of a connection failure that a retry does not fix by itself: a missing trust configuration, or a + * certificate or security check that failed, on the client or on the server side. + * + * @param failure the failure of a connection attempt + * @return the exception that describes the reason, or {@code null} for any other failure + */ + static Throwable findCertificateFailure(final Throwable failure) { + Throwable current = failure; + for (int depth = 0; current != null && depth < 16; depth++) { + if (current instanceof NotConfiguredException) { + return current; + } + if (current instanceof UaException uaException + && CERTIFICATE_STATUS_CODES.contains(uaException.getStatusCode().getValue())) { + return current; + } + current = current.getCause(); + } + return null; + } + + private CertificateValidator trustListValidator(final Path directory) throws IOException { + this.lock.lock(); + try { + if (this.closed) { + throw new IllegalStateException("The trust list in " + directory + " has been closed"); + } + if (this.trustListValidator == null) { + final CertificateQuarantine quarantine + = FileBasedCertificateQuarantine.create(directory.resolve("rejected").resolve("certs")); + final FileBasedTrustListManager manager = FileBasedTrustListManager.createAndInitialize(directory); + + if (manager.getTrustedCertificates().isEmpty() && manager.getIssuerCertificates().isEmpty()) { + LOG.warn("The trust list in {} contains no certificates, so the certificate of the OPC UA server will be" + + " rejected. Add the server certificate, or the certificate of its CA, to {}.", + directory, directory.resolve("trusted").resolve("certs")); + } + + this.trustListManager = manager; + this.trustListValidator = new DefaultClientCertificateValidator(manager, TRUST_LIST_CHECKS, quarantine); + } + return this.trustListValidator; + } finally { + this.lock.unlock(); + } + } + + private void logTrustAllOnce() { + this.lock.lock(); + try { + if (this.trustAllLogged) { + return; + } + this.trustAllLogged = true; + } finally { + this.lock.unlock(); + } + LOG.warn("The milo client is configured with trustAllCertificates=true. The certificate of the OPC UA server is" + + " not validated, so the client does not authenticate the server it connects to. This should not be" + + " used in production environments."); + } + + @Override + public void close() throws IOException { + final FileBasedTrustListManager manager; + + this.lock.lock(); + try { + this.closed = true; + manager = this.trustListManager; + this.trustListManager = null; + this.trustListValidator = null; + } finally { + this.lock.unlock(); + } + + if (manager != null) { + manager.close(); + } + } + + /** + * The endpoint uses a security policy other than None, but no way to validate the server certificate is configured. + * Retrying does not help until the configuration changes. + */ + static final class NotConfiguredException extends IllegalStateException { + + private static final long serialVersionUID = 1L; + + NotConfiguredException(final String message) { + super(message); + } + } +} diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java index f62e880e8d872..89dd3dfd40109 100644 --- a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java +++ b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java @@ -16,6 +16,7 @@ */ package org.apache.camel.component.milo.client.internal; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -55,6 +56,7 @@ import org.eclipse.milo.opcua.stack.core.Identifiers; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; @@ -582,8 +584,10 @@ nodeId, direction, Identifiers.References, includeSubTypes, uint(nodeClasses), private final MiloClientConfiguration configuration; private final ScheduledExecutorService executor; private final long reconnectTimeout; + private final ServerCertificateTrust serverCertificateTrust; private Connected connected; + private volatile Throwable lastConnectFailure; private boolean disposed; private Future reconnectJob; private final Map subscriptions = new HashMap<>(); @@ -594,6 +598,7 @@ public SubscriptionManager(final MiloClientConfiguration configuration, final Sc this.configuration = configuration; this.executor = executor; this.reconnectTimeout = reconnectTimeout; + this.serverCertificateTrust = new ServerCertificateTrust(configuration); connect(); } @@ -603,6 +608,7 @@ private synchronized void handleConnectionFailure(final Throwable e) { this.connected.dispose(); this.connected = null; } + this.lastConnectFailure = e; // log @@ -645,6 +651,7 @@ private void performAndEvalConnect() { LOG.debug("Update state : {} -> {}", this.connected, connected); final Connected oldConnected = this.connected; this.connected = connected; + this.lastConnectFailure = null; if (oldConnected != null) { LOG.debug("Dispose old state"); @@ -658,11 +665,28 @@ private void performAndEvalConnect() { } } } catch (final Exception e) { - LOG.info("Failed to connect", e); + this.lastConnectFailure = e; + logConnectFailure(e); triggerReconnect(false); } } + private static void logConnectFailure(final Exception e) { + final Throwable certificateFailure = ServerCertificateTrust.findCertificateFailure(e); + if (certificateFailure instanceof ServerCertificateTrust.NotConfiguredException) { + LOG.warn("Failed to connect: {}", certificateFailure.getMessage()); + LOG.debug("Failed to connect", e); + } else if (certificateFailure != null) { + // a certificate rejected by the trust list can be trusted later, so the client keeps retrying + // passed as text: SLF4J would log a trailing Throwable as the exception, with its stack trace + LOG.warn("Failed to connect, because a certificate or security check failed: {}", + String.valueOf(certificateFailure)); + LOG.debug("Failed to connect", e); + } else { + LOG.info("Failed to connect", e); + } + } + private Connected performConnect() throws Exception { // eval endpoint @@ -697,6 +721,9 @@ private Connected performConnect() throws Exception { LOG.debug("Selected endpoint: {}", endpoint); + // the same validator checks the server certificate for the secure channel, the session and the identity token + final CertificateValidator certificateValidator = this.serverCertificateTrust.validatorFor(endpoint); + // set identity providers final List providers = new LinkedList<>(); @@ -707,7 +734,7 @@ private Connected performConnect() throws Exception { LOG.debug("Enable username/password provider: {}", creds[0]); } - providers.add(new UsernameProvider(creds[0], creds[1])); + providers.add(new UsernameProvider(creds[0], creds[1], certificateValidator)); } } @@ -716,6 +743,7 @@ private Connected performConnect() throws Exception { final OpcUaClientConfigBuilder cfg = this.configuration.newBuilder(); cfg.setIdentityProvider(new CompositeProvider(providers)); cfg.setEndpoint(endpoint); + cfg.setCertificateValidator(certificateValidator); // create client final OpcUaClient client = OpcUaClient.create( @@ -777,6 +805,12 @@ public void dispose() { // dispose outside of lock connected.dispose(); } + + try { + this.serverCertificateTrust.close(); + } catch (final IOException e) { + LOG.debug("Failed to close the trust list. This exception is ignored.", e); + } } private synchronized void triggerReconnect(final boolean immediate) { @@ -883,9 +917,10 @@ protected synchronized void whenConnected(final Worker worker) { } } - private static CompletableFuture newNotConnectedResult() { + private CompletableFuture newNotConnectedResult() { final CompletableFuture result = new CompletableFuture<>(); - result.completeExceptionally(new IllegalStateException("No connected")); + // the reason of the last failed connection attempt, if any, tells the caller why there is no connection + result.completeExceptionally(new IllegalStateException("No connected", this.lastConnectFailure)); return result; } diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/ServerCertificateValidationTest.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/ServerCertificateValidationTest.java new file mode 100644 index 0000000000000..12352d91f9c6f --- /dev/null +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/ServerCertificateValidationTest.java @@ -0,0 +1,213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.milo; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.cert.X509Certificate; +import java.util.EnumSet; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Exchange; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.milo.call.TestCertificateFactory; +import org.apache.camel.component.milo.server.MiloServerComponent; +import org.apache.camel.component.mock.MockEndpoint; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.DefaultApplicationGroup; +import org.eclipse.milo.opcua.stack.core.security.DefaultCertificateManager; +import org.eclipse.milo.opcua.stack.core.security.DefaultClientCertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.MemoryCertificateQuarantine; +import org.eclipse.milo.opcua.stack.core.security.MemoryCertificateStore; +import org.eclipse.milo.opcua.stack.core.security.MemoryTrustListManager; +import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * The client validates the certificate of a server that only offers a secured endpoint. + */ +class ServerCertificateValidationTest extends AbstractMiloServerTest { + + private static final String DIRECT_START = "direct:start"; + + private static final String MILO_SERVER_ITEM = "milo-server:myitem1"; + + private static final String MILO_CLIENT = "milo-client:opc.tcp://foo:bar@localhost:@@port@@?node=" + + NodeIds.nodeValue(MiloServerComponent.DEFAULT_NAMESPACE_URI, "myitem1") + + "&keyStoreUrl=file:src/test/resources/keystore&keyStorePassword=testtest" + + "&keyPassword=test&keyAlias=test&allowedSecurityPolicies=Basic256Sha256" + + "&discoveryEndpointSuffix=/discovery&overrideHost=true"; + + private static final String SERVER_APPLICATION_URI = "urn:eclipse:milo:test"; + + @TempDir + static Path pki; + + private final RecordingCertificateValidator recordingValidator = new RecordingCertificateValidator(); + + @EndpointInject("mock:trustList") + MockEndpoint trustListEndpoint; + + @EndpointInject("mock:emptyTrustList") + MockEndpoint emptyTrustListEndpoint; + + @EndpointInject("mock:notConfigured") + MockEndpoint notConfiguredEndpoint; + + @EndpointInject("mock:trustAll") + MockEndpoint trustAllEndpoint; + + @EndpointInject("mock:certificateValidator") + MockEndpoint certificateValidatorEndpoint; + + @Produce(DIRECT_START) + ProducerTemplate producer; + + @Override + protected void configureContext(final CamelContext context) throws Exception { + super.configureContext(context); + context.getRegistry().bind("recordingValidator", this.recordingValidator); + } + + @Override + protected void configureMiloServer(final MiloServerComponent server) throws Exception { + super.configureMiloServer(server); + + // the server uses a self-signed certificate, and accepts any client: the client is under test here + final DefaultApplicationGroup certificateGroup = DefaultApplicationGroup.createAndInitialize( + new MemoryTrustListManager(), new MemoryCertificateStore(), new TestCertificateFactory(), + new CertificateValidator.InsecureCertificateValidator()); + final X509Certificate serverCertificate = certificateGroup.getCertificateEntries().get(0).certificateChain[0]; + + server.setApplicationUri(SERVER_APPLICATION_URI); + server.setCertificateManager(new DefaultCertificateManager(new MemoryCertificateQuarantine(), certificateGroup)); + server.setCertificate(serverCertificate); + server.setSecurityPolicies(EnumSet.of(SecurityPolicy.Basic256Sha256)); + server.setUsernameSecurityPolicyUri(SecurityPolicy.Basic256Sha256); + + final Path trustedCerts = Files.createDirectories(pki.resolve("trusted").resolve("trusted").resolve("certs")); + Files.write(trustedCerts.resolve("server.der"), serverCertificate.getEncoded()); + + this.recordingValidator.trust(serverCertificate); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from(DIRECT_START).to(MILO_SERVER_ITEM); + + // the consumers deliver the current value while they start, so the test starts these routes + from(resolve(trustListClient("trusted"))).autoStartup(false).to("mock:trustList"); + from(resolve(trustListClient("empty"))).autoStartup(false).to("mock:emptyTrustList"); + from(resolve(MILO_CLIENT)).autoStartup(false).to("mock:notConfigured"); + from(resolve(MILO_CLIENT + "&trustAllCertificates=true")).autoStartup(false).to("mock:trustAll"); + from(resolve(MILO_CLIENT + "&certificateValidator=#recordingValidator")).autoStartup(false) + .to("mock:certificateValidator"); + } + }; + } + + @Test + void onlyClientsThatCanValidateTheServerCertificateConnect() throws Exception { + this.trustListEndpoint.setExpectedCount(1); + this.trustAllEndpoint.setExpectedCount(1); + this.certificateValidatorEndpoint.setExpectedCount(1); + + this.emptyTrustListEndpoint.setExpectedCount(0); + this.emptyTrustListEndpoint.setSleepForEmptyTest(5_000); + this.notConfiguredEndpoint.setExpectedCount(0); + this.notConfiguredEndpoint.setSleepForEmptyTest(5_000); + + // the value is written before the consumers start, so it is the first notification of each client that + // connects (and not the initial Bad value of the item) + this.producer.sendBody("Foo"); + context.getRouteController().startAllRoutes(); + + MockEndpoint.assertIsSatisfied(context); + + // the server certificate rejected by the empty trust list is kept for review + final Path rejectedCerts = pki.resolve("empty").resolve("rejected").resolve("certs"); + await().atMost(10, TimeUnit.SECONDS).until(() -> countFiles(rejectedCerts) > 0); + + assertTrue(this.recordingValidator.validations.get() > 0, "The configured certificate validator was not used"); + + // a producer of a client that cannot connect gets the reason of the last connection attempt + assertConnectionFailure(MILO_CLIENT, "The certificate of the OPC UA server cannot be validated"); + assertConnectionFailure(trustListClient("empty"), "Bad_SecurityChecksFailed"); + } + + private void assertConnectionFailure(final String clientUri, final String expectedReason) { + final Exchange exchange = this.producer.send(resolve(clientUri + "&defaultAwaitWrites=true"), + e -> e.getMessage().setBody("Bar")); + + final StringBuilder causes = new StringBuilder(); + for (Throwable cause = exchange.getException(); cause != null; cause = cause.getCause()) { + causes.append(cause).append('\n'); + } + assertTrue(causes.indexOf("No connected") >= 0, causes::toString); + assertTrue(causes.indexOf(expectedReason) >= 0, causes::toString); + } + + private static String trustListClient(final String directory) { + return MILO_CLIENT + "&trustListDirectory=RAW(" + pki.resolve(directory) + ")"; + } + + private static long countFiles(final Path directory) throws IOException { + if (!Files.isDirectory(directory)) { + return 0; + } + try (Stream files = Files.list(directory)) { + return files.count(); + } + } + + private static final class RecordingCertificateValidator implements CertificateValidator { + + private final AtomicInteger validations = new AtomicInteger(); + private final MemoryTrustListManager trustList = new MemoryTrustListManager(); + private final CertificateValidator delegate + = new DefaultClientCertificateValidator(this.trustList, new MemoryCertificateQuarantine()); + + void trust(final X509Certificate certificate) { + this.trustList.addTrustedCertificate(certificate); + } + + @Override + public void validateCertificateChain( + final List certificateChain, final String applicationUri, final String[] validHostNames) + throws UaException { + this.validations.incrementAndGet(); + this.delegate.validateCertificateChain(certificateChain, applicationUri, validHostNames); + } + } +} diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/client/MiloClientConfigurationTest.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/client/MiloClientConfigurationTest.java new file mode 100644 index 0000000000000..5f8edb88c1eef --- /dev/null +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/client/MiloClientConfigurationTest.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.milo.client; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class MiloClientConfigurationTest { + + private static final String ENDPOINT_URI = "opc.tcp://localhost:4840"; + + @Test + void cacheIdIsUnchangedWithoutServerCertificateTrustSettings() { + assertEquals(ENDPOINT_URI, configuration().toCacheId()); + } + + @Test + void endpointsValidatingTheServerDifferentlyDoNotShareAConnection() { + final MiloClientConfiguration trustAll = configuration(); + trustAll.setTrustAllCertificates(true); + final MiloClientConfiguration trustList = configuration(); + trustList.setTrustListDirectory("pki"); + final MiloClientConfiguration otherTrustList = configuration(); + otherTrustList.setTrustListDirectory("other-pki"); + final MiloClientConfiguration validator = configuration(); + validator.setCertificateValidator(validator()); + + final Set cacheIds = new HashSet<>( + Arrays.asList( + configuration().toCacheId(), trustAll.toCacheId(), trustList.toCacheId(), otherTrustList.toCacheId(), + validator.toCacheId())); + + assertEquals(5, cacheIds.size()); + } + + @Test + void copyAndCloneKeepServerCertificateTrustSettings() { + final CertificateValidator certificateValidator = validator(); + final MiloClientConfiguration original = configuration(); + original.setTrustListDirectory("pki"); + original.setCertificateValidator(certificateValidator); + original.setTrustAllCertificates(true); + + for (final MiloClientConfiguration copy : Arrays.asList(new MiloClientConfiguration(original), original.clone())) { + assertEquals("pki", copy.getTrustListDirectory()); + assertSame(certificateValidator, copy.getCertificateValidator()); + assertTrue(copy.isTrustAllCertificates()); + } + } + + private static MiloClientConfiguration configuration() { + final MiloClientConfiguration configuration = new MiloClientConfiguration(); + configuration.setEndpointUri(ENDPOINT_URI); + return configuration; + } + + private static CertificateValidator validator() { + return (certificateChain, applicationUri, validHostNames) -> { + }; + } +} diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/client/internal/ServerCertificateTrustTest.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/client/internal/ServerCertificateTrustTest.java new file mode 100644 index 0000000000000..a9a05de0c8e07 --- /dev/null +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/client/internal/ServerCertificateTrustTest.java @@ -0,0 +1,280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.milo.client.internal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.KeyPair; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; + +import org.apache.camel.component.milo.call.TestCertificateFactory; +import org.apache.camel.component.milo.client.MiloClientConfiguration; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.DefaultClientCertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ServerCertificateTrustTest { + + private static X509Certificate selfSignedServerCertificate; + private static TestPki pki; + + @TempDir + Path trustListDirectory; + + @BeforeAll + static void createCertificates() throws Exception { + final TestCertificateFactory certificateFactory = new TestCertificateFactory(); + final KeyPair keyPair = certificateFactory.createRsaSha256KeyPair(); + selfSignedServerCertificate = certificateFactory.createRsaSha256CertificateChain(keyPair)[0]; + pki = new TestPki("Camel Milo Test CA"); + } + + @Test + void securedEndpointWithoutTrustConfigurationIsRefused() { + final ServerCertificateTrust trust = new ServerCertificateTrust(new MiloClientConfiguration()); + + final ServerCertificateTrust.NotConfiguredException e = assertThrows( + ServerCertificateTrust.NotConfiguredException.class, + () -> trust.validatorFor(endpoint(SecurityPolicy.Basic256Sha256))); + + assertTrue(e.getMessage().contains("trustListDirectory"), e.getMessage()); + assertTrue(e.getMessage().contains("certificateValidator"), e.getMessage()); + assertTrue(e.getMessage().contains("trustAllCertificates"), e.getMessage()); + } + + @Test + void endpointWithoutSecurityDoesNotNeedTrustConfiguration() throws Exception { + final ServerCertificateTrust trust = new ServerCertificateTrust(new MiloClientConfiguration()); + + assertInstanceOf(CertificateValidator.InsecureCertificateValidator.class, + trust.validatorFor(endpoint(SecurityPolicy.None))); + } + + @Test + void trustAllCertificatesAcceptsAnyServerCertificate() throws Exception { + final MiloClientConfiguration configuration = new MiloClientConfiguration(); + configuration.setTrustAllCertificates(true); + final ServerCertificateTrust trust = new ServerCertificateTrust(configuration); + + final CertificateValidator validator = trust.validatorFor(endpoint(SecurityPolicy.Basic256Sha256)); + + assertDoesNotThrow(() -> validator.validateCertificateChain(List.of(selfSignedServerCertificate), null, null)); + } + + @Test + void certificateValidatorIsUsedBeforeOtherOptions() throws Exception { + final CertificateValidator custom = (certificateChain, applicationUri, validHostNames) -> { + }; + final MiloClientConfiguration configuration = new MiloClientConfiguration(); + configuration.setCertificateValidator(custom); + configuration.setTrustListDirectory(this.trustListDirectory.toString()); + configuration.setTrustAllCertificates(true); + + try (ServerCertificateTrust trust = new ServerCertificateTrust(configuration)) { + assertSame(custom, trust.validatorFor(endpoint(SecurityPolicy.Basic256Sha256))); + } + } + + @Test + void trustListAcceptsTrustedServerCertificate() throws Exception { + trust(selfSignedServerCertificate); + + try (ServerCertificateTrust trust = trustListTrust()) { + final CertificateValidator validator = trust.validatorFor(endpoint(SecurityPolicy.Basic256Sha256)); + + assertInstanceOf(DefaultClientCertificateValidator.class, validator); + assertDoesNotThrow( + () -> validator.validateCertificateChain(List.of(selfSignedServerCertificate), null, null)); + // a reconnect uses the same trust list + assertSame(validator, trust.validatorFor(endpoint(SecurityPolicy.Basic256Sha256))); + } + } + + @Test + void trustListRejectsAndKeepsUntrustedServerCertificate() throws Exception { + // the trust list holds a CA that did not issue the server certificate + trust(new TestPki("Another Test CA").certificate()); + + try (ServerCertificateTrust trust = trustListTrust()) { + final CertificateValidator validator = trust.validatorFor(endpoint(SecurityPolicy.Basic256Sha256)); + + // Milo reports a certificate without a chain up to a trusted certificate as a failed security check + final UaException e = assertThrows(UaException.class, + () -> validator.validateCertificateChain(List.of(selfSignedServerCertificate), null, null)); + assertEquals(StatusCodes.Bad_SecurityChecksFailed, e.getStatusCode().getValue(), e.toString()); + } + + assertTrue(Files.isDirectory(this.trustListDirectory.resolve("trusted").resolve("certs"))); + assertTrue(Files.isDirectory(this.trustListDirectory.resolve("issuer").resolve("certs"))); + assertEquals(1, countRejected()); + } + + @Test + void trustListAcceptsServerCertificateOfCaWithRevocationList() throws Exception { + final X509Certificate serverCertificate = validServerCertificate(); + trust(pki.certificate()); + trustRevocationList(pki.revocationList()); + + try (ServerCertificateTrust trust = trustListTrust()) { + final CertificateValidator validator = trust.validatorFor(endpoint(SecurityPolicy.Basic256Sha256)); + + assertDoesNotThrow(() -> validator.validateCertificateChain( + List.of(serverCertificate, pki.certificate()), TestPki.SERVER_APPLICATION_URI, null)); + } + } + + @Test + void trustListRefusesServerCertificateOfCaWithoutRevocationList() throws Exception { + final X509Certificate serverCertificate = validServerCertificate(); + trust(pki.certificate()); + + assertRefused(List.of(serverCertificate, pki.certificate()), TestPki.SERVER_APPLICATION_URI, + StatusCodes.Bad_CertificateRevocationUnknown); + } + + @Test + void trustListRefusesRevokedServerCertificate() throws Exception { + final X509Certificate serverCertificate = validServerCertificate(); + trust(pki.certificate()); + trustRevocationList(pki.revocationList(serverCertificate)); + + assertRefused(List.of(serverCertificate, pki.certificate()), TestPki.SERVER_APPLICATION_URI, + StatusCodes.Bad_CertificateRevoked); + } + + @Test + void trustListRefusesExpiredServerCertificate() throws Exception { + final Instant now = Instant.now(); + final X509Certificate serverCertificate = TestPki.selfSignedServerCertificate( + now.minus(2, ChronoUnit.DAYS), now.minus(1, ChronoUnit.DAYS)); + trust(serverCertificate); + + assertRefused(List.of(serverCertificate), TestPki.SERVER_APPLICATION_URI, StatusCodes.Bad_CertificateTimeInvalid); + } + + @Test + void trustListRefusesServerCertificateOfAnotherApplication() throws Exception { + final Instant now = Instant.now(); + final X509Certificate serverCertificate = TestPki.selfSignedServerCertificate( + now.minus(1, ChronoUnit.HOURS), now.plus(1, ChronoUnit.HOURS)); + trust(serverCertificate); + + assertRefused(List.of(serverCertificate), "urn:camel:milo:test:other", StatusCodes.Bad_CertificateUriInvalid); + } + + @Test + void closedTrustListIsNotReused() throws Exception { + final ServerCertificateTrust trust = trustListTrust(); + trust.validatorFor(endpoint(SecurityPolicy.Basic256Sha256)); + + trust.close(); + + assertThrows(IllegalStateException.class, () -> trust.validatorFor(endpoint(SecurityPolicy.Basic256Sha256))); + } + + @Test + void certificateFailuresAreFoundInTheCauseChain() { + final ServerCertificateTrust.NotConfiguredException notConfigured + = new ServerCertificateTrust.NotConfiguredException("not configured"); + final UaException untrusted = new UaException(StatusCodes.Bad_CertificateUntrusted, "untrusted"); + + assertSame(notConfigured, + ServerCertificateTrust.findCertificateFailure(new IllegalStateException("wrapped", notConfigured))); + assertSame(untrusted, ServerCertificateTrust.findCertificateFailure(new ExecutionException(untrusted))); + assertNull(ServerCertificateTrust.findCertificateFailure(new UaException(StatusCodes.Bad_Timeout, "timeout"))); + assertNull(ServerCertificateTrust.findCertificateFailure(new IOException("connection refused"))); + } + + private void assertRefused( + final List certificateChain, final String applicationUri, final long statusCode) + throws Exception { + try (ServerCertificateTrust trust = trustListTrust()) { + final CertificateValidator validator = trust.validatorFor(endpoint(SecurityPolicy.Basic256Sha256)); + + final UaException e = assertThrows(UaException.class, + () -> validator.validateCertificateChain(certificateChain, applicationUri, null)); + assertEquals(statusCode, e.getStatusCode().getValue(), e.toString()); + } + // only a certificate that does not chain up to a trusted certificate is kept for review + assertEquals(0, countRejected()); + } + + private static X509Certificate validServerCertificate() throws Exception { + final Instant now = Instant.now(); + return pki.issueServerCertificate(now.minus(1, ChronoUnit.HOURS), now.plus(1, ChronoUnit.HOURS)); + } + + private ServerCertificateTrust trustListTrust() { + final MiloClientConfiguration configuration = new MiloClientConfiguration(); + configuration.setTrustListDirectory(this.trustListDirectory.toString()); + return new ServerCertificateTrust(configuration); + } + + private void trust(final X509Certificate certificate) throws Exception { + final Path trustedCerts = Files.createDirectories(this.trustListDirectory.resolve("trusted").resolve("certs")); + Files.write(trustedCerts.resolve(certificate.getSerialNumber() + "-" + + Integer.toHexString(certificate.hashCode()) + ".der"), + certificate.getEncoded()); + } + + private void trustRevocationList(final X509CRL revocationList) throws Exception { + final Path trustedCrl = Files.createDirectories(this.trustListDirectory.resolve("trusted").resolve("crl")); + Files.write(trustedCrl.resolve("ca.crl"), revocationList.getEncoded()); + } + + private long countRejected() throws IOException { + final Path rejectedCerts = this.trustListDirectory.resolve("rejected").resolve("certs"); + if (!Files.isDirectory(rejectedCerts)) { + return 0; + } + try (Stream rejected = Files.list(rejectedCerts)) { + return rejected.count(); + } + } + + private static EndpointDescription endpoint(final SecurityPolicy securityPolicy) { + final MessageSecurityMode securityMode + = securityPolicy == SecurityPolicy.None ? MessageSecurityMode.None : MessageSecurityMode.SignAndEncrypt; + return new EndpointDescription( + "opc.tcp://localhost:4840", null, ByteString.NULL_VALUE, securityMode, securityPolicy.getUri(), null, null, + UByte.valueOf(0)); + } +} diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/client/internal/TestPki.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/client/internal/TestPki.java new file mode 100644 index 0000000000000..0a0cca2805707 --- /dev/null +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/client/internal/TestPki.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.milo.client.internal; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.CRLReason; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.cert.X509v2CRLBuilder; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CRLConverter; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +/** + * A certificate authority for tests, which issues server certificates and certificate revocation lists. + */ +final class TestPki { + + static final String SERVER_APPLICATION_URI = "urn:camel:milo:test:server"; + + private final X500Name name; + private final KeyPair keyPair; + private final X509Certificate certificate; + private long serialNumber; + + TestPki(final String commonName) throws Exception { + this.name = new X500Name("CN=" + commonName); + this.keyPair = newKeyPair(); + + final Instant now = Instant.now(); + final X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder( + this.name, nextSerialNumber(), Date.from(now.minus(1, ChronoUnit.DAYS)), + Date.from(now.plus(1, ChronoUnit.DAYS)), this.name, this.keyPair.getPublic()); + builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true)); + builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign)); + this.certificate = sign(builder); + } + + X509Certificate certificate() { + return this.certificate; + } + + /** + * Issues a certificate for a server with the application URI {@link #SERVER_APPLICATION_URI}. + */ + X509Certificate issueServerCertificate(final Instant notBefore, final Instant notAfter) throws Exception { + final X509v3CertificateBuilder builder = serverCertificateBuilder( + this.name, nextSerialNumber(), notBefore, notAfter, newKeyPair().getPublic(), 0); + return sign(builder); + } + + /** + * Creates a self-signed certificate for a server with the application URI {@link #SERVER_APPLICATION_URI}. As OPC + * UA requires for a self-signed application certificate, it may sign certificates, since it is its own issuer. + */ + static X509Certificate selfSignedServerCertificate(final Instant notBefore, final Instant notAfter) throws Exception { + final KeyPair keyPair = newKeyPair(); + final X509v3CertificateBuilder builder = serverCertificateBuilder( + new X500Name("CN=Camel Milo Test Server"), BigInteger.ONE, notBefore, notAfter, keyPair.getPublic(), + KeyUsage.keyCertSign); + return new JcaX509CertificateConverter().getCertificate( + builder.build(new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate()))); + } + + private static X509v3CertificateBuilder serverCertificateBuilder( + final X500Name issuer, final BigInteger serialNumber, final Instant notBefore, final Instant notAfter, + final PublicKey publicKey, final int additionalKeyUsage) + throws Exception { + final X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder( + issuer, serialNumber, Date.from(notBefore), Date.from(notAfter), + new X500Name("CN=Camel Milo Test Server"), publicKey); + builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false)); + builder.addExtension(Extension.keyUsage, true, new KeyUsage( + KeyUsage.digitalSignature | KeyUsage.nonRepudiation | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment + | additionalKeyUsage)); + builder.addExtension(Extension.subjectAlternativeName, false, new GeneralNames( + new GeneralName[] { + new GeneralName(GeneralName.uniformResourceIdentifier, SERVER_APPLICATION_URI), + new GeneralName(GeneralName.dNSName, "localhost") })); + return builder; + } + + /** + * Issues a certificate revocation list that revokes the given certificates. + */ + X509CRL revocationList(final X509Certificate... revoked) throws Exception { + final Instant now = Instant.now(); + final X509v2CRLBuilder builder = new X509v2CRLBuilder(this.name, Date.from(now.minus(1, ChronoUnit.HOURS))); + builder.setNextUpdate(Date.from(now.plus(1, ChronoUnit.DAYS))); + for (final X509Certificate certificate : revoked) { + builder.addCRLEntry(certificate.getSerialNumber(), Date.from(now.minus(1, ChronoUnit.HOURS)), + CRLReason.keyCompromise); + } + return new JcaX509CRLConverter().getCRL(builder.build(signer())); + } + + private X509Certificate sign(final X509v3CertificateBuilder builder) throws Exception { + return new JcaX509CertificateConverter().getCertificate(builder.build(signer())); + } + + private ContentSigner signer() throws Exception { + return new JcaContentSignerBuilder("SHA256withRSA").build(this.keyPair.getPrivate()); + } + + private BigInteger nextSerialNumber() { + this.serialNumber++; + return BigInteger.valueOf(this.serialNumber); + } + + private static KeyPair newKeyPair() throws Exception { + final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); + generator.initialize(2048); + return generator.generateKeyPair(); + } +} diff --git a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MiloBrowseComponentBuilderFactory.java b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MiloBrowseComponentBuilderFactory.java index 27dba5d36c3a0..6fcb3df8cc214 100644 --- a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MiloBrowseComponentBuilderFactory.java +++ b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MiloBrowseComponentBuilderFactory.java @@ -461,6 +461,71 @@ default MiloBrowseComponentBuilder sessionTimeout(java.lang.Long sessionTimeout) doSetProperty("sessionTimeout", sessionTimeout); return this; } + + /** + * A custom validator for the certificate of the OPC UA server. When + * set, it is used instead of the trust list configured with + * trustListDirectory. Endpoints share a connection only when they use + * the same validator instance. + * + * The option is a: + * <code>org.eclipse.milo.opcua.stack.core.security.CertificateValidator</code> type. + * + * Group: security + * + * @param certificateValidator the value to set + * @return the dsl builder + */ + default MiloBrowseComponentBuilder certificateValidator(org.eclipse.milo.opcua.stack.core.security.CertificateValidator certificateValidator) { + doSetProperty("certificateValidator", certificateValidator); + return this; + } + + + /** + * Whether to accept any certificate presented by the OPC UA server. + * This is insecure: the connection is encrypted, but the client does + * not authenticate the server it talks to. It only applies when neither + * certificateValidator nor trustListDirectory is configured. + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: security + * + * @param trustAllCertificates the value to set + * @return the dsl builder + */ + default MiloBrowseComponentBuilder trustAllCertificates(boolean trustAllCertificates) { + doSetProperty("trustAllCertificates", trustAllCertificates); + return this; + } + + /** + * The directory holding the trust list used to validate the certificate + * of the OPC UA server, in the layout used by Eclipse Milo: trusted + * certificates in trusted/certs, CRLs of trusted certificates in + * trusted/crl, certificates of issuing CAs in issuer/certs and their + * CRLs in issuer/crl. The directories are created if they do not exist. + * Besides the chain of trust, the validity period, the revocation by a + * CRL of the trust list and the application URI of the server + * certificate are checked. A certificate issued by a CA is refused when + * the trust list holds no CRL of that CA; an empty CRL is enough. A + * server certificate that does not chain up to a trusted certificate is + * written to rejected/certs, from where it can be moved to + * trusted/certs once it has been checked. + * + * The option is a: <code>java.lang.String</code> type. + * + * Group: security + * + * @param trustListDirectory the value to set + * @return the dsl builder + */ + default MiloBrowseComponentBuilder trustListDirectory(java.lang.String trustListDirectory) { + doSetProperty("trustListDirectory", trustListDirectory); + return this; + } } class MiloBrowseComponentBuilderImpl @@ -507,6 +572,9 @@ protected boolean setPropertyOnComponent( case "requestTimeout": getOrCreateConfiguration((MiloBrowseComponent) component).setRequestTimeout((java.lang.Long) value); return true; case "sessionName": getOrCreateConfiguration((MiloBrowseComponent) component).setSessionName((java.lang.String) value); return true; case "sessionTimeout": getOrCreateConfiguration((MiloBrowseComponent) component).setSessionTimeout((java.lang.Long) value); return true; + case "certificateValidator": getOrCreateConfiguration((MiloBrowseComponent) component).setCertificateValidator((org.eclipse.milo.opcua.stack.core.security.CertificateValidator) value); return true; + case "trustAllCertificates": getOrCreateConfiguration((MiloBrowseComponent) component).setTrustAllCertificates((boolean) value); return true; + case "trustListDirectory": getOrCreateConfiguration((MiloBrowseComponent) component).setTrustListDirectory((java.lang.String) value); return true; default: return false; } } diff --git a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MiloClientComponentBuilderFactory.java b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MiloClientComponentBuilderFactory.java index d5ec2da4cd016..97f6ee997c66f 100644 --- a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MiloClientComponentBuilderFactory.java +++ b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MiloClientComponentBuilderFactory.java @@ -489,6 +489,71 @@ default MiloClientComponentBuilder sessionTimeout(java.lang.Long sessionTimeout) doSetProperty("sessionTimeout", sessionTimeout); return this; } + + /** + * A custom validator for the certificate of the OPC UA server. When + * set, it is used instead of the trust list configured with + * trustListDirectory. Endpoints share a connection only when they use + * the same validator instance. + * + * The option is a: + * <code>org.eclipse.milo.opcua.stack.core.security.CertificateValidator</code> type. + * + * Group: security + * + * @param certificateValidator the value to set + * @return the dsl builder + */ + default MiloClientComponentBuilder certificateValidator(org.eclipse.milo.opcua.stack.core.security.CertificateValidator certificateValidator) { + doSetProperty("certificateValidator", certificateValidator); + return this; + } + + + /** + * Whether to accept any certificate presented by the OPC UA server. + * This is insecure: the connection is encrypted, but the client does + * not authenticate the server it talks to. It only applies when neither + * certificateValidator nor trustListDirectory is configured. + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: security + * + * @param trustAllCertificates the value to set + * @return the dsl builder + */ + default MiloClientComponentBuilder trustAllCertificates(boolean trustAllCertificates) { + doSetProperty("trustAllCertificates", trustAllCertificates); + return this; + } + + /** + * The directory holding the trust list used to validate the certificate + * of the OPC UA server, in the layout used by Eclipse Milo: trusted + * certificates in trusted/certs, CRLs of trusted certificates in + * trusted/crl, certificates of issuing CAs in issuer/certs and their + * CRLs in issuer/crl. The directories are created if they do not exist. + * Besides the chain of trust, the validity period, the revocation by a + * CRL of the trust list and the application URI of the server + * certificate are checked. A certificate issued by a CA is refused when + * the trust list holds no CRL of that CA; an empty CRL is enough. A + * server certificate that does not chain up to a trusted certificate is + * written to rejected/certs, from where it can be moved to + * trusted/certs once it has been checked. + * + * The option is a: <code>java.lang.String</code> type. + * + * Group: security + * + * @param trustListDirectory the value to set + * @return the dsl builder + */ + default MiloClientComponentBuilder trustListDirectory(java.lang.String trustListDirectory) { + doSetProperty("trustListDirectory", trustListDirectory); + return this; + } } class MiloClientComponentBuilderImpl @@ -536,6 +601,9 @@ protected boolean setPropertyOnComponent( case "requestTimeout": getOrCreateConfiguration((MiloClientComponent) component).setRequestTimeout((java.lang.Long) value); return true; case "sessionName": getOrCreateConfiguration((MiloClientComponent) component).setSessionName((java.lang.String) value); return true; case "sessionTimeout": getOrCreateConfiguration((MiloClientComponent) component).setSessionTimeout((java.lang.Long) value); return true; + case "certificateValidator": getOrCreateConfiguration((MiloClientComponent) component).setCertificateValidator((org.eclipse.milo.opcua.stack.core.security.CertificateValidator) value); return true; + case "trustAllCertificates": getOrCreateConfiguration((MiloClientComponent) component).setTrustAllCertificates((boolean) value); return true; + case "trustListDirectory": getOrCreateConfiguration((MiloClientComponent) component).setTrustListDirectory((java.lang.String) value); return true; default: return false; } } diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MiloBrowseEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MiloBrowseEndpointBuilderFactory.java index e9b7f9485ebf5..d0d7b56b3b58b 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MiloBrowseEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MiloBrowseEndpointBuilderFactory.java @@ -685,6 +685,103 @@ default MiloBrowseEndpointBuilder sessionTimeout(String sessionTimeout) { doSetProperty("sessionTimeout", sessionTimeout); return this; } + /** + * A custom validator for the certificate of the OPC UA server. When + * set, it is used instead of the trust list configured with + * trustListDirectory. Endpoints share a connection only when they use + * the same validator instance. + * + * The option is a: + * org.eclipse.milo.opcua.stack.core.security.CertificateValidator type. + * + * Group: security + * + * @param certificateValidator the value to set + * @return the dsl builder + */ + default MiloBrowseEndpointBuilder certificateValidator(org.eclipse.milo.opcua.stack.core.security.CertificateValidator certificateValidator) { + doSetProperty("certificateValidator", certificateValidator); + return this; + } + /** + * A custom validator for the certificate of the OPC UA server. When + * set, it is used instead of the trust list configured with + * trustListDirectory. Endpoints share a connection only when they use + * the same validator instance. + * + * The option will be converted to a + * org.eclipse.milo.opcua.stack.core.security.CertificateValidator type. + * + * Group: security + * + * @param certificateValidator the value to set + * @return the dsl builder + */ + default MiloBrowseEndpointBuilder certificateValidator(String certificateValidator) { + doSetProperty("certificateValidator", certificateValidator); + return this; + } + /** + * Whether to accept any certificate presented by the OPC UA server. + * This is insecure: the connection is encrypted, but the client does + * not authenticate the server it talks to. It only applies when neither + * certificateValidator nor trustListDirectory is configured. + * + * The option is a: boolean type. + * + * Default: false + * Group: security + * + * @param trustAllCertificates the value to set + * @return the dsl builder + */ + default MiloBrowseEndpointBuilder trustAllCertificates(boolean trustAllCertificates) { + doSetProperty("trustAllCertificates", trustAllCertificates); + return this; + } + /** + * Whether to accept any certificate presented by the OPC UA server. + * This is insecure: the connection is encrypted, but the client does + * not authenticate the server it talks to. It only applies when neither + * certificateValidator nor trustListDirectory is configured. + * + * The option will be converted to a boolean type. + * + * Default: false + * Group: security + * + * @param trustAllCertificates the value to set + * @return the dsl builder + */ + default MiloBrowseEndpointBuilder trustAllCertificates(String trustAllCertificates) { + doSetProperty("trustAllCertificates", trustAllCertificates); + return this; + } + /** + * The directory holding the trust list used to validate the certificate + * of the OPC UA server, in the layout used by Eclipse Milo: trusted + * certificates in trusted/certs, CRLs of trusted certificates in + * trusted/crl, certificates of issuing CAs in issuer/certs and their + * CRLs in issuer/crl. The directories are created if they do not exist. + * Besides the chain of trust, the validity period, the revocation by a + * CRL of the trust list and the application URI of the server + * certificate are checked. A certificate issued by a CA is refused when + * the trust list holds no CRL of that CA; an empty CRL is enough. A + * server certificate that does not chain up to a trusted certificate is + * written to rejected/certs, from where it can be moved to + * trusted/certs once it has been checked. + * + * The option is a: java.lang.String type. + * + * Group: security + * + * @param trustListDirectory the value to set + * @return the dsl builder + */ + default MiloBrowseEndpointBuilder trustListDirectory(String trustListDirectory) { + doSetProperty("trustListDirectory", trustListDirectory); + return this; + } } /** diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MiloClientEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MiloClientEndpointBuilderFactory.java index 2db17c5273820..e51293d9d97f1 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MiloClientEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MiloClientEndpointBuilderFactory.java @@ -709,6 +709,103 @@ default MiloClientEndpointConsumerBuilder sessionTimeout(String sessionTimeout) doSetProperty("sessionTimeout", sessionTimeout); return this; } + /** + * A custom validator for the certificate of the OPC UA server. When + * set, it is used instead of the trust list configured with + * trustListDirectory. Endpoints share a connection only when they use + * the same validator instance. + * + * The option is a: + * org.eclipse.milo.opcua.stack.core.security.CertificateValidator type. + * + * Group: security + * + * @param certificateValidator the value to set + * @return the dsl builder + */ + default MiloClientEndpointConsumerBuilder certificateValidator(org.eclipse.milo.opcua.stack.core.security.CertificateValidator certificateValidator) { + doSetProperty("certificateValidator", certificateValidator); + return this; + } + /** + * A custom validator for the certificate of the OPC UA server. When + * set, it is used instead of the trust list configured with + * trustListDirectory. Endpoints share a connection only when they use + * the same validator instance. + * + * The option will be converted to a + * org.eclipse.milo.opcua.stack.core.security.CertificateValidator type. + * + * Group: security + * + * @param certificateValidator the value to set + * @return the dsl builder + */ + default MiloClientEndpointConsumerBuilder certificateValidator(String certificateValidator) { + doSetProperty("certificateValidator", certificateValidator); + return this; + } + /** + * Whether to accept any certificate presented by the OPC UA server. + * This is insecure: the connection is encrypted, but the client does + * not authenticate the server it talks to. It only applies when neither + * certificateValidator nor trustListDirectory is configured. + * + * The option is a: boolean type. + * + * Default: false + * Group: security + * + * @param trustAllCertificates the value to set + * @return the dsl builder + */ + default MiloClientEndpointConsumerBuilder trustAllCertificates(boolean trustAllCertificates) { + doSetProperty("trustAllCertificates", trustAllCertificates); + return this; + } + /** + * Whether to accept any certificate presented by the OPC UA server. + * This is insecure: the connection is encrypted, but the client does + * not authenticate the server it talks to. It only applies when neither + * certificateValidator nor trustListDirectory is configured. + * + * The option will be converted to a boolean type. + * + * Default: false + * Group: security + * + * @param trustAllCertificates the value to set + * @return the dsl builder + */ + default MiloClientEndpointConsumerBuilder trustAllCertificates(String trustAllCertificates) { + doSetProperty("trustAllCertificates", trustAllCertificates); + return this; + } + /** + * The directory holding the trust list used to validate the certificate + * of the OPC UA server, in the layout used by Eclipse Milo: trusted + * certificates in trusted/certs, CRLs of trusted certificates in + * trusted/crl, certificates of issuing CAs in issuer/certs and their + * CRLs in issuer/crl. The directories are created if they do not exist. + * Besides the chain of trust, the validity period, the revocation by a + * CRL of the trust list and the application URI of the server + * certificate are checked. A certificate issued by a CA is refused when + * the trust list holds no CRL of that CA; an empty CRL is enough. A + * server certificate that does not chain up to a trusted certificate is + * written to rejected/certs, from where it can be moved to + * trusted/certs once it has been checked. + * + * The option is a: java.lang.String type. + * + * Group: security + * + * @param trustListDirectory the value to set + * @return the dsl builder + */ + default MiloClientEndpointConsumerBuilder trustListDirectory(String trustListDirectory) { + doSetProperty("trustListDirectory", trustListDirectory); + return this; + } } /** @@ -1514,6 +1611,103 @@ default MiloClientEndpointProducerBuilder sessionTimeout(String sessionTimeout) doSetProperty("sessionTimeout", sessionTimeout); return this; } + /** + * A custom validator for the certificate of the OPC UA server. When + * set, it is used instead of the trust list configured with + * trustListDirectory. Endpoints share a connection only when they use + * the same validator instance. + * + * The option is a: + * org.eclipse.milo.opcua.stack.core.security.CertificateValidator type. + * + * Group: security + * + * @param certificateValidator the value to set + * @return the dsl builder + */ + default MiloClientEndpointProducerBuilder certificateValidator(org.eclipse.milo.opcua.stack.core.security.CertificateValidator certificateValidator) { + doSetProperty("certificateValidator", certificateValidator); + return this; + } + /** + * A custom validator for the certificate of the OPC UA server. When + * set, it is used instead of the trust list configured with + * trustListDirectory. Endpoints share a connection only when they use + * the same validator instance. + * + * The option will be converted to a + * org.eclipse.milo.opcua.stack.core.security.CertificateValidator type. + * + * Group: security + * + * @param certificateValidator the value to set + * @return the dsl builder + */ + default MiloClientEndpointProducerBuilder certificateValidator(String certificateValidator) { + doSetProperty("certificateValidator", certificateValidator); + return this; + } + /** + * Whether to accept any certificate presented by the OPC UA server. + * This is insecure: the connection is encrypted, but the client does + * not authenticate the server it talks to. It only applies when neither + * certificateValidator nor trustListDirectory is configured. + * + * The option is a: boolean type. + * + * Default: false + * Group: security + * + * @param trustAllCertificates the value to set + * @return the dsl builder + */ + default MiloClientEndpointProducerBuilder trustAllCertificates(boolean trustAllCertificates) { + doSetProperty("trustAllCertificates", trustAllCertificates); + return this; + } + /** + * Whether to accept any certificate presented by the OPC UA server. + * This is insecure: the connection is encrypted, but the client does + * not authenticate the server it talks to. It only applies when neither + * certificateValidator nor trustListDirectory is configured. + * + * The option will be converted to a boolean type. + * + * Default: false + * Group: security + * + * @param trustAllCertificates the value to set + * @return the dsl builder + */ + default MiloClientEndpointProducerBuilder trustAllCertificates(String trustAllCertificates) { + doSetProperty("trustAllCertificates", trustAllCertificates); + return this; + } + /** + * The directory holding the trust list used to validate the certificate + * of the OPC UA server, in the layout used by Eclipse Milo: trusted + * certificates in trusted/certs, CRLs of trusted certificates in + * trusted/crl, certificates of issuing CAs in issuer/certs and their + * CRLs in issuer/crl. The directories are created if they do not exist. + * Besides the chain of trust, the validity period, the revocation by a + * CRL of the trust list and the application URI of the server + * certificate are checked. A certificate issued by a CA is refused when + * the trust list holds no CRL of that CA; an empty CRL is enough. A + * server certificate that does not chain up to a trusted certificate is + * written to rejected/certs, from where it can be moved to + * trusted/certs once it has been checked. + * + * The option is a: java.lang.String type. + * + * Group: security + * + * @param trustListDirectory the value to set + * @return the dsl builder + */ + default MiloClientEndpointProducerBuilder trustListDirectory(String trustListDirectory) { + doSetProperty("trustListDirectory", trustListDirectory); + return this; + } } /** @@ -2248,6 +2442,103 @@ default MiloClientEndpointBuilder sessionTimeout(String sessionTimeout) { doSetProperty("sessionTimeout", sessionTimeout); return this; } + /** + * A custom validator for the certificate of the OPC UA server. When + * set, it is used instead of the trust list configured with + * trustListDirectory. Endpoints share a connection only when they use + * the same validator instance. + * + * The option is a: + * org.eclipse.milo.opcua.stack.core.security.CertificateValidator type. + * + * Group: security + * + * @param certificateValidator the value to set + * @return the dsl builder + */ + default MiloClientEndpointBuilder certificateValidator(org.eclipse.milo.opcua.stack.core.security.CertificateValidator certificateValidator) { + doSetProperty("certificateValidator", certificateValidator); + return this; + } + /** + * A custom validator for the certificate of the OPC UA server. When + * set, it is used instead of the trust list configured with + * trustListDirectory. Endpoints share a connection only when they use + * the same validator instance. + * + * The option will be converted to a + * org.eclipse.milo.opcua.stack.core.security.CertificateValidator type. + * + * Group: security + * + * @param certificateValidator the value to set + * @return the dsl builder + */ + default MiloClientEndpointBuilder certificateValidator(String certificateValidator) { + doSetProperty("certificateValidator", certificateValidator); + return this; + } + /** + * Whether to accept any certificate presented by the OPC UA server. + * This is insecure: the connection is encrypted, but the client does + * not authenticate the server it talks to. It only applies when neither + * certificateValidator nor trustListDirectory is configured. + * + * The option is a: boolean type. + * + * Default: false + * Group: security + * + * @param trustAllCertificates the value to set + * @return the dsl builder + */ + default MiloClientEndpointBuilder trustAllCertificates(boolean trustAllCertificates) { + doSetProperty("trustAllCertificates", trustAllCertificates); + return this; + } + /** + * Whether to accept any certificate presented by the OPC UA server. + * This is insecure: the connection is encrypted, but the client does + * not authenticate the server it talks to. It only applies when neither + * certificateValidator nor trustListDirectory is configured. + * + * The option will be converted to a boolean type. + * + * Default: false + * Group: security + * + * @param trustAllCertificates the value to set + * @return the dsl builder + */ + default MiloClientEndpointBuilder trustAllCertificates(String trustAllCertificates) { + doSetProperty("trustAllCertificates", trustAllCertificates); + return this; + } + /** + * The directory holding the trust list used to validate the certificate + * of the OPC UA server, in the layout used by Eclipse Milo: trusted + * certificates in trusted/certs, CRLs of trusted certificates in + * trusted/crl, certificates of issuing CAs in issuer/certs and their + * CRLs in issuer/crl. The directories are created if they do not exist. + * Besides the chain of trust, the validity period, the revocation by a + * CRL of the trust list and the application URI of the server + * certificate are checked. A certificate issued by a CA is refused when + * the trust list holds no CRL of that CA; an empty CRL is enough. A + * server certificate that does not chain up to a trusted certificate is + * written to rejected/certs, from where it can be moved to + * trusted/certs once it has been checked. + * + * The option is a: java.lang.String type. + * + * Group: security + * + * @param trustListDirectory the value to set + * @return the dsl builder + */ + default MiloClientEndpointBuilder trustListDirectory(String trustListDirectory) { + doSetProperty("trustListDirectory", trustListDirectory); + return this; + } } /**