I'm currently looking into settings up a client/server application using Akka remote actors to communicate. As a part of that setup, I would like to enable the build-in ssl mode, which is supported through netty.
However I'm not entirely sure on how to exactly set the parameters, even though I have tried a number of different combinations.
I have used http://doc.akka.io/docs/akka/2.2.0/java/remoting.html for reference on the different parameters.
Regarding creating keystore and truststore I have used the guide in this link:
http://www.ibm.com/developerworks/library/j-customssl/sidebar.html
The relevant part of my configuration looks like this on the client:
remote {
enabled-transports = ["akka.remote.netty.ssl"]
netty.ssl {
host = ""
port = 0
enable-ssl = true
}
netty.ssl.security {
key-store = "ServiceTesterClientKeys"
trust-store = "clientTrust"
key-store-password = "XX"
key-password = "XX"
trust-store-password = "YY"
protocol = "TLSv1"
random-number-generator = "AES128CounterSecureRNG"
enabled-algorithms = [TLS_RSA_WITH_AES_128_CBC_SHA]
}
}
and like this on the server:
remote {
enabled-transports = ["akka.remote.netty.ssl"]
netty.ssl {
hostname = ""
port = 2562
enable-ssl = true
}
netty.ssl.security {
key-store = "serverKeys"
trust-store = "serverTrust"
key-store-password = "YY"
key-password = "YY"
trust-store-password = "XX"
protocol = "TLSv1"
random-number-generator = "AES128CounterSecureRNG"
enabled-algorithms = [TLS_RSA_WITH_AES_128_CBC_SHA]
}
}
Do I need to add the properties or can Akka find it as long as it's on the classpath?
-Djavax.net.ssl.keyStore=A
-Djavax.net.ssl.trustStore=B
At runtime I get a long stack, but in the beginning it says:
[MySystem-akka.actor.default-dispatcher-11] ERROR akka.remote.EndpointWriter - AssociationError [akka.ssl.tcp://MySystem#10.195.20.11:10693] -> [akka.ssl.tcp://MyServerSystem#localhost:2562]: Error [Association failed with [akka.ssl.tcp://MyServerSystem#localhost:2562]] [
akka.remote.EndpointAssociationException: Association failed with [akka.ssl.tcp://MyServerSystem#localhost:2562]
Caused by: akka.remote.transport.netty.NettyTransport$$anonfun$associate$1$$anon$2: Failed to initialize a pipeline.
Caused by: akka.remote.RemoteTransportException: Client SSL connection could not be established because SSL context could not be constructed.
Help would be very much appreciated.
Regards Stefan
Okay, I have looked further into the issue.
The problem was related to the random-number-generator = "AES128CounterSecureRNG" property.
Instead I have choosen to use the default implementation.
I guess I will need to add the provider, if I want to use this implementation.
For those who looked thanks for your time.
Related
I have two servers:
Server1: 10.7.44.49
Server2: 10.7.44.71
and two actorSystems running on those servers:
akka://Test#10.7.44.49:5555
akka://Test#10.7.44.71:5555
I'm trying to deploy an actor from Server2 to Server1 remotely.
To achieve that, I set in the configuration of Server2:
deployment {
/simpleActor {
remote = "akka://Test#10.7.44.49:5555"
}
But I get:
[WARN] [09/07/2022 13:36:53.156] [sbt-bg-threads-1] [akka.remote.RemoteActorRefProvider] Remote deploy of [akka://Test/user/simpleActor] is not allowed, falling back to local.
I also tried to achieve it programmatically:
val address = AddressFromURIString("akka://Test#10.7.44.49:5555")
val actorRef = system.actorOf(Props[SimpleActor]().withDeploy(Deploy(scope = RemoteScope(address))))
But the result is the same.
Any clue on deploying an actor to another actorSystem running on a different machine?
Reference: https://doc.akka.io/docs/akka/current/remoting.html#programmatic-remote-deployment
That is logged in the else clause of this if:
hasClusterOrUseUnsafe && shouldCreateRemoteActorRef(system, address)
hasClusterOrUseUnsafe returns true if and only if one of akka.actor.provider = cluster or akka.remote.use-unsafe-remote-features-outside-cluster = true in your config
shouldCreateRemoteActorRef is almost certainly going to be true (unless you're using a custom RemoteActorRefProvider, in which case you're basically on your own)
So setting one of
akka.actor.provider = cluster
akka.remote.use-unsafe-remote-features-outside-cluster = true
I am working on a application that connects to an SFTP server and downloads files using Apache Commons VFS, it works just fine, with the exception that the system needs to allow the user to specify a proxy, as needed.
Now, I know Apache Commons VFS is built on top of Jsch and I know Jsch contains the classes: com.jcraft.jsch.ProxyHTTP, com.jcraft.jsch.ProxySOCKS4 and com.jcraft.jsch.ProxySOCKS5.
The code below is an extract of VFS class org.apache.commons.vfs2.provider.sftp.SftpClientFactory:
public static Session createConnection(
...
final SftpFileSystemConfigBuilder.ProxyType proxyType = builder.getProxyType(fileSystemOptions);
...
final String proxyUser = builder.getProxyUser(fileSystemOptions);
final String proxyPassword = builder.getProxyPassword(fileSystemOptions);
Proxy proxy = null;
if (SftpFileSystemConfigBuilder.PROXY_HTTP.equals(proxyType)) {
proxy = createProxyHTTP(proxyHost, proxyPort);
((ProxyHTTP)proxy).setUserPasswd(proxyUser, proxyPassword);
} else if (SftpFileSystemConfigBuilder.PROXY_SOCKS5.equals(proxyType)) {
proxy = createProxySOCKS5(proxyHost, proxyPort);
((ProxySOCKS5)proxy).setUserPasswd(proxyUser, proxyPassword);
} else if (SftpFileSystemConfigBuilder.PROXY_STREAM.equals(proxyType)) {
proxy = createStreamProxy(proxyHost, proxyPort, fileSystemOptions, builder);
}
...
As you can you see, there's no "if" statement to instantiate ProxySOCKS4!
I have duplicated the SftpClientFactory class, set my version to load before the original class on the classpath and changed the code as follow:
public static Session createConnection(
...
final SftpFileSystemConfigBuilder.ProxyType proxyType = builder.getProxyType(fileSystemOptions);
...
final String proxyUser = builder.getProxyUser(fileSystemOptions);
final String proxyPassword = builder.getProxyPassword(fileSystemOptions);
Proxy proxy = null;
if (SftpFileSystemConfigBuilder.PROXY_HTTP.equals(proxyType)) {
proxy = createProxyHTTP(proxyHost, proxyPort);
((ProxyHTTP)proxy).setUserPasswd(proxyUser, proxyPassword);
/// change start (I also created the PROXY_SOCKS4 constant)
} else if (SftpFileSystemConfigBuilder.PROXY_SOCKS4.equals(proxyType)) {
proxy = createProxySOCKS4(proxyHost, proxyPort);
((ProxySOCKS4)proxy).setUserPasswd(proxyUser, proxyPassword);
/// change end
} else if (SftpFileSystemConfigBuilder.PROXY_SOCKS5.equals(proxyType)) {
proxy = createProxySOCKS5(proxyHost, proxyPort);
((ProxySOCKS5)proxy).setUserPasswd(proxyUser, proxyPassword);
} else if (SftpFileSystemConfigBuilder.PROXY_STREAM.equals(proxyType)) {
proxy = createStreamProxy(proxyHost, proxyPort, fileSystemOptions, builder);
}
...
.. and guess what, when I set my application to use a Socks 4 Proxy it works alright with the change above. It is important to say that setting the application to work with Socks 5 does not work if the proxy server is a Socks 4 type, and that's true not only for my application with VFS, but also any other client I tested, like Fillezila or WinSCP.
So, the main question is:
Why does VFS predicts the usage of ProxyHTTP, ProxySOCKS5 but completely ignores the JSch ProxySOCKS4 class? Am I missing some SFTP or Proxy concept here or should I consider VFS bugged? That's the first time I work with VFS.
Please consider the question in bold as the main question not to make it too broad.
I wasn't able to get or find a better answer in time, so what I did to solve my problem was exactly what I described in the question.
I duplicated the classes SftpClientFactory e SftpFileSystemConfigBuilder, made the necessary adjustments and used them instead of the original classes, it's ugly and now I am stuck with a specific VFS version, I know, but the problem was solved.
Lesson for next time: use Jsch instead of VFS.
I'll leave the question open though, in case someone else have a proper solution or answer.
I have problem with vertx HttpClient.
Here's code which shows that tests GET using vertx and plain java.
Vertx vertx = Vertx.vertx();
HttpClientOptions options = new HttpClientOptions()
.setTrustAll(true)
.setSsl(false)
.setDefaultPort(80)
.setProtocolVersion(HttpVersion.HTTP_1_1)
.setLogActivity(true);
HttpClient client = vertx.createHttpClient(options);
client.getNow("google.com", "/", response -> {
System.out.println("Received response with status code " + response.statusCode());
});
System.out.println(getHTML("http://google.com"));
Where getHTML() is from here: How do I do a HTTP GET in Java?
This is my output:
<!doctype html><html... etc <- correct output from plain java
Feb 08, 2017 11:31:21 AM io.vertx.core.http.impl.HttpClientRequestImpl
SEVERE: java.net.UnknownHostException: failed to resolve 'google.com'. Exceeded max queries per resolve 3
But vertx can't connect. What's wrong here? I'm not using any proxy.
For reference: a solution, as described in this question and in tsegismont's comment here, is to set the flag vertx.disableDnsResolver to true:
-Dvertx.disableDnsResolver=true
in order to fall back to the JVM DNS resolver as explained here:
sometimes it can be desirable to use the JVM built-in resolver, the JVM system property -Dvertx.disableDnsResolver=true activates this behavior
I observed this DNS resolution issue with a redis client in a kubernetes environment.
I had this issue, what caused it for me was stale DNS servers being picked up by the Java runtime, i.e. servers registered for a network the machine was no longer connected to. The issue is first in the Sun JNDI implementation, it also exists in Netty which uses JNDI to bootstrap its list of name servers on most platforms, then finally shows up in VertX.
I think a good place to fix this would be in the Netty layer where the set of default DNS servers is bootstrapped. I have raised a ticket with the Netty project so we'll see if they agree with me! Here is the Netty ticket
In the mean time a fairly basic workaround is to filter the default DNS servers detected by Netty, based on whether they are reachable or not. Here is a code Sample in Kotlin to apply before constructing the main VertX instance.
// The default set of name servers provided by JNDI can contain stale entries
// This default set is picked up by Netty and in turn by VertX
// To work around this, we filter for only reachable name servers on startup
val nameServers = DefaultDnsServerAddressStreamProvider.defaultAddressList()
val reachableNameServers = nameServers.stream()
.filter {ns -> ns.address.isReachable(NS_REACHABLE_TIMEOUT)}
.map {ns -> ns.address.hostAddress}
.collect(Collectors.toList())
if (reachableNameServers.size == 0)
throw StartupException("There are no reachable name servers available")
val opts = VertxOptions()
opts.addressResolverOptions.servers = reachableNameServers
// The primary Vertx instance
val vertx = Vertx.vertx(opts)
A little more detail in case it is helpful. I have a company machine, which at some point was connected to the company network by a physical cable. Details of the company's internal name servers were set up by DHCP on the physical interface. Using the wireless interface at home, DNS for the wireless interface gets set to my home DNS while the config for the physical interface is not updated. This is fine since that device is not active, ipconfig /all does not show the internal company DNS servers. However, looking in the registry they are still there:
Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces
They get picked up by the JNDI mechanism, which feeds Netty and in turn VertX. Since they are not reachable from my home location, DNS resolution fails. I can imagine this home/office situation is not unique to me! I don't know whether something similar could occur with multiple virtual interfaces on containers or VMs, it could be worth looking at if you are having problems.
Here is the sample code which works for me.
public class TemplVerticle extends HttpVerticle {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
// Create the web client and enable SSL/TLS with a trust store
WebClient client = WebClient.create(vertx,
new WebClientOptions()
.setSsl(true)
.setTrustAll(true)
.setDefaultPort(443)
.setKeepAlive(true)
.setDefaultHost("www.w3schools.com")
);
client.get("www.w3schools.com")
.as(BodyCodec.string())
.send(ar -> {
if (ar.succeeded()) {
HttpResponse<String> response = ar.result();
System.out.println("Got HTTP response body");
System.out.println(response.body().toString());
} else {
ar.cause().printStackTrace();
}
});
}
}
Try using web client instead of httpclient, here you have an example (with rx):
private val client: WebClient = WebClient.create(vertx, WebClientOptions()
.setSsl(true)
.setTrustAll(true)
.setDefaultPort(443)
.setKeepAlive(true)
)
open fun <T> get(uri: String, marshaller: Class<T>): Single<T> {
return client.getAbs(host + uri).rxSend()
.map { extractJson(it, uri, marshaller) }
}
Another option is to use getAbs.
I want to create an agent object using siteminder r.12. Want to find the values for the below parameters. Where is the value stored?
User-defined connection parameters defined in your codeāfor example:
AgentAPI agent = new AgentAPI();
ServerDef sd = new ServerDef();
sd.serverIpAddress = POLICY_IP;
sd.connectionMin = CX_MIN;
sd.connectionMax = CX_MAX;
sd.connectionStep = CX_STEP;
sd.timeout = CX_TIMEOUT;
sd.authorizationPort = AZ_PORT;
sd.authenticationPort = AUTH_PORT;
sd.accountingPort = ACC_PORT;
InitDef init=new InitDef(AGENT_LOGIN,SHARED_SECRET,false, sd);
agent.init(init);
Thanks,
navi
To use the AgentApi you will need to know some things about your Policy Server and agent. You will have to find the host address of the Policy Server, the agent name you will use to query the PS, the authorization port and authentication port and the shared secret.
Go here for the spec of the AgentApi:
https://support.ca.com/cadocs/0/CA%20SiteMinder%2012%2052-ENU/Bookshelf_Files/programming-reference/legacy-sm-java-sdk/netegrity/siteminder/javaagent/AgentAPI.html
the parameters you are looking for are related to Host Configuration Object (HCO) and SmHost.conf settings.
I'm writing client-side code for Windows Kerberos authentication with a service (logging code omitted):
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
// System.setProperty("sun.security.krb5.debug", "true");
Package thisPkg = AuthHelper.class.getPackage();
String configPath = Util.getConfigPath(thisPkg, "jaas.conf");
System.setProperty("java.security.auth.login.config", "=" + configPath);
GSSManager manager = GSSManager.getInstance();
GSSName peerName = manager.createName(spn, GSSName.NT_HOSTBASED_SERVICE);
GSSContext context = manager.createContext(peerName, null, null,
GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(true); // required
context.requestCredDeleg(true); // required for publish
byte[] serverTokenBytes = new byte[0];
while (!context.isEstablished()) {
byte[] clientTokenBytes = context.initSecContext(serverTokenBytes, 0,
serverTokenBytes.length);
if (clientTokenBytes != null)
socket.send(createClientMessage(clientTokenBytes));
if (context.isEstablished()) break;
Message message = socket.receive();
String serverToken = message.getFirst("SERVERTOKEN").toString();
serverTokenBytes = Base64.decodeBase64(serverToken);
}
Where jaas.conf simply contains:
sp {
com.sun.security.auth.module.Krb5LoginModule required debug=true;
};
I have also set the allowtgtsessionkey registry key as required, and installed JCE Unlimited Strength Jurisdiction Policy Files 7.
The code sometimes works (i.e. mutual authentication is established); however, sometimes it gets stuck for a while at the first call to GSSContext.initSecContext, throwing an exception after about a minute:
Exception in thread "main" GSSException: No valid credentials provided (Mechanism level: Receive timed out)
...
Caused by: java.net.SocketTimeoutException: Receive timed out
...
When I enable Kerberos debugging output (by uncommenting the second line above), I can see that the protocol sometimes gets stuck at line:
getKDCFromDNS using UDP
A Java Kerberos troubleshooting website suggests that this is an issue with the Kerberos authentication server, but I know that the server is up and running, since we have similar code written in C# (using .NET libraries) that never gets stuck.
It seems like the DNS resolution for the Kerberos authentication server is going through some indirection, which is unreliable. If you specify the server explicitly (somewhere at the beginning of your code), it will bypass that redirection:
System.setProperty("java.security.krb5.realm", "<YOUR_KRB_REALM>");
System.setProperty("java.security.krb5.kdc", "<YOUR_KRB_SERVER_ADDR_OR_IP>");
EDIT: It turns out that communication with Kerberos servers was inherently unreliable due to the protocol using UDP, so it had a high chance of failing for servers that are relatively far away. Windows 8 uses TCP by default; to force TCP on previous versions:
XP/2000: In HKLM\System\CurrentControlSet\Control\Lsa\Kerberos, set DWORD MaxPacketSize to 1.
2003/Vista/7: In HKLM\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters, set DWORD MaxPacketSize to 1.
(Note that the same registry directory also needs DWORD AllowTGTSessionKey set to 1 for Kerberos to work at all.)