Package com.adito.tunnels

Source Code of com.adito.tunnels.TunnelingService

        /*
*  Adito
*
*  Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either version 2 of
*  the License, or (at your option) any later version.
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public
*  License along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
     
package com.adito.tunnels;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.maverick.multiplex.Channel;
import com.maverick.multiplex.MultiplexedConnection;
import com.maverick.multiplex.Request;
import com.maverick.multiplex.RequestHandler;
import com.maverick.util.ByteArrayReader;
import com.maverick.util.ByteArrayWriter;
import com.adito.agent.AbstractResourceService;
import com.adito.agent.AgentService;
import com.adito.agent.AgentTunnel;
import com.adito.agent.DefaultAgentManager;
import com.adito.core.BundleActionMessage;
import com.adito.core.CoreEvent;
import com.adito.core.CoreException;
import com.adito.core.CoreServlet;
import com.adito.core.GlobalWarning;
import com.adito.core.GlobalWarningManager;
import com.adito.core.stringreplacement.VariableReplacement;
import com.adito.policyframework.LaunchSession;
import com.adito.policyframework.LaunchSessionFactory;
import com.adito.policyframework.LaunchSessionManager;
import com.adito.policyframework.NoPermissionException;
import com.adito.policyframework.Policy;
import com.adito.policyframework.PolicyDatabaseFactory;
import com.adito.policyframework.PolicyException;
import com.adito.policyframework.ResourceAccessEvent;
import com.adito.policyframework.ResourceUtil;
import com.adito.security.SessionInfo;
import com.adito.tunnels.agent.LocalForwardingChannel;
import com.adito.tunnels.agent.RemoteTunnel;
import com.adito.tunnels.agent.RemoteTunnelManagerFactory;

/**
* {@link AgentService} implementation for dealing with
* the <i>SSL Tunnels</i> resource.
*
* @author brett
*/
public class TunnelingService extends AbstractResourceService implements RequestHandler {


  static Log log = LogFactory.getLog(TunnelingService.class);

  /**
   * Sent by server to start a list of local tunnels. Payload consists of
   * tunnel resource details including resource ID.
   */
  public static final String START_LOCAL_TUNNEL = "startLocalTunnel"; //$NON-NLS-1$
 
  /**
   * Sent by client to request that a tunnel is launched. The server should
   * then configure a launch session. If the tunnel is local, the server
   * should reply in the same way of {@link #START_LOCAL_TUNNEL} (in which
   * case the agent then configures and starts the local tunnel). If the
   * tunnel is remote, no reply will be sent.
   */
  public static final String SETUP_AND_LAUNCH_TUNNEL = "setupAndLaunchTunnel"; //$NON-NLS-1$

  /**
   * Notification request that a remote tunnel has started.
   */
  public static final String START_REMOTE_TUNNEL = "startRemoteTunnel";
 
  /**
   * Notification request that a remote tunnel has stopped.
   */
  public static final String STOP_REMOTE_TUNNEL = "stopRemoteTunnel";
 
  /**
   * Sent by server to stop a single local tunnel. Payload consists of
   * resourceID
   */
  public static final String STOP_LOCAL_TUNNEL = "stopLocalTunnel"; //$NON-NLS-1$

  /**
   * Sent by server to request a list of all active local tunnels. Payload to
   * be sent back to server consists of all active resource IDs
   */
  public static final String ACTIVE_LOCAL_TUNNELS = "activeLocalTunnels"; //$NON-NLS-1$
 
  //  Private instance variables
  private AgentTunnel agent;
 
    /**
     * Constructor
     */
    public TunnelingService() {
    super(TunnelPlugin.SSL_TUNNEL_RESOURCE_TYPE, new int[] {
        TunnelsEventConstants.CREATE_TUNNEL,
        TunnelsEventConstants.REMOVE_TUNNEL,
        TunnelsEventConstants.UPDATE_TUNNEL });
  }
 
