SMTP/POP3 through proxy System.getProperties() vs new Properties()? - java

Im trying to get mail from a POP3 server through a proxy. Most "tutorials" suggest doing something like
Properties p = System.getProperties();
p.setProperty("proxySet", "true");//does this line even do anything?
p.setProperty("socksProxyHost", proxyHost);
p.setPorperty("socksProxyPort", proxyPort);
p.setProperty("socksProxyVersion", "5");//or 4 if you want to use 4
p.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
p.setProperty("mail.pop3.socketFactory.fallback", "false");//also not sure what it does
p.setProperty("mail.pop3.port", portOnHostYouWantToTalkTo);
p.setProperty("mail.pop3.socketFactory.port", portOnHostYouWantToTalkTo);
Session session = Session.getDefaultInstance(p, null);
//or session = Session.getInstance(p, null);
URLName urlName = new URLName(protocol, hostYouwantToTalkTo, portOnHostYouWantToTalkTo, null, mailbox, mailboxPassword);
Store store = session.getStore(urlName);
Now, if I do something like this I get an exception:
java.net.SocketException: Can't connect to SOCKS proxy:Connection timed out: connect.
My POP3 server does not log any connections, suggesting there is a proxy issue or an error in my code. I am using 73.29.157.190:29099 for now.
2) If, however, I do
Properties p = new Properties();
//all the same logic and stuff
Session = Session.getInstance(p, null);
My POP3 server logs a connection from localhost, and works properly, suggesting that I am NOT using a proxy to connect to it and everything else is fine.
My question is, why do "tutorials" use System.getProperties() and pass it to getInstance()? Every Session instance will keep a reference to System.properties. So, effectively every Session instance will be affected every time you try to create a new one or alter System.getProperties() in any way so you might as well reuse the same one.
Does javamail need something set in System.properties specifically and not the ones passed to Session?
Also, what parameters do you need to set in order to get javamail to use a proxy? What does System.properties have that makes it work unlike my new Properties? A link to a good tutorial or documentation that explains it would be greatly appreciated.
Thanks!

First, get rid of all the socket factory stuff, you don't need it.
Next, make sure you really have a SOCKS proxy and not just a web proxy. If you do, see this JavaMail FAQ entry.
Setting the System properties for a SOCKS proxy will cause all network connections from your program to go through the proxy server, which may not be what you want.

Related

Remote access to Message Queue over SSL in GlassFish

