I have builded a Java server that listen on a port (6666). Now, i need to connect to this server with a LDAP Browser (I use Softerra). The connection is done, but i have to know when there is an LDAP bind/search, and i have no idea of how to do that.
Here is the code of my server (feel free to tell me if it's not very clear/good, i'm quite new to Java Prog.):
package net.nantes.littleldap;
import java.net.*;
import java.io.*;
public class Serverside {
public static void main(String[] args) {
ServerSocket socketserver ;
Socket socket ;
BufferedReader in;
PrintWriter out;
try {
Authenticate auth = new Authenticate();
socketserver = new ServerSocket(6666);
System.out.println("Le serveur est à l'écoute du port "+socketserver.getLocalPort());
auth.connect();
socket = socketserver.accept();
String inputLine = new String();
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
System.out.println("Connecté au serveur");
while ((inputLine = in.readLine()) != null){
System.out.println(inputLine);
out = new PrintWriter(socket.getOutputStream());
out.println("Connection réussie");
out.flush();
}
socket.close();
socketserver.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
Sorry, the message are in french, but it's not really important. I think maybe I could do something with InputLine (when I print it, it returns some String relative to LDAP, but i can be hard to parse).
So, any idea ? Thanks a lot !
I would strongly recommend you utilize either JNDI or one of the LDAP SDKs that are available.
We like: https://www.unboundid.com/products/ldap-sdk/
-jim
In addition to listening to the port, your server has to "understand" the LDAP protocol.
I use the OpenDS LDAP SDK (http://www.middleware.vt.edu/pubs/opends-sdk-0.9.0/).
Code is like this
public class MyLdapServer
implements ServerConnectionFactory<LDAPClientContext, Integer> {
private LDAPListener listener;
public void init() {
try {
listener = new LDAPListener(1389, this);
} catch (IOException e) {
logger.error("error opening LDAP listener", e);
}
}
public void destroy() {
listener.close();
}
#Override
public ServerConnection<Integer> handleAccept(LDAPClientContext context)
throws ErrorResultException {
if (logger.isDebugEnabled())
logger.debug("ldap connection from: " + context.getPeerAddress());
IncomingLdapConnection ilc = new IncomingLdapConnection(context);
return ilc;
}
private static Logger logger = LoggerFactory.getLogger(MyLdapServer.class);
}
The IncomingLdapConnection allows you to handle the LDAP operations:
public class IncomingLdapConnection
implements ServerConnection<Integer> {
public void handleBind(Integer ctx, int version, BindRequest request,
ResultHandler<? super BindResult> resultHandler,
IntermediateResponseHandler intermediateResponseHandler)
throws UnsupportedOperationException {
if (request.getAuthenticationType() != -128) {
logger.warn("LDAP BIND: unsupported authentication type: " + request.getAuthenticationType());
resultHandler.handleResult(Responses.newBindResult(ResultCode.AUTH_METHOD_NOT_SUPPORTED));
return;
}
String bindName = request.getName();
if (bindName.length() > 0) {
if (request instanceof GenericBindRequest) {
GenericBindRequest bindRequest = (GenericBindRequest)request;
String userName = parseUidDn(bindName);
if (userName == null) {
// manche LDAP-Clients senden keine DN, sondern direkt den Namen
userName = bindName;
}
String password = bindRequest.getAuthenticationValue().toString();
logger.debug("LDAP BIND: non-anonymous bind, user = " + userName);
anonymous = false;
} else {
logger.warn("LDAP BIND: non-anonymous bind, but unsupported request");
resultHandler.handleResult(Responses.newBindResult(ResultCode.AUTH_METHOD_NOT_SUPPORTED));
return;
}
} else {
logger.debug("LDAP BIND: anonymous bind");
anonymous = true;
}
boolean success = anonymous;
if (!anonymous) {
// authenticate user, set "success"
}
if (success)
resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
else
resultHandler.handleResult(Responses.newBindResult(ResultCode.INVALID_CREDENTIALS));
authenticated = success;
}
EDIT:
OpenDS Code for answering to LDAP search requests
public void handleSearch(Integer ctx, SearchRequest request,
SearchResultHandler responseHandler, IntermediateResponseHandler intermediateResponseHandler)
throws UnsupportedOperationException {
if (request.getScope() == SearchScope.BASE_OBJECT && request.getName().isRootDN()) {
logger.debug("LDAP Search: BASE_OBJECT");
responseHandler.handleEntry(Responses.newSearchResultEntry(rootEntry));
} else {
// do the search
// parameters: request.getName(), request.getScope(), request.getFilter()
}
responseHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
}
Check out the UnboundID LDAP SDK and some sample code.
EDIT:
I would not recommend the use of JNDI:
JNDI uses a deprecated configuration
JNDI has software defects
JNDI does not fully support LDAP standards
see also
LDAP: Programming Practices
Related
I've spent many hours trying to figure out how to perform NTLM authentication on Android Studio with no luck. I realize NTLM is not native to Android. Recently, I have been using the JCIFS library
jcifs.Config.registerSmbURLHandler();
URL url = new URL("https://domain%5cuser:pass#host");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
But I have getting the error
"Unable to find default handler for protocol: https"
The same code works in standard Java. At this point I've exhausted every suggestion I have found and I have no idea what to do.
I'm attempting to resolve the same issue, and came across the following link (class is pasted below in case of link rot):
https://lists.samba.org/archive/jcifs/2013-July/010105.html
I then use the following to force the handler's use:
jcifs.Config.registerSmbURLHandler();
System.setProperty("http.auth.ntlm.domain", domain);
System.setProperty("jcifs.smb.client.domain", domain);
System.setProperty("jcifs.smb.client.username", username);
System.setProperty("jcifs.smb.client.password", password);
System.setProperty("java.protocol.handler.pkgs", "domain.com.package");
I'm having issues, however, as the response comes back empty, so more investigation needs to be done there.
(The copyright notice, etc. have been left off as it kept confusing SO's code block parser)
public class Handler extends URLStreamHandler {
/**
* The default HTTP port (<code>80</code>).
*/
public static final int DEFAULT_HTTP_PORT = 80;
private static final Map PROTOCOL_HANDLERS = new HashMap();
private static final String HANDLER_PKGS_PROPERTY =
"java.protocol.handler.pkgs";
/**
* Vendor-specific default packages. If no packages are specified in
* "java.protocol.handler.pkgs", the VM uses one or more default
* packages, which are vendor specific. Sun's is included below
* for convenience; others could be as well. If a particular vendor's
* package isn't listed, it can be specified in
* "java.protocol.handler.pkgs".
*/
private static final String[] JVM_VENDOR_DEFAULT_PKGS = new String[] {
"sun.net.www.protocol"
};
private static URLStreamHandlerFactory factory;
/**
* Sets the URL stream handler factory for the environment. This
* allows specification of the factory used in creating underlying
* stream handlers. This can be called once per JVM instance.
*
* #param factory The URL stream handler factory.
*/
public static void setURLStreamHandlerFactory(
URLStreamHandlerFactory factory) {
synchronized (PROTOCOL_HANDLERS) {
if (Handler.factory != null) {
throw new IllegalStateException(
"URLStreamHandlerFactory already set.");
}
PROTOCOL_HANDLERS.clear();
Handler.factory = factory;
}
}
/**
* Returns the default HTTP port.
*
* #return An <code>int</code> containing the default HTTP port.
*/
protected int getDefaultPort() {
return DEFAULT_HTTP_PORT;
}
#Override
protected URLConnection openConnection(URL url) throws IOException
{
return this.openConnection(url, null);
}
#Override
protected URLConnection openConnection(URL url, Proxy proxy) throws IOException
{
url = new URL(url, url.toExternalForm(), getDefaultStreamHandler(url.getProtocol()));
final HttpURLConnection urlConnection;
if (proxy == null) {
urlConnection = (HttpURLConnection) url.openConnection();
} else {
urlConnection = (HttpURLConnection) url.openConnection(proxy);
}
return new NtlmHttpURLConnection(urlConnection);
}
private static URLStreamHandler getDefaultStreamHandler(String protocol)
throws IOException {
synchronized (PROTOCOL_HANDLERS) {
URLStreamHandler handler = (URLStreamHandler)
PROTOCOL_HANDLERS.get(protocol);
if (handler != null) return handler;
if (factory != null) {
handler = factory.createURLStreamHandler(protocol);
}
if (handler == null) {
String path = System.getProperty(HANDLER_PKGS_PROPERTY);
StringTokenizer tokenizer = new StringTokenizer(path, "|");
while (tokenizer.hasMoreTokens()) {
String provider = tokenizer.nextToken().trim();
if (provider.equals("jcifs")) continue;
String className = provider + "." + protocol + ".Handler";
try {
Class handlerClass = null;
try {
handlerClass = Class.forName(className);
} catch (Exception ex) { }
if (handlerClass == null) {
handlerClass = ClassLoader.getSystemClassLoader(
).loadClass(className);
}
handler = (URLStreamHandler) handlerClass.newInstance();
break;
} catch (Exception ex) { }
}
}
if (handler == null) {
for (int i = 0; i < JVM_VENDOR_DEFAULT_PKGS.length; i++) {
String className = JVM_VENDOR_DEFAULT_PKGS[i] + "." +
protocol + ".Handler";
try {
Class handlerClass = null;
try {
handlerClass = Class.forName(className);
} catch (Exception ex) { }
if (handlerClass == null) {
handlerClass = ClassLoader.getSystemClassLoader(
).loadClass(className);
}
handler = (URLStreamHandler) handlerClass.newInstance();
} catch (Exception ex) { }
if (handler != null) break;
}
}
if (handler == null) {
throw new IOException(
"Unable to find default handler for protocol: " +
protocol);
}
PROTOCOL_HANDLERS.put(protocol, handler);
return handler;
}
}
}
Major edit: 2015-05-27: After some degree of success updated on where I'm currently stuck rather than leaving a rambling post....could really do with some pointers on this one - a little bogged down....
I'm running some code on a Linux app server (WebSphere) that needs to authenticate to an IIS web service which is configured for "Integrated Authentication", but I'm having some problems forming the Authorization: Negotiate token.
I should also say that I need to put this token into the HTTP header for a JAX-WS SOAP request that I will subsequently build. I know my SOAP request itself works because we were using WS-Security Username token profile previously and it worked fine - trying to swap to kerberos is proving difficult...
My problem is with initSecContext I think. It appears that on the first call the context is configured in "some" way and there is some returned token data, but .isEstablished is false. The problem I'm having is putting the initSecContext call into a loop - it seems IIS just closes the connection when I do this. Can anyone give me some pointers - I seem to be taking the approach used by other posters and the Oracle samples (although the IBM/WebSphere sample only makes a single initSecContext call and doesn't check .isEstablished which seems odd to me based on the Oracle documentation).
Anyway, the error I get is below (note the Ready: property seems to clearly say initSecContext needs to loop - to me at least);
[5/27/15 6:51:11:605 UTC] 0000004f SystemOut O INFO: com.mycorp.kerberosKerberosTokenGenerator/getKerberosToken/run: After initSecContext:
--- GSSContext ---
Owner: domainuser#MYDOMAIN.COM
Peer: HTTP/iishost.mycorp.com
State: initialized
Lifetime: indefinite
Ready: no
Flags:
Confidentiality off
Delegation on
Integrity off
MutualAuthn on
ReplayDetection off
SequenceDetection off
DelegatedCred: unknown
--- End of GSSContext ---
[5/27/15 6:51:11:605 UTC] 0000004f SystemOut O INFO: com.mycorp.kerberosKerberosTokenGenerator/getKerberosToken/run: Context is not established, trying again
[5/27/15 6:51:11:606 UTC] 0000004f SystemOut O ERROR: com.mycorp.kerberosKerberosTokenGenerator/getKerberosToken/run: IOException during context establishment: Connection reset
My code is below;
LoginContext lc = getLoginContext(contextName);
final Subject subject = lc.getSubject();
String b64Token = (String) Subject.doAs(subject, new PrivilegedExceptionAction() {
#Override
public Object run() throws PrivilegedActionException, GSSException {
// Create socket to server
Socket socket;
DataInputStream inStream = null;
DataOutputStream outStream = null;
try {
socket = new Socket("iishost.mycorp.com", 443);
inStream = new DataInputStream(socket.getInputStream());
outStream = new DataOutputStream(socket.getOutputStream());
} catch (IOException ex) {
System.out.println("Exception setting up server sockets: " + ex.getMessage());
}
GSSName gssName = manager.createName(userName, GSSName.NT_USER_NAME, KRB5_MECH_OID);
GSSCredential gssCred = manager.createCredential(gssName.canonicalize(KRB5_MECH_OID),
GSSCredential.DEFAULT_LIFETIME,
KRB5_MECH_OID,
GSSCredential.INITIATE_ONLY);
gssCred.add(gssName, GSSCredential.INDEFINITE_LIFETIME,
GSSCredential.INDEFINITE_LIFETIME,
SPNEGO_MECH_OID,
GSSCredential.INITIATE_ONLY);
GSSName gssServerName = manager.createName(servicePrincipal, KERBEROS_V5_PRINCIPAL_NAME);
GSSContext clientContext = manager.createContext(gssServerName.canonicalize(SPNEGO_MECH_OID),
SPNEGO_MECH_OID,
gssCred,
GSSContext.DEFAULT_LIFETIME);
clientContext.requestCredDeleg(true);
clientContext.requestMutualAuth(true);
byte[] token = new byte[0];
while (!clientContext.isEstablished()) {
try {
token = clientContext.initSecContext(token, 0, token.length);
// IF I LOOK AT token HERE THERE IS CERTAINLY TOKEN DATA THERE - .isEstablished IS STILL FALSE
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
// Check if we're done
if (!clientContext.isEstablished()) {
token = new byte[inStream.readInt()];
inStream.readFully(token);
}
} catch (IOException ex) {
// THIS EXCEPTION IS THROWN ON SECOND ITERATION - LOOKS LIKE IIS CLOSES THE CONNECTION
System.out.println("IOException during context establishment: " + ex.getMessage());
}
}
String b64Token = Base64.encode(token);
clientContext.dispose(); // I'm assuming this won't invalidate the token in some way as I need to use it later
return b64Token;
}
});
This doc tells me I don't need to loop on initSecContext, but .isEstablished returns false for me: http://www-01.ibm.com/support/knowledgecenter/SS7K4U_8.5.5/com.ibm.websphere.zseries.doc/ae/tsec_SPNEGO_token.html?cp=SS7K4U_8.5.5%2F1-3-0-20-4-0&lang=en
The Oracle docs tell me I should: https://docs.oracle.com/javase/7/docs/api/org/ietf/jgss/GSSContext.html
My only hesitation is that from the Oracle docs it seems like I'm starting the application conversation, but what I'm trying to do it obtain the token only & it's later on in my code when I will use JAX-WS to post my actual web service call (including the spnego/kerberos token in the http header) - is this the cause of my issue?
Just an update. I have this working now - my previous code was largely ok - it was just my understanding of how the Kerberos token would be added to the JAX-WS request. Turns out it's just a matter of attaching a Handler to the bindingProvider. The handler then obtains the Kerberos token and adds it to the header of the request - nice and easy.
Below is my working Handler which is added to the Handler chain obtained from a call to bindingProvider.getBinding().getHandlerChain()
public class HTTPKerberosHandler implements SOAPHandler<SOAPMessageContext> {
private final String contextName;
private final String servicePrincipal;
private static Oid KRB5_MECH_OID = null;
private static Oid SPNEGO_MECH_OID = null;
private static Oid KERBEROS_V5_PRINCIPAL_NAME = null;
final String className = this.getClass().getName();
static {
try {
KERBEROS_V5_PRINCIPAL_NAME = new Oid("1.2.840.113554.1.2.2.1");
KRB5_MECH_OID = new Oid("1.2.840.113554.1.2.2");
SPNEGO_MECH_OID = new Oid("1.3.6.1.5.5.2");
} catch (final GSSException ex) {
System.out.println("Exception creating mechOid's: " + ex.getMessage());
ex.printStackTrace();
}
}
public HTTPKerberosHandler(final String contextName, final String servicePrincipal) {
this.contextName = contextName;
this.servicePrincipal = servicePrincipal;
}
#Override
public Set<QName> getHeaders() {
return null;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
#Override
public void close(MessageContext context) {
// No action
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
if (((Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY))) {
return handleRequest(context);
} else {
return handleResponse(context);
}
}
private boolean handleRequest(SOAPMessageContext context) {
byte[] token = getKerberosToken(contextName, servicePrincipal);
HashMap<String, String> sendTransportHeaders = new HashMap<String, String>();
sendTransportHeaders.put("Authorization", "Negotiate " + Base64.encode(token));
context.put(com.ibm.websphere.webservices.Constants.REQUEST_TRANSPORT_PROPERTIES, sendTransportHeaders);
return true;
}
private boolean handleResponse(SOAPMessageContext context) {
logger.logInformation(className, "handleResponse", "Inbound response detected");
return true;
}
public byte[] getKerberosToken(final String contextName, final String servicePrincipal) {
try {
LoginContext lc = getLoginContext(contextName);
final Subject subject = lc.getSubject();
byte[] token = (byte[]) Subject.doAs(subject, new PrivilegedExceptionAction() {
#Override
public Object run() throws PrivilegedActionException, GSSException {
final String methodName = "getKerberosToken/run";
final GSSManager manager = GSSManager.getInstance();
Set<Principal> principals = subject.getPrincipals();
Iterator it = principals.iterator();
String principalName = ((Principal) it.next()).getName();
logger.logInformation(className, methodName, "Using principal: [" + principalName + "]");
GSSName gssName = manager.createName(principalName, GSSName.NT_USER_NAME, KRB5_MECH_OID);
GSSCredential gssCred = manager.createCredential(gssName.canonicalize(KRB5_MECH_OID),
GSSCredential.DEFAULT_LIFETIME,
KRB5_MECH_OID,
GSSCredential.INITIATE_ONLY);
gssCred.add(gssName, GSSCredential.INDEFINITE_LIFETIME,
GSSCredential.INDEFINITE_LIFETIME,
SPNEGO_MECH_OID,
GSSCredential.INITIATE_ONLY);
logger.logInformation(className, methodName, "Client TGT obtained: " + gssCred.toString());
GSSName gssServerName = manager.createName(servicePrincipal, GSSName.NT_USER_NAME);
GSSContext clientContext = manager.createContext(gssServerName.canonicalize(SPNEGO_MECH_OID),
SPNEGO_MECH_OID,
gssCred,
GSSContext.DEFAULT_LIFETIME);
logger.logInformation(className, methodName, "Service ticket obtained: " + clientContext.toString());
byte[] token = new byte[0];
token = clientContext.initSecContext(token, 0, token.length);
clientContext.dispose();
return token;
}
});
return token;
} catch (PrivilegedActionException ex) {
logger.logError(HTTPKerberosHandler.class.getName(), methodName, "PrivilegedActionException: " + ex.getMessage());
} catch (Exception ex) {
logger.logError(HTTPKerberosHandler.class.getName(), methodName, "Exception: " + ex.getMessage());
}
return null;
}
private LoginContext getLoginContext(String contextName) {
LoginContext lc = null;
try {
lc = new LoginContext(contextName);
lc.login();
} catch (LoginException le) {
logger.logError(HTTPKerberosHandler.class.getName(), methodName, "Login exception: [" + le.getMessage() + "]");
le.printStackTrace();
}
return lc;
}
}
Can you please tell me how to use SubethaSmtp library? I just want to retrieve the mails from my Gmail inbox and display them or one of them in console window.
I studied most of the API doc but I'm not being able to put the pieces together to get the things working.
Can you please tell me about a working example?
I wrote this code to build a grails application. You may find some bad code habits but it's okey for a sample application.
Here is the code in src/groovy folder :
class MessageHandlerFactoryImpl implements MessageHandlerFactory {
#Override
MessageHandler create(MessageContext ctx) {
return new MessageHandlerImpl(ctx)
}
}
class MessageHandlerImpl implements MessageHandler {
MessageContext context
MessageHandlerImpl(MessageContext context) {
this.context = context
}
#Override
void from(String from) {
println "FROM: ${from}"
}
#Override
void recipient(String recipient) {
println "RECIPIENT: ${recipient}"
}
#Override
void data(InputStream data) {
println "DATA"
println "-------------------"
BufferedReader reader = new BufferedReader(new InputStreamReader(data))
StringBuilder builder = new StringBuilder()
String line
while ((line = reader.readLine()) != null) {
builder.append(line + "\n")
}
println builder.toString()
}
#Override
void done() {
println "DONE"
}
}
class SimpleMessageListenerImpl implements SimpleMessageListener {
#Override
boolean accept(String from, String recipient) {
println "accept: ${from} \n>> ${recipient}"
return false
}
#Override
void deliver(String from, String recipient, InputStream data) {
try {
println "deliver: ${from} \n>> ${recipient} \n>>> ${data.read()}"
} catch (TooMuchDataException e) {
println "TooMuchDataException: ${e.message}"
} catch (IOException e) {
println "IOException: ${e.message}"
}
}
}
class UsernamePasswordValidatorImpl implements UsernamePasswordValidator {
#Override
void login(String username, String password) {
try {
println "LOGIN:::::::"
} catch(LoginFailedException e) {
println "LoginFailedException: ${e.message}"
}
}
}
And here is my controller code.
class SubethaController {
SMTPServer server
def index() {
MessageHandlerFactoryImpl factory = new MessageHandlerFactoryImpl()
server = new SMTPServer(factory)
server.hostName = "imap.gmail.com"
server.port = 993
server.authenticationHandlerFactory = new EasyAuthenticationHandlerFactory(new UsernamePasswordValidatorImpl())
server.start()
}
def stop() {
server?.stop()
}
Wiser wiser
def wiser() {
server = new SMTPServer(new SimpleMessageListenerAdapter(new SimpleMessageListenerImpl()))
server.start()
wiser = new Wiser()
wiser.setPort(25001)
wiser.start()
for (WiserMessage message : wiser.getMessages())
{
String eSender = message.getEnvelopeSender()
String eReceiver = message.getEnvelopeReceiver()
println ">>>>>>>message.getMimeMessage ${message.getMimeMessage()}"
}
}
def wiserS() {
wiser?.stop()
}
}
Thanks.
Okey... I found the answer... The code is well written and is working fine. I just didn't know how to send messages to listening smtp server on the port. I just used telnet program and sent emails to the smtp server running on localhost. Now I will create DNS mapping to make it work on the Internet.
Thanks Nicolás for showing your interest.
I am trying to run some unix commands from my java code. I am using Google's Expect4J library for now and am open to any well documented libraries out there.
The problem is I am trying to capture output of last run command but am not able to get it. Does anyone know, what I am doing wrong here ?
The problem I am trying to solve here is connect to my jumphost and then SSH to some other servers, based on if I am able to connect, I need to copy or run some scripts on target server.
The code I have written is pasted below. Please help !!!
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import org.apache.oro.text.regex.MalformedPatternException;
import org.junit.internal.matchers.SubstringMatcher;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.bean.Server;
import expect4j.Closure;
import expect4j.Expect4j;
import expect4j.ExpectState;
import expect4j.matches.Match;
import expect4j.matches.RegExpMatch;
public class ExpectTest1 {
public final String RETURN_CHAR = "\r ";
public String expectOut = "";
private StringBuilder sBuilder = new StringBuilder();
/**
* #param args
*/
public static void main(String[] args) {
Expect4j exp;
List<String> cmdsToRun = new ArrayList<String>();
try {
ExpectTest1 test = new ExpectTest1();
exp = test.SSH("jumpbox.xyz.com","user1","passwd", cmdsToRun);
exp.getLastState().toString();
} catch (Exception e) {
e.printStackTrace();
}
}
public Expect4j SSH(String hostname, String username, String password, List<String> cmdsToRun) throws Exception {
return SSH(hostname, username, password, 22, cmdsToRun);
}
public Expect4j SSH(String hostname, String username, String password, int port, List<String> cmdsToRun) throws Exception {
JSch jsch=new JSch();
Session session=jsch.getSession(username, hostname, port);
if( password != null) {
session.setPassword(password);
}
Hashtable config=new Hashtable();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setDaemonThread(true);
session.connect(3 * 1000); // making a connection with timeout.
ChannelShell channel = (ChannelShell) session.openChannel("shell");
channel.setInputStream(System.in);
channel.setOutputStream(System.out);
channel.setPtyType("vt102");
Expect4j expect = new Expect4j(channel.getInputStream(), channel.getOutputStream());
channel.connect(5*1000);
Server hostServer = new Server();
hostServer.setHostName("box1.xyz.com");
hostServer.setUsername("user2");
Server destServer = new Server();
destServer.setHostName("box2.xyz.com");
destServer.setUsername("user3");
boolean isLogged = doSSH(hostServer, expect);
if(isLogged) {
doSSH(destServer, expect);
}
return expect;
}
private boolean doSSH (Server server, Expect4j expect) throws IOException, MalformedPatternException, Exception {
String command = "ssh " + server.getUsername() + "#" + server.getHostName() + RETURN_CHAR;
System.out.println("Logging in to: " + command);
boolean logged;
expect.send(command);
Thread.sleep(4000);
command = "uname -a" + RETURN_CHAR;
System.out.println(command);
expect.send(command);
Thread.sleep(10000);
if(isMatch(expect,server.getHostName().substring(0,server.getHostName().indexOf(".")))) {
System.out.println("Logged in to:" + server.getHostName() + ".....");
return true;
}
if(isMatch(expect, "Last login")) {
System.out.println("Logged in to:" + server.getHostName() + ".....");
return true;
}
if(isMatch(expect, "not known")) {
System.out.println("Node or Service not known...");
return false;
}
System.out.println("Node or Service not known...");
return false;
/*expect.expect(new Match[] {
new RegExpMatch("Name or service not known", new Closure() {
public void run(ExpectState state) throws Exception {
System.out.println("Name or service not known...");
expectOut = state.getBuffer();
}
})
});
expect.expect( new Match[] {
new RegExpMatch("Last login: \\w{3} (.*) from", new Closure() {
public void run(ExpectState state) throws Exception {
System.out.println("Logged In....");
expectOut = state.getBuffer();
}
})
});
if(expectOut != null && expectOut.length()>0 && !expectOut.matches("Name or service not known"))
return true;
return false;*/
}
private boolean isMatch(Expect4j expect, String regEx) throws MalformedPatternException, Exception {
/*expect.expect( new Match[] {
new RegExpMatch(regEx, new Closure() {
public void run(ExpectState state) throws Exception {
System.out.println(state.getBuffer());
System.out.println(state.getMatch());
expectOut = state.getMatch();
//System.out.println(state.getMatch());
}
})
});
if(expectOut != null
&& expectOut.length()>0
&& expectOut.matches(regEx)) {
//System.out.println(regEx);
return true;
}*/
System.out.println("*************");
System.out.println(expect.expect(regEx));
System.out.println("*************");
if(expect.expect(regEx) == 0)
return true;
return false;
}
}
I suspect that your ssh command is trying to prompt for a password or trying to ask you to add the host key to the `known_hosts file. I'm not sure they can be done by Expect4j since ssh connects to the tty directly to ask those questions. But this answer seems to have solved it:
Using expect to pass a password to ssh
Here's a similar question/answers that may help:
How to make a ssh connection to a firewall(router) with java?
When I am automating my ssh connections, I use public/private key encryption instead of passwords to connect to the server and I make sure that the server has been connected from the client from the command line successfully without a password. Make sure that the full host name is used. This will save the host key to the `known_hosts file so it won't be prompted for in the future.
Just an idea, you might consider using a Java library that handles the expect and key management for you. Here is one that I found which seems to do the trick.
http://www.jscape.com/products/components/java/ssh-factory/
See the SshScript or SshSession classes and documentation for details.
This is one of the most common application scenario that can be found all over the net. and I'm not asking any questions about the java codes that I did because I was successful in running it on my laptop where both the client and server part of the .java file resides. Rather I have had problem getting it to work in between two computers. I tried establishing physical connection using cross-over cable to connect two computers, and did a test to see if file transfers successfully and it did, however, keeping one Server part of the .java file in one computer and client part in the other, I tried to run the server first and then the client but it got a "access denied" error.
For reference here's my two .java files:
/* ChatClient.java */
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class ChatClient {
private static int port = 5000; /* port to connect to */
private static String host = "localhost"; /* host to connect to (server's IP)*/
private static BufferedReader stdIn;
private static String nick;
/**
* Read in a nickname from stdin and attempt to authenticate with the
* server by sending a NICK command to #out. If the response from #in
* is not equal to "OK" go bacl and read a nickname again
*/
private static String getNick(BufferedReader in,
PrintWriter out) throws IOException {
System.out.print("Enter your nick: ");
String msg = stdIn.readLine();
out.println("NICK " + msg);
String serverResponse = in.readLine();
if ("SERVER: OK".equals(serverResponse)) return msg;
System.out.println(serverResponse);
return getNick(in, out);
}
public static void main (String[] args) throws IOException {
Socket server = null;
try {
server = new Socket(host, port);
} catch (UnknownHostException e) {
System.err.println(e);
System.exit(1);
}
stdIn = new BufferedReader(new InputStreamReader(System.in));
/* obtain an output stream to the server... */
PrintWriter out = new PrintWriter(server.getOutputStream(), true);
/* ... and an input stream */
BufferedReader in = new BufferedReader(new InputStreamReader(
server.getInputStream()));
nick = getNick(in, out);
/* create a thread to asyncronously read messages from the server */
ServerConn sc = new ServerConn(server);
Thread t = new Thread(sc);
t.start();
String msg;
/* loop reading messages from stdin and sending them to the server */
while ((msg = stdIn.readLine()) != null) {
out.println(msg);
}
}
}
class ServerConn implements Runnable {
private BufferedReader in = null;
public ServerConn(Socket server) throws IOException {
/* obtain an input stream from the server */
in = new BufferedReader(new InputStreamReader(
server.getInputStream()));
}
public void run() {
String msg;
try {
/* loop reading messages from the server and show them
* on stdout */
while ((msg = in.readLine()) != null) {
System.out.println(msg);
}
} catch (IOException e) {
System.err.println(e);
}
}
}
and here's the ChatServer.java:
/* ChatServer.java */
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Hashtable;
public class ChatServer {
private static int port = 5000; /* port to listen on */
public static void main (String[] args) throws IOException
{
ServerSocket server = null;
try {
server = new ServerSocket(port); /* start listening on the port */
} catch (IOException e) {
System.err.println("Could not listen on port: " + port);
System.err.println(e);
System.exit(1);
}
Socket client = null;
while(true) {
try {
client = server.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
System.err.println(e);
System.exit(1);
}
/* start a new thread to handle this client */
Thread t = new Thread(new ClientConn(client));
t.start();
}
}
}
class ChatServerProtocol {
private String nick;
private ClientConn conn;
/* a hash table from user nicks to the corresponding connections */
private static Hashtable<String, ClientConn> nicks =
new Hashtable<String, ClientConn>();
private static final String msg_OK = "OK";
private static final String msg_NICK_IN_USE = "NICK IN USE";
private static final String msg_SPECIFY_NICK = "SPECIFY NICK";
private static final String msg_INVALID = "INVALID COMMAND";
private static final String msg_SEND_FAILED = "FAILED TO SEND";
/**
* Adds a nick to the hash table
* returns false if the nick is already in the table, true otherwise
*/
private static boolean add_nick(String nick, ClientConn c) {
if (nicks.containsKey(nick)) {
return false;
} else {
nicks.put(nick, c);
return true;
}
}
public ChatServerProtocol(ClientConn c) {
nick = null;
conn = c;
}
private void log(String msg) {
System.err.println(msg);
}
public boolean isAuthenticated() {
return ! (nick == null);
}
/**
* Implements the authentication protocol.
* This consists of checking that the message starts with the NICK command
* and that the nick following it is not already in use.
* returns:
* msg_OK if authenticated
* msg_NICK_IN_USE if the specified nick is already in use
* msg_SPECIFY_NICK if the message does not start with the NICK command
*/
private String authenticate(String msg) {
if(msg.startsWith("NICK")) {
String tryNick = msg.substring(5);
if(add_nick(tryNick, this.conn)) {
log("Nick " + tryNick + " joined.");
this.nick = tryNick;
return msg_OK;
} else {
return msg_NICK_IN_USE;
}
} else {
return msg_SPECIFY_NICK;
}
}
/**
* Send a message to another user.
* #recepient contains the recepient's nick
* #msg contains the message to send
* return true if the nick is registered in the hash, false otherwise
*/
private boolean sendMsg(String recipient, String msg) {
if (nicks.containsKey(recipient)) {
ClientConn c = nicks.get(recipient);
c.sendMsg(nick + ": " + msg);
return true;
} else {
return false;
}
}
/**
* Process a message coming from the client
*/
public String process(String msg) {
if (!isAuthenticated())
return authenticate(msg);
String[] msg_parts = msg.split(" ", 3);
String msg_type = msg_parts[0];
if(msg_type.equals("MSG")) {
if(msg_parts.length < 3) return msg_INVALID;
if(sendMsg(msg_parts[1], msg_parts[2])) return msg_OK;
else return msg_SEND_FAILED;
} else {
return msg_INVALID;
}
}
}
class ClientConn implements Runnable {
private Socket client;
private BufferedReader in = null;
private PrintWriter out = null;
ClientConn(Socket client) {
this.client = client;
try {
/* obtain an input stream to this client ... */
in = new BufferedReader(new InputStreamReader(
client.getInputStream()));
/* ... and an output stream to the same client */
out = new PrintWriter(client.getOutputStream(), true);
} catch (IOException e) {
System.err.println(e);
return;
}
}
public void run() {
String msg, response;
ChatServerProtocol protocol = new ChatServerProtocol(this);
try {
/* loop reading lines from the client which are processed
* according to our protocol and the resulting response is
* sent back to the client */
while ((msg = in.readLine()) != null) {
response = protocol.process(msg);
out.println("SERVER: " + response);
}
} catch (IOException e) {
System.err.println(e);
}
}
public void sendMsg(String msg) {
out.println(msg);
}
}
Now, what should I do in order to run this two files from two computers given that I have the physical connection(TCP/IP) setup already??
Thanks in advance... :)
Sounds like it's quite possibly a firewall problem. Have you tried opening a hole in your firewall for port 1001?
Have you also looked at your java.policy and make sure that it is configured to allow local codebase to open sockets?
as mentioned in comment, you should not use port < 1025 for you applications, since they are always used in deamon processes. However you should test your program like this
1) if you get connection refused then you should check the exception properly, whether client program takes time before generating exception ( that mean request is going to server and then it's giving connection refused), in that case you should try java.policy put following in a file named java.policy
grant {
permission java.net.SocketPermission ":1024-65535",
"connect,accept";
permission java.net.SocketPermission ":80", "connect";
permission java.io.FilePermission "", "read,write,delete";
permission java.security.SecurityPermission "";
};
while compiling use this flag -Djava.security.policy=java.policy
more-over you should also try -Djava.rmi.server.hostname=IP, where IP is clien-ip for client.java and server-ip for server.java
2) if you are immediately getting exception at client side then your request is not going outside your pc, so client has some problem.
check the exception properly and post them over here.
3) though i've not got access denied error, but it seems to have port problem that might be solved using policy or port>1024.
post what are you getting now.