    /**
     * Stop all forwards giving the resource ID of the <i>SSL-Tunnel</i> that
     * started them.
     *
     * @param launchSession launch session
     * @throws NoPermissionException if not allowed
     * @throws CoreException on any other error
     */
    public void stopTunnels(LaunchSession launchSession) throws NoPermissionException, CoreException {
        if (!DefaultAgentManager.getInstance().hasActiveAgent(launchSession.getSession())) {
            throw new TunnelException(TunnelException.INTERNAL_ERROR, (Throwable)null, "No agent.");
        }

        Tunnel tunnel = (Tunnel) launchSession.getResource();
        launchSession.checkAccessRights(null, agent.getSession());
        MultiplexedConnection agent = DefaultAgentManager.getInstance().getAgentBySession(launchSession.getSession());

        try {
            if (tunnel.getType() == TransportType.LOCAL_TUNNEL_ID) {
                Collection<Tunnel> l = new ArrayList<Tunnel>();
                l.add(tunnel);
                stopLocalTunnels(agent, l);
            } else if (tunnel.getType() == TransportType.REMOTE_TUNNEL_ID) {
                Collection<Tunnel> l = new ArrayList<Tunnel>();
                l.add(tunnel);
                stopRemoteTunnels(agent, l);
            } else {
                throw new TunnelException(TunnelException.INTERNAL_ERROR, (Throwable)null, "Unknown tunnel type " + tunnel.getType());
            }

            CoreServlet.getServlet().fireCoreEvent(
                            new ResourceAccessEvent(this, TunnelsEventConstants.TUNNEL_CLOSED, launchSession.getResource(),
                                            launchSession.getPolicy(), launchSession.getSession(), CoreEvent.STATE_SUCCESSFUL));

        } catch (TunnelException te) {
            CoreServlet.getServlet().fireCoreEvent(
                            new ResourceAccessEvent(this, TunnelsEventConstants.TUNNEL_CLOSED, launchSession.getResource(),
                                            launchSession.getPolicy(), launchSession.getSession(), te));
            throw te;
        } finally {
      LaunchSessionFactory.getInstance().removeLaunchSession(launchSession);
        }
    }

    /**
     * Start port forwards for the <i>SSL Tunnel</i> specified by the provided
     * resource ID.
     *
     * @param launchSession launch session
     * @throws NoPermissionException if not allowed
     * @throws TunnelException on any other other
     * @throws PolicyException on any other determininig policy
     */
    public void startTunnel(LaunchSession launchSession) throws NoPermissionException, TunnelException, PolicyException {

        if (!DefaultAgentManager.getInstance().hasActiveAgent(launchSession.getSession())) {
            throw new TunnelException(TunnelException.INTERNAL_ERROR, (Throwable)null, "No agent.");
        } else {
            Tunnel tunnel = (Tunnel) launchSession.getResource();
            launchSession.checkAccessRights(null, agent.getSession());
            AgentTunnel agent = DefaultAgentManager.getInstance().getAgentBySession(launchSession.getSession());

            try {
                if (tunnel.getType() == TransportType.LOCAL_TUNNEL_ID) {
                    startLocalTunnel(agent, tunnel, launchSession);
                } else if (tunnel.getType() == TransportType.REMOTE_TUNNEL_ID) {
                    startRemoteTunnel(agent, tunnel, launchSession);
                } else {
                    throw new TunnelException(TunnelException.INTERNAL_ERROR, (Throwable)null, "Unknown tunnel type " + tunnel.getType());
                }

                // Fire event
                CoreServlet.getServlet().fireCoreEvent(
                                new ResourceAccessEvent(this, TunnelsEventConstants.TUNNEL_OPENED, launchSession.getResource(),
                                                launchSession.getPolicy(), launchSession.getSession(), CoreEvent.STATE_SUCCESSFUL));
            } catch (TunnelException te) {

                // Fire event
                CoreServlet.getServlet().fireCoreEvent(
                                new ResourceAccessEvent(this, TunnelsEventConstants.TUNNEL_OPENED, launchSession.getResource(),
                                                launchSession.getPolicy(), launchSession.getSession(), te));

                throw te;
            }
        }
    }