I'm trying to access a Message Queue configured in GlassFish but have been facing a lot of problems. The first one is regarding the Trust Store password on the client side. I can only make it work if I use the default password (changeit), I'm always getting
Keystore was tampered with, or password was incorrect
if I try to use a different password. And yes, I'm pretty sure I'm using the correct password.
In fact, if I set the Trust Store with the default password and use the following property with a wrong value, it still works:
-Djavax.net.ssl.trustStorePassword=<wrong value>
Which leads me to conclude that it completely ignores this setting.
This is what I've so far:
System.setProperty("com.sun.CSIV2.ssl.standalone.client.required", "true");
System.setProperty("javax.net.ssl.trustStore", "<my path>/truststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "<my password>");
Properties properties = new Properties();
System.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
System.setProperty("org.omg.CORBA.ORBInitialPort", "3820");
InitialContext ctx = new InitialContext(properties);
com.sun.messaging.ConnectionFactory connectionFactory = new com.sun.messaging.ConnectionFactory();
connectionFactory.setProperty(ConnectionConfiguration.imqAddressList, "127.0.0.1:7676");
connectionFactory.setProperty(ConnectionConfiguration.imqDefaultUsername, "<app user>");
connectionFactory.setProperty(ConnectionConfiguration.imqDefaultPassword, "<app user password>");
QueueConnection queueConnection = connectionFactory.createQueueConnection();
queueConnection.start();
So, my first question is: How can I use the non-default password on my Trust Store? Do I have to use some kind of encoding/hashing on the value?
My second question is regarding authentication. The standard way of getting the Connection Factory (via JNDI) and authenticate (via createQueueConnection(user, pass)) does not seem to be working, it always tries to use the guest account. Is there a way to use the standard approach on GlassFish or am I limited to use proprietary code?
EDIT #1
After digging a little deeper, I've detected a behavior that seems a bug.
Looking at the stacktrace, one of the first methods being invoked is initJKS() from com.sun.enterprise.security.ssl.impl.SecuritySupportImpl. With the help of javassist, I realized that the following section is being invoked:
if (masterPasswordHelper == null && Globals.getDefaultHabitat() != null) {
masterPasswordHelper = Globals.getDefaultHabitat().getByType(MasterPasswordImpl.class);
}
if (masterPasswordHelper instanceof MasterPasswordImpl) {
keyStorePass = masterPasswordHelper.getMasterPassword();
trustStorePass = keyStorePass;
}
Causing the bypass of the next set of instructions:
if (keyStorePass == null) {
keyStorePass = System.getProperty(KEYSTORE_PASS_PROP, DEFAULT_KEYSTORE_PASS).toCharArray();
trustStorePass = System.getProperty(TRUSTSTORE_PASS_PROP, DEFAULT_TRUSTSTORE_PASS).toCharArray();}
And, as a consequence, to ignore the property javax.net.ssl.trustStorePassword. Why is Globals.getDefaultHabitat() returning a non null value?

What is the use of javax.mail.Session?

I was fixing a class responsible for sending emails. It looked like this (simplified):
/* ... */
Properties props = System.getProperties();
props.put("mail.smtp.host", A_VALID_IP_OF_MAIL_SERVER);
Session session = Session.getDefaultInstance(props, null);
try {
Message msg = new MimeMessage(session);
/* msg.setFrom(); msg.addRecipient(); etc. */
Transport.send(msg);
System.out.println("Sent!");
}
catch (Exception e) { /* ... */ }
/* ... */
During my work I set session to null and to my utter surprise the class still worked fine. It doesn't matter if I pass null to MimeMessage constructor. It doesn't throw an exception or anything. Moreover, the Transport.send() method includes the following lines:
240 Session s = (msg.session != null) ? msg.session :
241 Session.getDefaultInstance(System.getProperties(), null);
So if the session is null it just creates a new one using system properties. What is then the purpose of creating a Session object at all? Why doesn't MimeMessage have a default constructor if it doesn't matter what you pass in there?
I viewed a number of examples of using javax.mail, such as: example from Google and
example from tutorialspoint and they both create a Session object which seems pretty useless. Why would anyone do that?
What is then the purpose of creating a Session object at all?
The session is the context of how you are going to interact with the mail host. This includes but not limited to debugging output from the mail host, timeouts, and authentication mechanisms. If you want to interact with the same mail host in different ways then the session is the object that holds this information.
If a single JVM needs to connect to multiple mail servers you need two different sessions. This is explained in detail in the JavaMail FAQ:
If some other code in the same JVM (e.g., in the same app server) has already created the default Session with their properties, you may end up using their Session and your properties will be ignored. This often explains why your property settings seem to be ignored. Always use Session.getInstance to avoid this problem.
Most JavaMail examples fail the common mistakes test. Try to reference the JavaMail API sample programs Session.getDefaultInstance is rarely the right choice for any code. Most code should use Session.getInstance. Including a default constructor for MimeMessage would just encourage wrong behavior.

Java LDAP with multiple network interface

I have a server with two NICs and I need to specify which NIC must be used to to connect to a backend LDAP.
I know that in Java the NICs can be specified when a socket is created (http://docs.oracle.com/javase/tutorial/networking/nifs/definition.html), but how can I do that using the
JNDI/LDAP framework?
Thanks
What you need to do is to obtain control over JNDI's process of creating a socket. For that, you need to tell JNDI which SocketFactory to use.
When constructing the InitialLdapContext, you can provide a Hashtable.
Hashtable props = new Hashtable();
props.put("java.naming.ldap.factory.socket", "com.whatever.MySocketFactory");
InitialLdapContext ic = new InitialLdapContext(props, null);
When com.whatever.MySocketFactory is your own class, extending javax.net.SocketFactory.
I think there's a constant somewhere in the JDK for java.naming.ldap.factory.socket, but I can't find it...
Or you could use:
env.put(Context.PROVIDER_URL, "ldap://<specific IP Address>:636/o=JNDITutorial");
-jim

How do you connect to a Multi-Instance Queue Manager using MQQueueConnectionFactory

We have an application which needs to communicate with a Multi-Instance QueueManager. Both (instances) are running on the default port and have unique addresses.
serverA.internal.company.address
serverB.internal.company.address
We use the following code to establish the ConnectionFactory:
MQQueueConnectionFactory connectionFactory = new MQQueueConnectionFactory();
connectionFactory.setTransportType(1);
connectionFactory.setPort(1414);
connectionFactory.setChannel("CLIENTCONNECTION");
connectionFactory.setQueueManager("queue.manager.name.here");
connectionFactory.setHostName("serverA.internal.company.address");
How can we specify both addresses so that failover is achieved without writing our own retry logic?
using the following:
connectionFactory.setConnectionNameList("serverA.internal.company.address(1414),"
+ "serverB.internal.company.address(1414)")
instead of
connectionFactory.setHostName("serverA.internal.company.address");
connectionFactory.setPort(1414);
did the trick for us.
You are on exactly the correct track - but please do review this technote for information.
http://www-01.ibm.com/support/docview.wss?uid=swg21508357

How to SSH to a server behind another SSH server using JSch?

I need to be able to ssh from a Java program into a remote server, and from there SSH to another server. I have credentials for both servers on my client.
The commands will be passed automatically from within the app as regular strings (no user input). I need to be able to run those custom commands on the second server and be able to decide what commands to issue during runtime, based on the output and some simple logic.
Can I use JSch to do that and if yes, where should I start look into? (Examples, info)
=============================================================
ADDED:
Exception in thread "main" com.jcraft.jsch.JSchException:
UnknownHostKey: host.net. RSA key fingerprint is 'blahblahblah'
as till now, I am solving this problem by modifying the known_hosts file and adding host manually in there.
Can I bypass this little problem by settings an option somewhere telling the JSch to press YES automatically when this YES-NO question is asked?
To connect to a second server behind a firewall, there are in principle two options.
The naive one would be to call ssh on the first server (from an exec channel), indicating the right server. This would need agent forwarding with JSch, and also doesn't provide the JSch API to access the second server, only the ssh command line.
The better one would be to use the connection to the first server to build up a TCP Tunnel, and use this tunnel to connect to the second server. The JSch Wiki contains a ProxySSH class (together with some example code) which allows to use a JSch session as a tunnel for a second JSch session. (Disclaimer: This class was written mainly by me, with some support from the JSch author.)
When you have your connection to the second server, use either a shell channel or a series of exec channels to execute your commands. (See Shell, Exec or Subsystem Channel in the JSch Wiki for an overview, and the Javadocs for details.)
For your unknown-host-key problem:
The secure version would be to collect all host keys (in a secure way) before and put them in the known_hosts file. (If you simply trust the key which is presented to you, you are vulnerable to a man-in-the-middle attack. If these are of no concern in your network, since it is physically secured, good for you.)
The convenient version is setting the configuration option StrictHostKeyChecking to no - this will add unknown host keys to the host keys file:
JSch.setConfig("StrictHostKeyChecking", "no");
(You can also set it individually on the sessions, if you only want to set it for the proxied sessions and not for the tunnel session. Or override it for the tunnel session with yesor ask - there the MITM danger might be greater.)
A middle way would be to enable actually asking the user (which then should compare the fingerprints to some list) - for this, implement the UserInfo interface and provide the object to the session. (The JSch Wiki contains an example implementation using Swing JOptionPanes, which you can simply use if your client program runs on a system with GUI.)
For the saving of accepted host keys to work, you must use the JSch.setKnownHosts method with a file name argument, not the one with an InputStream argument - else your accepting will have to be repeated for each restart of your client.
Use an SSH tunnel, aka local port forwarding, to open an SSH/SFTP connection to B via A.
Session sessionA = jsch.getSession("usernameA", "hostA");
// ...
sessionA.connect();
int forwardedPort = sessionA.setPortForwardingL(0, "hostB", 22);
Session sessionB = jsch.getSession("usernameB", "localhost", forwardedPort);
// ...
sessionB.connect();
// Use sessionB here for shell/exec/sftp
You may need to deal with UnknownHostKey exception.
This can help anyone. Works fine:
public static void sesionA(){
try {
Session sessionA = jSch.getSession(username, hostA);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
sessionA.setConfig(config);
sessionA.setPassword(passwordA);
sessionA.connect();
if(sessionA.isConnected()) {
System.out.println("Connected host A!");
forwardedPort = 2222;
sessionA.setPortForwardingL(forwardedPort, hostB, 22);
}
} catch (JSchException e) {
e.printStackTrace();
}
}
public static void sesionB(){
try {
Session sessionB = jSch.getSession(username, "localhost", forwardedPort);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
sessionB.setConfig(config);
sessionB.setPassword(passwordB);
sessionB.connect();
if(sessionB.isConnected()) {
System.out.println("Connected host B!");
}
}
}

Categories