/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package de.cismet.cids.client.tools;
import Sirius.navigator.connection.SessionManager;
import Sirius.navigator.ui.ComponentRegistry;
import Sirius.server.newuser.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.BasicScheme;
import org.apache.commons.httpclient.auth.CredentialsProvider;
import org.apache.commons.io.IOUtils;
import org.openide.util.Exceptions;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import de.cismet.cids.server.actions.HttpTunnelAction;
import de.cismet.cids.server.actions.ServerActionParameter;
import de.cismet.commons.security.AccessHandler;
import de.cismet.commons.security.Tunnel;
import de.cismet.commons.security.exceptions.CannotReadFromURLException;
import de.cismet.netutil.tunnel.TunnelTargetGroup;
import de.cismet.security.GUICredentialsProvider;
import de.cismet.tools.gui.log4jquickconfig.Log4JQuickConfig;
/**
* DOCUMENT ME!
*
* @author thorsten
* @version $Revision$, $Date$
*/
public class CallServerTunnel implements Tunnel {
//~ Static fields/initializers ---------------------------------------------
private static final String tunnelActionName = "httpTunnelAction";
private static ObjectMapper mapper = new ObjectMapper();
private static final transient org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(
CallServerTunnel.class);
//~ Instance fields --------------------------------------------------------
private String callserverName = "not set";
private volatile User user = null;
private HashMap<String, String[]> tunnelTargetGroupRegExs = new HashMap<String, String[]>();
private volatile ArrayList<String> userKeyList = null;
private final transient Map<String, TunnelGUICredentialsProvider> credentialsForURLS =
new HashMap<String, TunnelGUICredentialsProvider>();
//~ Constructors -----------------------------------------------------------
/**
* Creates a new CallServerTunnel object.
*
* @param callserverName DOCUMENT ME!
*/
public CallServerTunnel(final String callserverName) {
try {
this.callserverName = callserverName;
final TunnelTargetGroup[] tGroups = mapper.readValue(CallServerTunnel.class.getResourceAsStream(
"/de/cismet/cids/client/tools/tunnelTargets.json"),
TunnelTargetGroup[].class);
for (final TunnelTargetGroup ttg : tGroups) {
tunnelTargetGroupRegExs.put(ttg.getTargetGroupkey(), ttg.getTargetExpressions());
}
} catch (Exception ex) {
LOG.warn(
"Problem during Parsing of the TunnelTargetGroups. Will alwas return false in isResponsible(). No tunnel functionality available.",
ex);
}
}
//~ Methods ----------------------------------------------------------------
@Override
public boolean isResponsible(final ACCESS_METHODS method, final String url) {
switch (method) {
case POST_REQUEST_NO_TUNNEL:
case GET_REQUEST_NO_TUNNEL: {
return false;
}
case HEAD_REQUEST:
case GET_REQUEST:
case POST_REQUEST: {
try {
for (final String key : tunnelTargetGroupRegExs.keySet()) {
if (getUserKeyList().contains(key.trim())) {
for (final String regex : tunnelTargetGroupRegExs.get(key)) {
if (url.matches(regex)) {
if (LOG.isDebugEnabled()) {
LOG.debug(new StringBuilder("Tunnel hit: ").append(key).append('(').append(
regex).append(") for:\n").append(url).append('\n').append(method));
}
return true;
}
}
}
}
} catch (Exception e) {
LOG.warn(
"Exception in isResponsible of CallserverTunnel. Will return false. No tunnel functionality available.",
e);
}
}
}
if (LOG.isDebugEnabled()) {
LOG.debug(new StringBuilder("Tunnel miss for:\n").append(url).append('\n').append(method));
}
return false;
}
@Override
public InputStream doRequest(final URL url,
final Reader requestParameter,
final ACCESS_METHODS method,
final HashMap<String, String> options) throws Exception {
final ServerActionParameter urlSAP = new ServerActionParameter<URL>(HttpTunnelAction.PARAMETER_TYPE.URL
.toString(),
url);
final Object nullBody = null;
final ServerActionParameter methodSAP = new ServerActionParameter<ACCESS_METHODS>(
HttpTunnelAction.PARAMETER_TYPE.METHOD.toString(),
method);
final ServerActionParameter optionsSAP = new ServerActionParameter<HashMap<String, String>>(
HttpTunnelAction.PARAMETER_TYPE.OPTIONS.toString(),
options);
final StringBuilder parameter = new StringBuilder();
final BufferedReader reader = new BufferedReader(requestParameter);
String currentLine;
while ((currentLine = reader.readLine()) != null) {
parameter.append(currentLine);
}
final ServerActionParameter parameterSAP = new ServerActionParameter<String>(
HttpTunnelAction.PARAMETER_TYPE.REQUEST.toString(),
parameter.toString());
byte[] result = null;
Object res = null;
try {
TunnelGUICredentialsProvider cp = credentialsForURLS.get(url.toString());
if (cp == null) {
res = SessionManager.getProxy()
.executeTask(
tunnelActionName,
callserverName,
nullBody,
urlSAP,
parameterSAP,
methodSAP,
optionsSAP);
} else {
res = executeWithCreds(
tunnelActionName,
callserverName,
nullBody,
urlSAP,
parameterSAP,
methodSAP,
optionsSAP,
cp.getCredentials());
}
if ((res instanceof CannotReadFromURLException)) {
if (cp == null) {
cp = createSynchronizedCP(url);
}
UsernamePasswordCredentials creds = null;
do {
cp.getCredentials(new BasicScheme(), null, -1, false);
creds = cp.getCredentials();
} while ((creds == null) && !cp.isAuthenticationCanceled());
res = executeWithCreds(
tunnelActionName,
callserverName,
nullBody,
urlSAP,
parameterSAP,
methodSAP,
optionsSAP,
creds);
}
result = (byte[])res;
} catch (final Exception ex) {
}
if (result != null) {
return new ByteArrayInputStream(result);
} else {
return null;
}
}
@Override
public InputStream doRequest(final URL url,
final InputStream requestParameter,
final HashMap<String, String> options) throws Exception {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public ACCESS_HANDLER_TYPES getHandlerType() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public boolean isAccessMethodSupported(final ACCESS_METHODS method) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private ArrayList<String> getUserKeyList() {
try {
if (userKeyList == null) {
synchronized (this) {
if (userKeyList == null) {
user = SessionManager.getSession().getUser();
final String configAttr = SessionManager.getProxy().getConfigAttr(user, "tunnel.targetgroups");
if (configAttr != null) {
final String[] keys = configAttr.split(",");
userKeyList = new ArrayList<String>(keys.length);
for (final String s : keys) {
userKeyList.add(s.trim());
}
} else {
userKeyList = new ArrayList<String>(1);
}
}
}
}
return userKeyList;
} catch (Exception e) {
LOG.warn("Exception during retrieval of tunnelUserKeyList. Will be empty.", e);
return null;
}
}
/**
* DOCUMENT ME!
*
* @param args DOCUMENT ME!
*/
public static void main(final String[] args) {
try {
DevelopmentTools.initSessionManagerFromRestfulConnectionOnLocalhost(
"WUNDA_BLAU",
null,
"admin",
"leo");
final CallServerTunnel cst = new CallServerTunnel("kjdfhg");
System.out.println(cst.isResponsible(
ACCESS_METHODS.GET_REQUEST,
"http://chaos.wuppertal-intra.de/weird/path/to/nonsense"));
System.out.println(cst.isResponsible(ACCESS_METHODS.GET_REQUEST, "http://www.google.de"));
System.out.println(cst.isResponsible(ACCESS_METHODS.GET_REQUEST, "http://s10221./path/to/X"));
final InputStream is = cst.doRequest(new URL("http://cismet.de/"),
new StringReader(""),
ACCESS_METHODS.GET_REQUEST,
new LinkedHashMap());
if (is != null) {
System.out.println(IOUtils.toString(is));
}
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
} finally {
System.exit(0);
}
}
/**
* DOCUMENT ME!
*
* @param url DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
protected CredentialsProvider getCredentialProvider(final URL url) {
TunnelGUICredentialsProvider cp = credentialsForURLS.get(url.toString());
if (cp == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("no Credential Provider available for url: " + url);
}
cp = createSynchronizedCP(url);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Credential Provider available for url: " + url);
}
}
return cp;
}
/**
* DOCUMENT ME!
*
* @param url DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public synchronized TunnelGUICredentialsProvider createSynchronizedCP(final URL url) {
if (LOG.isDebugEnabled()) {
LOG.debug("Credential Provider should be created synchronously"); // NOI18N
}
TunnelGUICredentialsProvider cp = credentialsForURLS.get(url.toString());
if (cp == null) {
cp = new TunnelGUICredentialsProvider(url);
if (LOG.isDebugEnabled()) {
LOG.debug("A new Credential Provider instance was created for: " + url.toString()); // NOI18N
}
credentialsForURLS.put(url.toString(), cp);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Credential Provider was already available: " + url.toString()); // NOI18N
}
}
return cp;
}
/**
* DOCUMENT ME!
*/
public void resetCredentials() {
for (final GUICredentialsProvider prov : credentialsForURLS.values()) {
prov.setUsernamePassword(null);
}
credentialsForURLS.clear();
}
/**
* DOCUMENT ME!
*
* @param taskname DOCUMENT ME!
* @param taskdomain DOCUMENT ME!
* @param body DOCUMENT ME!
* @param urlSAP DOCUMENT ME!
* @param parameterSAP DOCUMENT ME!
* @param methodSAP DOCUMENT ME!
* @param optionsSAP DOCUMENT ME!
* @param creds DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws Exception DOCUMENT ME!
*/
private Object executeWithCreds(final String taskname,
final String taskdomain,
final Object body,
final ServerActionParameter urlSAP,
final ServerActionParameter parameterSAP,
final ServerActionParameter methodSAP,
final ServerActionParameter optionsSAP,
final UsernamePasswordCredentials creds) throws Exception {
final ServerActionParameter credentialsSAP;
if (creds != null) {
final HashMap<String, String> credOptions = new HashMap<String, String>();
credOptions.put(HttpTunnelAction.CREDENTIALS_USERNAME_KEY, creds.getUserName());
credOptions.put(HttpTunnelAction.CREDENTIALS_PASSWORD_KEY, creds.getPassword());
credentialsSAP = new ServerActionParameter<HashMap<String, String>>(
HttpTunnelAction.PARAMETER_TYPE.CREDENTIALS.toString(),
credOptions);
} else {
credentialsSAP = null;
}
return SessionManager.getProxy()
.executeTask(
taskname,
taskdomain,
body,
urlSAP,
parameterSAP,
methodSAP,
optionsSAP,
credentialsSAP);
}
//~ Inner Classes ----------------------------------------------------------
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
class TunnelGUICredentialsProvider extends GUICredentialsProvider {
//~ Instance fields ----------------------------------------------------
private URL url;
//~ Constructors -------------------------------------------------------
/**
* Creates a new MyGCR object.
*
* @param url DOCUMENT ME!
*/
public TunnelGUICredentialsProvider(final URL url) {
super(url, ComponentRegistry.getRegistry().getMainWindow());
this.url = url;
}
//~ Methods ------------------------------------------------------------
@Override
public boolean testConnection(final UsernamePasswordCredentials creds) {
try {
final ServerActionParameter urlSAP = new ServerActionParameter<URL>(HttpTunnelAction.PARAMETER_TYPE.URL
.toString(),
url);
final ServerActionParameter parameterSAP = new ServerActionParameter<String>(
HttpTunnelAction.PARAMETER_TYPE.REQUEST.toString(),
"");
final ServerActionParameter methodSAP = new ServerActionParameter<ACCESS_METHODS>(
HttpTunnelAction.PARAMETER_TYPE.METHOD.toString(),
AccessHandler.ACCESS_METHODS.GET_REQUEST);
final ServerActionParameter optionsSAP = new ServerActionParameter<HashMap<String, String>>(
HttpTunnelAction.PARAMETER_TYPE.OPTIONS.toString(),
null);
final Object res = executeWithCreds(
tunnelActionName,
callserverName,
null,
urlSAP,
parameterSAP,
methodSAP,
optionsSAP,
creds);
if (res instanceof CannotReadFromURLException) {
return false;
}
final byte[] instanceTest = (byte[])res;
return true;
} catch (final Exception ex) {
return false;
}
}
}
}