    /**
     * Get a set of the resource ids of all active tunnels (local and remote).
     *
     * @param session
     * @return resource IDs of active tunnels
     */
    public Set<Integer> getActiveTunnels(SessionInfo session) {

        try {
            MultiplexedConnection tunnel = DefaultAgentManager.getInstance().getAgentBySession(session);

            if (tunnel == null)
                return null;

            HashSet<Integer> activeTunnelIds = new HashSet<Integer>();

            // The agent keeps track of 'local' tunnels

            Request request = new Request(ACTIVE_LOCAL_TUNNELS);
            if (tunnel.sendRequest(request, true) && request.getRequestData()!=null) {

                ByteArrayReader reader = new ByteArrayReader(request.getRequestData());
                int count = (int) reader.readInt();
                for (int i = 0; i < count; i++) {
                    activeTunnelIds.add(new Integer((int) reader.readInt()));
                }
            }

            // The server keeps track of 'remote' tunnels
            Collection<RemoteTunnel> activeRemoteTunnels = RemoteTunnelManagerFactory.getInstance().getRemoteTunnels(session);
            if (activeRemoteTunnels != null) {
                synchronized (activeRemoteTunnels) {
                    for (RemoteTunnel r : activeRemoteTunnels) {
                        activeTunnelIds.add(r.getTunnel().getResourceId());
                    }
                }
            }

            return activeTunnelIds;
        } catch (IOException e) {
            log.error("Failed to get active tunnel list from agent", e);
            return null;
        }
    }

    public void performStartup(AgentTunnel agent) {
      this.agent = agent;
        notifyAutoStartTunnels();
    }

    public Channel createChannel(MultiplexedConnection connection, String type) {
        if (type.equals(LocalForwardingChannel.CHANNEL_TYPE)) {
            return new LocalForwardingChannel();
        } else
            return null;
    }

  public void initializeTunnel(AgentTunnel tunnel) {
    tunnel.registerRequestHandler(SETUP_AND_LAUNCH_TUNNEL, this);
  }

  public boolean processRequest(Request request, MultiplexedConnection connection) {
    AgentTunnel agent = (AgentTunnel) connection;
    if (request.getRequestName().equals(SETUP_AND_LAUNCH_TUNNEL) && request.getRequestData()!=null) {
      try {
        ByteArrayReader reader = new ByteArrayReader(request.getRequestData());
        int id = (int)reader.readInt();
        Tunnel resource = (Tunnel)TunnelPlugin.SSL_TUNNEL_RESOURCE_TYPE.getResourceById(id);
        if (resource == null) {
          throw new Exception("No resource with ID " + id);
        }
        Policy policy = LaunchSessionManager.getLaunchRequestPolicy(null, agent.getSession(), resource);
        if (resource.sessionPasswordRequired(agent.getSession())) {
          // TODO: prompt user for credentials through agent!
          return true;
        } else {
          LaunchSession launchSession = LaunchSessionFactory.getInstance().createLaunchSession(agent.getSession(),
            resource,
            policy);
          launchSession.checkAccessRights(null, agent.getSession());
                  if (resource.getType() == TransportType.LOCAL_TUNNEL_ID) {
                      try {
                          Request req = buildLocalTunnel(resource, launchSession);
                          request.setRequestData(req.getRequestData());
                        return true;
                      } catch (IOException ioe) {
                          throw new TunnelException(TunnelException.INTERNAL_ERROR, ioe);
                      }
                  } else if (resource.getType() == TransportType.REMOTE_TUNNEL_ID) {
                      startRemoteTunnel(agent, resource, launchSession);
                      request.setRequestData(null);
                      return true;
                  } else {
                      throw new TunnelException(TunnelException.INTERNAL_ERROR, (Throwable)null, "Unknown tunnel type " + resource.getType());
                  }
        }
      } catch (Exception e) {
        log.error("Failed to start tunnel.", e);
        return false;
      }
    }
    return false;
  }

  public void postReply(MultiplexedConnection connection) {   
  }

    void startRemoteTunnel(AgentTunnel agent, Tunnel tunnel , LaunchSession launchSession) throws TunnelException {
        RemoteTunnel remoteTunnel = RemoteTunnelManagerFactory.getInstance().createRemoteTunnel(tunnel, agent, launchSession);
        remoteTunnel.start();
    }
   
    void startLocalTunnel(AgentTunnel agent, Tunnel tunnel, LaunchSession launchSession) throws TunnelException {
        try {
            Request req = buildLocalTunnel(tunnel, launchSession);
            /* Only require replies if not running on the protocol thread. This allows autostart
             * tunnels to work without blocking
             */           
            if (!agent.sendRequest(req, Thread.currentThread() != agent.getThread())) {
                throw new TunnelException(TunnelException.AGENT_REFUSED_LOCAL_TUNNEL, (Throwable)null);
            }
        } catch (IOException ioe) {
            throw new TunnelException(TunnelException.INTERNAL_ERROR, ioe);
        }
    }

