use of org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription in project milo by eclipse.
the class DiscoveryClient method findServers.
/**
* Query the FindServers service at the {@code endpointUrl}.
* <p>
* The discovery URL(s) for each server {@link ApplicationDescription} in the response can then be used in a
* {@link #getEndpoints(String)} call to discover the endpoints for that server.
*
* @param endpointUrl the endpoint URL to find servers at.
* @param customizer a {@link Consumer} that accepts a {@link UaStackClientConfigBuilder} for customization.
* @return a List of {@link ApplicationDescription}s returned by the FindServers service.
*/
public static CompletableFuture<List<ApplicationDescription>> findServers(String endpointUrl, Consumer<UaStackClientConfigBuilder> customizer) {
EndpointDescription endpoint = new EndpointDescription(endpointUrl, null, null, MessageSecurityMode.None, SecurityPolicy.None.getUri(), null, Stack.TCP_UASC_UABINARY_TRANSPORT_URI, ubyte(0));
UaStackClientConfigBuilder builder = UaStackClientConfig.builder();
builder.setEndpoint(endpoint);
customizer.accept(builder);
UaStackClientConfig config = builder.build();
try {
UaStackClient stackClient = UaStackClient.create(config);
DiscoveryClient discoveryClient = new DiscoveryClient(stackClient);
return discoveryClient.connect().thenCompose(c -> c.findServers(endpointUrl, new String[0], new String[0])).whenComplete((e, ex) -> discoveryClient.disconnect()).thenApply(response -> l(response.getServers()));
} catch (UaException e) {
return failedFuture(e);
}
}
use of org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription in project milo by eclipse.
the class DefaultSubscriptionServiceSet method onTransferSubscriptions.
@Override
public void onTransferSubscriptions(ServiceRequest service) throws UaException {
TransferSubscriptionsRequest request = (TransferSubscriptionsRequest) service.getRequest();
OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get();
Session session = service.attr(ServiceAttributes.SESSION_KEY).get();
List<UInteger> subscriptionIds = l(request.getSubscriptionIds());
if (subscriptionIds.isEmpty()) {
throw new UaException(StatusCodes.Bad_NothingToDo);
}
List<TransferResult> results = Lists.newArrayList();
for (UInteger subscriptionId : subscriptionIds) {
Subscription subscription = server.getSubscriptions().get(subscriptionId);
if (subscription == null) {
results.add(new TransferResult(new StatusCode(StatusCodes.Bad_SubscriptionIdInvalid), new UInteger[0]));
} else {
Session otherSession = subscription.getSession();
if (!sessionsHaveSameUser(session, otherSession)) {
results.add(new TransferResult(new StatusCode(StatusCodes.Bad_UserAccessDenied), new UInteger[0]));
} else {
UInteger[] availableSequenceNumbers;
synchronized (subscription) {
otherSession.getSubscriptionManager().sendStatusChangeNotification(subscription, new StatusCode(StatusCodes.Good_SubscriptionTransferred));
otherSession.getSubscriptionManager().removeSubscription(subscriptionId);
subscription.setSubscriptionManager(session.getSubscriptionManager());
subscriptionManager.addSubscription(subscription);
subscription.getMonitoredItems().values().forEach(item -> item.setSession(session));
availableSequenceNumbers = subscription.getAvailableSequenceNumbers();
if (request.getSendInitialValues()) {
subscription.getMonitoredItems().values().stream().filter(item -> item instanceof MonitoredDataItem).map(item -> (MonitoredDataItem) item).forEach(MonitoredDataItem::maybeSendLastValue);
}
}
subscription.getSubscriptionDiagnostics().getTransferRequestCount().increment();
ApplicationDescription toClient = session.getClientDescription();
ApplicationDescription fromClient = otherSession.getClientDescription();
if (Objects.equals(toClient, fromClient)) {
subscription.getSubscriptionDiagnostics().getTransferredToSameClientCount().increment();
} else {
subscription.getSubscriptionDiagnostics().getTransferredToAltClientCount().increment();
}
results.add(new TransferResult(StatusCode.GOOD, availableSequenceNumbers));
}
}
}
TransferSubscriptionsResponse response = new TransferSubscriptionsResponse(service.createResponseHeader(), a(results, TransferResult.class), new DiagnosticInfo[0]);
service.setResponse(response);
}
use of org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription in project milo by eclipse.
the class SessionFsmFactory method createSession.
@SuppressWarnings("Duplicates")
private static CompletableFuture<CreateSessionResponse> createSession(FsmContext<State, Event> ctx, OpcUaClient client) {
UaStackClient stackClient = client.getStackClient();
EndpointDescription endpoint = stackClient.getConfig().getEndpoint();
String gatewayServerUri = endpoint.getServer().getGatewayServerUri();
String serverUri;
if (gatewayServerUri != null && !gatewayServerUri.isEmpty()) {
serverUri = endpoint.getServer().getApplicationUri();
} else {
serverUri = null;
}
ByteString clientNonce = NonceUtil.generateNonce(32);
ByteString clientCertificate = stackClient.getConfig().getCertificate().map(c -> {
try {
return ByteString.of(c.getEncoded());
} catch (CertificateEncodingException e) {
return ByteString.NULL_VALUE;
}
}).orElse(ByteString.NULL_VALUE);
ApplicationDescription clientDescription = new ApplicationDescription(client.getConfig().getApplicationUri(), client.getConfig().getProductUri(), client.getConfig().getApplicationName(), ApplicationType.Client, null, null, null);
CreateSessionRequest request = new CreateSessionRequest(client.newRequestHeader(), clientDescription, serverUri, client.getConfig().getEndpoint().getEndpointUrl(), client.getConfig().getSessionName().get(), clientNonce, clientCertificate, client.getConfig().getSessionTimeout().doubleValue(), client.getConfig().getMaxResponseMessageSize());
LOGGER.debug("[{}] Sending CreateSessionRequest...", ctx.getInstanceId());
return stackClient.sendRequest(request).thenApply(CreateSessionResponse.class::cast).thenCompose(response -> {
try {
SecurityPolicy securityPolicy = SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri());
if (securityPolicy != SecurityPolicy.None) {
if (response.getServerCertificate().isNullOrEmpty()) {
throw new UaException(StatusCodes.Bad_SecurityChecksFailed, "Certificate missing from CreateSessionResponse");
}
List<X509Certificate> serverCertificateChain = CertificateUtil.decodeCertificates(response.getServerCertificate().bytesOrEmpty());
X509Certificate serverCertificate = serverCertificateChain.get(0);
X509Certificate certificateFromEndpoint = CertificateUtil.decodeCertificate(endpoint.getServerCertificate().bytesOrEmpty());
if (!serverCertificate.equals(certificateFromEndpoint)) {
throw new UaException(StatusCodes.Bad_SecurityChecksFailed, "Certificate from CreateSessionResponse did not " + "match certificate from EndpointDescription!");
}
client.getConfig().getCertificateValidator().validateCertificateChain(serverCertificateChain, endpoint.getServer().getApplicationUri(), EndpointUtil.getHost(endpoint.getEndpointUrl()));
SignatureData serverSignature = response.getServerSignature();
byte[] dataBytes = Bytes.concat(clientCertificate.bytesOrEmpty(), clientNonce.bytesOrEmpty());
byte[] signatureBytes = serverSignature.getSignature().bytesOrEmpty();
SignatureUtil.verify(SecurityAlgorithm.fromUri(serverSignature.getAlgorithm()), serverCertificate, dataBytes, signatureBytes);
}
return completedFuture(response);
} catch (UaException e) {
return failedFuture(e);
}
});
}
use of org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription in project milo by eclipse.
the class SessionManager method stripNonEssentialFields.
/**
* Strip the non-essential fields from an EndpointDescription and its ApplicationDescription
* for return by the CreateSession service.
* <p>
* See Part 4, 5.6.6.2 for details.
*
* @param endpoint the {@link EndpointDescription} to strip non-essential fields from.
* @return a new {@link EndpointDescription} with only the essential fields.
*/
private static EndpointDescription stripNonEssentialFields(EndpointDescription endpoint) {
// It is recommended that Servers only include the server.applicationUri, endpointUrl,
// securityMode, securityPolicyUri, userIdentityTokens, transportProfileUri, and
// securityLevel with all other parameters set to null. Only the recommended parameters
// shall be verified by the client.
ApplicationDescription applicationDescription = endpoint.getServer();
ApplicationDescription newApplicationDescription = new ApplicationDescription(applicationDescription.getApplicationUri(), null, null, ApplicationType.Server, null, null, null);
return new EndpointDescription(endpoint.getEndpointUrl(), newApplicationDescription, ByteString.NULL_VALUE, endpoint.getSecurityMode(), endpoint.getSecurityPolicyUri(), endpoint.getUserIdentityTokens(), endpoint.getTransportProfileUri(), endpoint.getSecurityLevel());
}
use of org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription in project milo by eclipse.
the class SessionManager method createSession.
private CreateSessionResponse createSession(ServiceRequest serviceRequest) throws UaException {
CreateSessionRequest request = (CreateSessionRequest) serviceRequest.getRequest();
long maxSessionCount = server.getConfig().getLimits().getMaxSessionCount().longValue();
if (createdSessions.size() + activeSessions.size() >= maxSessionCount) {
throw new UaException(StatusCodes.Bad_TooManySessions);
}
ByteString serverNonce = NonceUtil.generateNonce(32);
NodeId authenticationToken = new NodeId(0, NonceUtil.generateNonce(32));
long maxRequestMessageSize = serviceRequest.getServer().getConfig().getEncodingLimits().getMaxMessageSize();
double revisedSessionTimeout = Math.max(5000, Math.min(server.getConfig().getLimits().getMaxSessionTimeout(), request.getRequestedSessionTimeout()));
ApplicationDescription clientDescription = request.getClientDescription();
long secureChannelId = serviceRequest.getSecureChannelId();
EndpointDescription endpoint = serviceRequest.getEndpoint();
SecurityPolicy securityPolicy = SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri());
EndpointDescription[] serverEndpoints = server.getEndpointDescriptions().stream().filter(ed -> !ed.getEndpointUrl().endsWith("/discovery")).filter(ed -> endpointMatchesUrl(ed, request.getEndpointUrl())).filter(ed -> Objects.equal(endpoint.getTransportProfileUri(), ed.getTransportProfileUri())).map(SessionManager::stripNonEssentialFields).toArray(EndpointDescription[]::new);
if (serverEndpoints.length == 0) {
// GetEndpoints in UaStackServer returns *all* endpoints regardless of a hostname
// match in the endpoint URL if the result after filtering is 0 endpoints. Do the
// same here.
serverEndpoints = server.getEndpointDescriptions().stream().filter(ed -> !ed.getEndpointUrl().endsWith("/discovery")).filter(ed -> Objects.equal(endpoint.getTransportProfileUri(), ed.getTransportProfileUri())).map(SessionManager::stripNonEssentialFields).toArray(EndpointDescription[]::new);
}
ByteString clientNonce = request.getClientNonce();
if (securityPolicy != SecurityPolicy.None) {
NonceUtil.validateNonce(clientNonce);
if (clientNonces.contains(clientNonce)) {
throw new UaException(StatusCodes.Bad_NonceInvalid);
}
}
if (securityPolicy != SecurityPolicy.None && clientNonce.isNotNull()) {
clientNonces.add(clientNonce);
while (clientNonces.size() > 64) {
clientNonces.remove(0);
}
}
ByteString clientCertificateBytes = request.getClientCertificate();
if (securityPolicy != SecurityPolicy.None && serviceRequest.getClientCertificateBytes() != null) {
if (!Objects.equal(clientCertificateBytes, serviceRequest.getClientCertificateBytes())) {
throw new UaException(StatusCodes.Bad_SecurityChecksFailed, "certificate used to open secure channel " + "differs from certificate used to create session");
}
}
SecurityConfiguration securityConfiguration = createSecurityConfiguration(endpoint, clientCertificateBytes);
if (securityPolicy != SecurityPolicy.None) {
X509Certificate clientCertificate = securityConfiguration.getClientCertificate();
List<X509Certificate> clientCertificateChain = securityConfiguration.getClientCertificateChain();
if (clientCertificate == null || clientCertificateChain == null) {
throw new UaException(StatusCodes.Bad_SecurityChecksFailed, "client certificate must be non-null");
}
ServerCertificateValidator certificateValidator = server.getConfig().getCertificateValidator();
certificateValidator.validateCertificateChain(clientCertificateChain, clientDescription.getApplicationUri());
}
// SignatureData must be created using only the bytes of the client
// leaf certificate, not the bytes of the client certificate chain.
SignatureData serverSignature = getServerSignature(securityPolicy, securityConfiguration.getKeyPair(), clientNonce, securityConfiguration.getClientCertificateBytes());
NodeId sessionId = new NodeId(1, "Session:" + UUID.randomUUID());
String sessionName = request.getSessionName();
Duration sessionTimeout = Duration.ofMillis(DoubleMath.roundToLong(revisedSessionTimeout, RoundingMode.UP));
Session session = new Session(server, sessionId, sessionName, sessionTimeout, clientDescription, request.getServerUri(), request.getMaxResponseMessageSize(), endpoint, secureChannelId, securityConfiguration);
session.setLastNonce(serverNonce);
session.addLifecycleListener((s, remove) -> {
createdSessions.remove(authenticationToken);
activeSessions.remove(authenticationToken);
sessionListeners.forEach(l -> l.onSessionClosed(s));
});
createdSessions.put(authenticationToken, session);
sessionListeners.forEach(l -> l.onSessionCreated(session));
return new CreateSessionResponse(serviceRequest.createResponseHeader(), sessionId, authenticationToken, revisedSessionTimeout, serverNonce, endpoint.getServerCertificate(), serverEndpoints, new SignedSoftwareCertificate[0], serverSignature, uint(maxRequestMessageSize));
}
Aggregations