Finally I made it. Although it seems not possible by analyzing JSCH user auth methods, somehow the code below work really great.
And it’s much easier than I thought before, no need 3 steps any more, just one java service.
import com.wm.data.*;
import com.wm.util.Values;
import com.wm.app.b2b.server.Service;
import com.wm.app.b2b.server.ServiceException;
import com.wm.app.b2b.server.Resources;
import com.wm.app.b2b.server.Server;
import com.wm.app.b2b.server.sftp.client.*;
import com.jcraft.jsch.*;
import java.util.Properties;
import java.io.FileReader;
import com.wm.util.JournalLogger;
import java.io.*;
import java.lang.reflect.Field;
import pub.CommonUtils;
import com.wm.passman.PasswordManager;
import com.wm.passman.PasswordManagerException;
import com.wm.security.OutboundPasswordStore;
import com.wm.util.security.WmSecureString;
public static final void login(IData pipeline) throws ServiceException {
IDataCursor dataCursor = pipeline.getCursor();
boolean bReuseSession = false;
String sessionKey = null;
try {
String userAlias = CommonUtils.getRequiredStrParam(dataCursor, "userAlias");
String reuseSession = IDataUtil.getString(dataCursor, "reuseSession");
bReuseSession = (reuseSession != null) && (reuseSession.equalsIgnoreCase("true"));
//Return cached sessionKey
if (bReuseSession) {
sessionKey = sftpSessionManager.getSessionForAlias(userAlias);
}
if (sessionKey == null){
//Retrieve user alias info
IData getUserAliasInput = IDataFactory.create();
IDataCursor getUserAliasInputCursor = getUserAliasInput.getCursor();
IDataUtil.put(getUserAliasInputCursor, "alias", userAlias);
getUserAliasInputCursor.destroy();
SFTPUserAlias sftpUserAlias = sftpManager.getUserAlias(getUserAliasInput);
//Retrieve server alias info
IData getServerAliasInput = IDataFactory.create();
IDataCursor getServerAliasInputCursor = getServerAliasInput.getCursor();
IDataUtil.put(getServerAliasInputCursor, "alias", sftpUserAlias.getSftpServerAlias());
getServerAliasInputCursor.destroy();
SFTPServerAlias sftpServerAlias = sftpManager.getServerAliasInfo(getServerAliasInput);
//Configure session
JSch jsch = new JSch();
//jsch.setHostKeyRepository(getHostKeyRepository());
jsch.addIdentity(getPrivateKeyFile(sftpUserAlias.getKeyFileLocation()), retrivePasswordAsString("wm.is.admin.sftpclient.pass.phrase." + userAlias));
Session session = jsch.getSession(sftpUserAlias.getUserName(),
sftpServerAlias.getHostName(), sftpServerAlias.getPort());
session.setPassword(retrivePasswordAsString("wm.is.admin.sftpclient.password." + userAlias));
//Init session config map
java.util.Properties config = new java.util.Properties();
config.put("kex", sftpUserAlias.getPreferredKeyExchangeAlgo());
String compression = "none";
if ("zlib".equals(sftpUserAlias.getCompression())) {
compression = "zlib,none";
}
config.put("compression.s2c", compression);
config.put("compression.c2s", compression);
config.put("compression_level", String.valueOf(sftpUserAlias.getCompressionLevel()));
config.put("MaxAuthTries", String.valueOf(sftpUserAlias.getNoOfRetries()));
//config.put("StrictHostKeyChecking", "yes");
config.put("StrictHostKeyChecking", "no");
config.put("PreferredAuthentications", "publickey,password");
session.setConfig(config);
//Connect to SFTP server
session.connect();
//Cache sessionKey for reuse
sessionKey = sftpSessionManager.addSession(session, sftpUserAlias.getSessionTimeout(), userAlias);
//Return sessionKey
CommonUtils.mergeOutput(dataCursor, "sessionKey", sessionKey);
}
} catch (Exception e) {
throw new ServiceException(e);
}finally{
dataCursor.destroy();
}
}
private static SFTPSessionManager sftpSessionManager = SFTPSessionManager.getInstance();
private static SFTPClientManager sftpManager = SFTPClientManager.getInstance();
private static Resources resources = new Resources(Server.getHomeDir(), true);
private static File identitiesDir = resources.getDir(resources.getSFTPDir(), "identities");
private static String retrivePasswordAsString(String passHandle) throws PasswordManagerException {
String password = null;
if (passHandle != null){
PasswordManager passman = OutboundPasswordStore.getStore();
WmSecureString secureString = passman.retrievePassword(passHandle);
password = secureString.toString();
}
return password;
}
private static String getPrivateKeyFile(String keyFileName){
if (keyFileName == null) {
return keyFileName;
}
return new File(identitiesDir, keyFileName).getAbsolutePath();
}
private static HostKeyRepository getHostKeyRepository() throws Exception{
Field field = sftpManager.getClass().getDeclaredField("sftpSvrAliasManager");
field.setAccessible(true);
return (HostKeyRepository)field.get(sftpManager);
}
Service inputs:
userAlias : String
reuseSession : String (Optional)
Service outpus:
sessionKey : String
Before invoking this service, you have to config server alias and user alias the same as how you use native SFTP, just remember you MUST config user alias as password first, then change to key.
Basically you could replace build-in login service (pub.client.sftp:login) with this one, then you could use build-in SFTP services (like pub.client.sftp:get) with the output sessionKey.
The code is tested on my 9.9, so let me know if you have any issues on 9.8.
#webMethods#Integration-Server-and-ESB#webMethods-General