    @SuppressWarnings("unchecked")
    void notifyAutoStartTunnels() {
        try {
            SessionInfo session = agent.getSession();
            List<Tunnel> tunnels = ResourceUtil.getGrantedResource(session, TunnelPlugin.SSL_TUNNEL_RESOURCE_TYPE);
           
            List<BundleActionMessage> tunnelFailures = new ArrayList<BundleActionMessage>();
            for (Tunnel tunnel : tunnels) {
                if (tunnel.isAutoStart()) {
                    try {
                        Policy policy = PolicyDatabaseFactory.getInstance().getGrantingPolicyForUser(session.getUser(), tunnel);
                        LaunchSession launchSession = LaunchSessionFactory.getInstance().createLaunchSession(session, tunnel, policy);
                        startTunnel(launchSession);
                    } catch (TunnelException tne) {
                        log.error("failed to start tunnel: '" + tunnel + "'", tne);
                        tunnelFailures.add(tne.getBundleActionMessage());
                    }
                }
            }
           
            if (!tunnelFailures.isEmpty()) {
                tunnelFailures.add(0, new BundleActionMessage("tunnels", "error.tunnels.autostart", tunnelFailures.size()));
                for (BundleActionMessage actionMessage : tunnelFailures) {
                    GlobalWarning globalWarning = new GlobalWarning(session.getHttpSession(), actionMessage);
                    GlobalWarningManager.getInstance().addToSession(globalWarning);
                }
            }
        } catch (Exception e) {
            log.error("Failed to start auto-start tunnels", e);
        }
    }
   
    Request buildLocalTunnel(Tunnel tunnel, LaunchSession launchSession) throws IOException {
      // Process destination host and port for replacement variables
      VariableReplacement r = new VariableReplacement();
      r.setLaunchSession(launchSession);
      String destHost = r.replace(tunnel.getDestination().getHost());
     
        ByteArrayWriter msg = new ByteArrayWriter();
        msg.writeString(launchSession == null ? "" : launchSession.getId());
        msg.writeInt(tunnel.getResourceId());
        msg.writeString(tunnel.getResourceName());
        msg.writeInt(tunnel.getType());
        msg.writeString(tunnel.getTransport());
        msg.writeString(tunnel.getSourceInterface());       
        msg.writeInt(tunnel.getSourcePort());
        msg.writeInt(tunnel.getDestination().getPort());
        msg.writeString(destHost);
        Request req = new Request(START_LOCAL_TUNNEL, msg.toByteArray());
        return req;

    }

    void stopLocalTunnels(MultiplexedConnection agent, Collection<Tunnel> tunnels) throws CoreException {

        CoreException e = null;

        for (Tunnel tunnel : tunnels) {
            try {
                ByteArrayWriter msg = new ByteArrayWriter();
                msg.writeInt(tunnel.getResourceId());
                if (!agent.sendRequest(new Request(STOP_LOCAL_TUNNEL, msg.toByteArray()), false) && e == null) {
                    e = new TunnelException(TunnelException.AGENT_REFUSED_LOCAL_TUNNEL_STOP, (Throwable)null);
                }
            } catch (IOException ex) {
                throw new TunnelException(TunnelException.INTERNAL_ERROR, ex);
            }
        }
        if (e != null) {
            throw e;
        }
    }

    void stopRemoteTunnels(MultiplexedConnection agent, Collection<Tunnel> tunnels) throws CoreException {

        CoreException e = null;

        for (Tunnel tunnel : tunnels) {
            try {
                RemoteTunnel rt = RemoteTunnelManagerFactory.getInstance().getRemoteTunnel(tunnel.getResourceId());
                if (rt != null) {
                    rt.stopListener();
                } else {
                    throw new Exception("No active with ID for " + tunnel.getResourceId());
                }
            } catch (Exception ex) {
                throw new TunnelException(TunnelException.INTERNAL_ERROR, ex);
            }
        }
        if (e != null) {
            throw e;
        }
    }
}
TOP

Related Classes of com.adito.tunnels.TunnelingService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.