KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > tunnels > TunnelingService


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

19             
20 package com.sslexplorer.tunnels;
21
22 import java.io.IOException JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Set JavaDoc;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32 import com.maverick.multiplex.Channel;
33 import com.maverick.multiplex.MultiplexedConnection;
34 import com.maverick.multiplex.Request;
35 import com.maverick.multiplex.RequestHandler;
36 import com.maverick.util.ByteArrayReader;
37 import com.maverick.util.ByteArrayWriter;
38 import com.sslexplorer.agent.AbstractResourceService;
39 import com.sslexplorer.agent.AgentService;
40 import com.sslexplorer.agent.AgentTunnel;
41 import com.sslexplorer.agent.DefaultAgentManager;
42 import com.sslexplorer.core.CoreEvent;
43 import com.sslexplorer.core.CoreException;
44 import com.sslexplorer.core.CoreServlet;
45 import com.sslexplorer.core.stringreplacement.VariableReplacement;
46 import com.sslexplorer.policyframework.LaunchSession;
47 import com.sslexplorer.policyframework.LaunchSessionFactory;
48 import com.sslexplorer.policyframework.LaunchSessionManager;
49 import com.sslexplorer.policyframework.NoPermissionException;
50 import com.sslexplorer.policyframework.Policy;
51 import com.sslexplorer.policyframework.PolicyDatabaseFactory;
52 import com.sslexplorer.policyframework.PolicyException;
53 import com.sslexplorer.policyframework.ResourceAccessEvent;
54 import com.sslexplorer.policyframework.ResourceUtil;
55 import com.sslexplorer.security.SessionInfo;
56 import com.sslexplorer.tunnels.agent.LocalForwardingChannel;
57 import com.sslexplorer.tunnels.agent.RemoteTunnel;
58 import com.sslexplorer.tunnels.agent.RemoteTunnelManagerFactory;
59
60 /**
61  * {@link AgentService} implementation for dealing with
62  * the <i>SSL Tunnels</i> resource.
63  *
64  * @author brett
65  */

66 public class TunnelingService extends AbstractResourceService implements RequestHandler {
67
68
69     static Log log = LogFactory.getLog(TunnelingService.class);
70
71     /**
72      * Sent by server to start a list of local tunnels. Payload consists of
73      * tunnel resource details including resource ID.
74      */

75     public static final String JavaDoc START_LOCAL_TUNNEL = "startLocalTunnel@3sp.com"; //$NON-NLS-1$
76

77     /**
78      * Sent by client to request that a tunnel is launched. The server should
79      * then configure a launch session. If the tunnel is local, the server
80      * should reply in the same way of {@link #START_LOCAL_TUNNEL} (in which
81      * case the agent then configures and starts the local tunnel). If the
82      * tunnel is remote, no reply will be sent.
83      */

84     public static final String JavaDoc SETUP_AND_LAUNCH_TUNNEL = "setupAndLaunchTunnel@3sp.com"; //$NON-NLS-1$
85

86     /**
87      * Notification request that a remote tunnel has started.
88      */

89     public static final String JavaDoc START_REMOTE_TUNNEL = "startRemoteTunnel@3sp.com";
90     
91     /**
92      * Notification request that a remote tunnel has stopped.
93      */

94     public static final String JavaDoc STOP_REMOTE_TUNNEL = "stopRemoteTunnel@3sp.com";
95     
96     /**
97      * Sent by server to stop a single local tunnel. Payload consists of
98      * resourceID
99      */

100     public static final String JavaDoc STOP_LOCAL_TUNNEL = "stopLocalTunnel@3sp.com"; //$NON-NLS-1$
101

102     /**
103      * Sent by server to request a list of all active local tunnels. Payload to
104      * be sent back to server consists of all active resource IDs
105      */

106     public static final String JavaDoc ACTIVE_LOCAL_TUNNELS = "activeLocalTunnels@3sp.com"; //$NON-NLS-1$
107

108     // Private instance variables
109
private AgentTunnel agent;
110     
111     /**
112      * Constructor
113      */

114     public TunnelingService() {
115         super(TunnelPlugin.SSL_TUNNEL_RESOURCE_TYPE, new int[] {
116                 TunnelsEventConstants.CREATE_TUNNEL,
117                 TunnelsEventConstants.REMOVE_TUNNEL,
118                 TunnelsEventConstants.UPDATE_TUNNEL });
119     }
120     
121     /**
122      * Stop all forwards giving the resource ID of the <i>SSL-Tunnel</i> that
123      * started them.
124      *
125      * @param launchSession launch session
126      * @throws NoPermissionException if not allowed
127      * @throws CoreException on any other error
128      */

129     public void stopTunnels(LaunchSession launchSession) throws NoPermissionException, CoreException {
130         if (!DefaultAgentManager.getInstance().hasActiveAgent(launchSession.getSession())) {
131             throw new TunnelException(TunnelException.INTERNAL_ERROR, (Throwable JavaDoc)null, "No agent.");
132         }
133
134         Tunnel tunnel = (Tunnel) launchSession.getResource();
135         launchSession.checkAccessRights(null, agent.getSession());
136         MultiplexedConnection agent = DefaultAgentManager.getInstance().getAgentBySession(launchSession.getSession());
137
138         try {
139             if (tunnel.getType() == TransportType.LOCAL_TUNNEL_ID) {
140                 Collection JavaDoc<Tunnel> l = new ArrayList JavaDoc<Tunnel>();
141                 l.add(tunnel);
142                 stopLocalTunnels(agent, l);
143             } else if (tunnel.getType() == TransportType.REMOTE_TUNNEL_ID) {
144                 Collection JavaDoc<Tunnel> l = new ArrayList JavaDoc<Tunnel>();
145                 l.add(tunnel);
146                 stopRemoteTunnels(agent, l);
147             } else {
148                 throw new TunnelException(TunnelException.INTERNAL_ERROR, (Throwable JavaDoc)null, "Unknown tunnel type " + tunnel.getType());
149             }
150
151             CoreServlet.getServlet().fireCoreEvent(
152                             new ResourceAccessEvent(this, TunnelsEventConstants.TUNNEL_CLOSED, launchSession.getResource(),
153                                             launchSession.getPolicy(), launchSession.getSession(), CoreEvent.STATE_SUCCESSFUL));
154
155         } catch (TunnelException te) {
156             CoreServlet.getServlet().fireCoreEvent(
157                             new ResourceAccessEvent(this, TunnelsEventConstants.TUNNEL_CLOSED, launchSession.getResource(),
158                                             launchSession.getPolicy(), launchSession.getSession(), te));
159             throw te;
160         } finally {
161             LaunchSessionFactory.getInstance().removeLaunchSession(launchSession);
162         }
163     }
164
165     /**
166      * Start port forwards for the <i>SSL Tunnel</i> specified by the provided
167      * resource ID.
168      *
169      * @param launchSession launch session
170      * @throws NoPermissionException if not allowed
171      * @throws TunnelException on any other other
172      * @throws PolicyException on any other determininig policy
173      */

174     public void startTunnel(LaunchSession launchSession) throws NoPermissionException, TunnelException, PolicyException {
175
176         if (!DefaultAgentManager.getInstance().hasActiveAgent(launchSession.getSession())) {
177             throw new TunnelException(TunnelException.INTERNAL_ERROR, (Throwable JavaDoc)null, "No agent.");
178         } else {
179             Tunnel tunnel = (Tunnel) launchSession.getResource();
180             launchSession.checkAccessRights(null, agent.getSession());
181             AgentTunnel agent = DefaultAgentManager.getInstance().getAgentBySession(launchSession.getSession());
182
183             try {
184                 if (tunnel.getType() == TransportType.LOCAL_TUNNEL_ID) {
185                     startLocalTunnel(agent, tunnel, launchSession);
186                 } else if (tunnel.getType() == TransportType.REMOTE_TUNNEL_ID) {
187                     startRemoteTunnel(agent, tunnel, launchSession);
188                 } else {
189                     throw new TunnelException(TunnelException.INTERNAL_ERROR, (Throwable JavaDoc)null, "Unknown tunnel type " + tunnel.getType());
190                 }
191
192                 // Fire event
193
CoreServlet.getServlet().fireCoreEvent(
194                                 new ResourceAccessEvent(this, TunnelsEventConstants.TUNNEL_OPENED, launchSession.getResource(),
195                                                 launchSession.getPolicy(), launchSession.getSession(), CoreEvent.STATE_SUCCESSFUL));
196             } catch (TunnelException te) {
197
198                 // Fire event
199
CoreServlet.getServlet().fireCoreEvent(
200                                 new ResourceAccessEvent(this, TunnelsEventConstants.TUNNEL_OPENED, launchSession.getResource(),
201                                                 launchSession.getPolicy(), launchSession.getSession(), te));
202
203                 throw te;
204             }
205         }
206     }
207
208     /**
209      * Get a set of the resource ids of all active tunnels (local and remote).
210      *
211      * @param session
212      * @return resource IDs of active tunnels
213      */

214     public Set JavaDoc<Integer JavaDoc> getActiveTunnels(SessionInfo session) {
215
216         try {
217             MultiplexedConnection tunnel = DefaultAgentManager.getInstance().getAgentBySession(session);
218
219             if (tunnel == null)
220                 return null;
221
222             HashSet JavaDoc<Integer JavaDoc> activeTunnelIds = new HashSet JavaDoc<Integer JavaDoc>();
223
224             // The agent keeps track of 'local' tunnels
225

226             Request request = new Request(ACTIVE_LOCAL_TUNNELS);
227             if (tunnel.sendRequest(request, true) && request.getRequestData()!=null) {
228
229                 ByteArrayReader reader = new ByteArrayReader(request.getRequestData());
230                 int count = (int) reader.readInt();
231                 for (int i = 0; i < count; i++) {
232                     activeTunnelIds.add(new Integer JavaDoc((int) reader.readInt()));
233                 }
234             }
235
236             // The server keeps track of 'remote' tunnels
237
Collection JavaDoc<RemoteTunnel> activeRemoteTunnels = RemoteTunnelManagerFactory.getInstance().getRemoteTunnels(session);
238             if (activeRemoteTunnels != null) {
239                 synchronized (activeRemoteTunnels) {
240                     for (RemoteTunnel r : activeRemoteTunnels) {
241                         activeTunnelIds.add(r.getTunnel().getResourceId());
242                     }
243                 }
244             }
245
246             return activeTunnelIds;
247         } catch (IOException JavaDoc e) {
248             log.error("Failed to get active tunnel list from agent", e);
249             return null;
250         }
251     }
252
253     public void performStartup(AgentTunnel agent) {
254         this.agent = agent;
255         notifyAutoStartTunnels();
256     }
257
258     public Channel createChannel(MultiplexedConnection connection, String JavaDoc type) {
259         if (type.equals(LocalForwardingChannel.CHANNEL_TYPE)) {
260             return new LocalForwardingChannel();
261         } else
262             return null;
263     }
264
265     public void initializeTunnel(AgentTunnel tunnel) {
266         tunnel.registerRequestHandler(SETUP_AND_LAUNCH_TUNNEL, this);
267     }
268
269     public boolean processRequest(Request request, MultiplexedConnection connection) {
270         AgentTunnel agent = (AgentTunnel) connection;
271         if (request.getRequestName().equals(SETUP_AND_LAUNCH_TUNNEL) && request.getRequestData()!=null) {
272             try {
273                 ByteArrayReader reader = new ByteArrayReader(request.getRequestData());
274                 int id = (int)reader.readInt();
275                 Tunnel resource = (Tunnel)TunnelPlugin.SSL_TUNNEL_RESOURCE_TYPE.getResourceById(id);
276                 if (resource == null) {
277                     throw new Exception JavaDoc("No resource with ID " + id);
278                 }
279                 Policy policy = LaunchSessionManager.getLaunchRequestPolicy(null, agent.getSession(), resource);
280                 if (resource.sessionPasswordRequired(agent.getSession())) {
281                     // TODO: prompt user for credentials through agent!
282
return true;
283                 } else {
284                     LaunchSession launchSession = LaunchSessionFactory.getInstance().createLaunchSession(agent.getSession(),
285                         resource,
286                         policy);
287                     launchSession.checkAccessRights(null, agent.getSession());
288                     if (resource.getType() == TransportType.LOCAL_TUNNEL_ID) {
289                         try {
290                             Request req = buildLocalTunnel(resource, launchSession);
291                             request.setRequestData(req.getRequestData());
292                             return true;
293                         } catch (IOException JavaDoc ioe) {
294                             throw new TunnelException(TunnelException.INTERNAL_ERROR, ioe);
295                         }
296                     } else if (resource.getType() == TransportType.REMOTE_TUNNEL_ID) {
297                         startRemoteTunnel(agent, resource, launchSession);
298                         request.setRequestData(null);
299                         return true;
300                     } else {
301                         throw new TunnelException(TunnelException.INTERNAL_ERROR, (Throwable JavaDoc)null, "Unknown tunnel type " + resource.getType());
302                     }
303                 }
304             } catch (Exception JavaDoc e) {
305                 log.error("Failed to start tunnel.", e);
306                 return false;
307             }
308         }
309         return false;
310     }
311
312     public void postReply(MultiplexedConnection connection) {
313     }
314
315     void startRemoteTunnel(AgentTunnel agent, Tunnel tunnel , LaunchSession launchSession) throws TunnelException {
316         RemoteTunnel remoteTunnel = RemoteTunnelManagerFactory.getInstance().createRemoteTunnel(tunnel, agent, launchSession);
317         remoteTunnel.start();
318     }
319     
320     void startLocalTunnel(AgentTunnel agent, Tunnel tunnel, LaunchSession launchSession) throws TunnelException {
321         try {
322             Request req = buildLocalTunnel(tunnel, launchSession);
323             /* Only require replies if not running on the protocol thread. This allows autostart
324              * tunnels to work without blocking
325              */

326             if (!agent.sendRequest(req, Thread.currentThread() != agent.getThread())) {
327                 throw new TunnelException(TunnelException.AGENT_REFUSED_LOCAL_TUNNEL, (Throwable JavaDoc)null);
328             }
329         } catch (IOException JavaDoc ioe) {
330             throw new TunnelException(TunnelException.INTERNAL_ERROR, ioe);
331         }
332     }
333
334     @SuppressWarnings JavaDoc("unchecked")
335     void notifyAutoStartTunnels() {
336         try {
337             List JavaDoc<Tunnel> tunnels = ResourceUtil.getGrantedResource(agent.getSession(), TunnelPlugin.SSL_TUNNEL_RESOURCE_TYPE);
338             for (Tunnel tunnel : tunnels) {
339                 if(tunnel.isAutoStart()) {
340                     LaunchSession launchSession = LaunchSessionFactory.getInstance().createLaunchSession(
341                         agent.getSession(), tunnel, PolicyDatabaseFactory.getInstance().getGrantingPolicyForUser(
342                             agent.getSession().getUser(), tunnel));
343                     startTunnel(launchSession);
344                 }
345             }
346         } catch (Exception JavaDoc e) {
347             log.error("Failed to start auto-start tunnels", e);
348         }
349
350     }
351
352     Request buildLocalTunnel(Tunnel tunnel, LaunchSession launchSession) throws IOException JavaDoc {
353         // Process destination host and port for replacement variables
354
VariableReplacement r = new VariableReplacement();
355         r.setLaunchSession(launchSession);
356         String JavaDoc destHost = r.replace(tunnel.getDestination().getHost());
357         
358         ByteArrayWriter msg = new ByteArrayWriter();
359         msg.writeString(launchSession == null ? "" : launchSession.getId());
360         msg.writeInt(tunnel.getResourceId());
361         msg.writeString(tunnel.getResourceName());
362         msg.writeInt(tunnel.getType());
363         msg.writeString(tunnel.getTransport());
364         msg.writeString(tunnel.getSourceInterface());
365         msg.writeInt(tunnel.getSourcePort());
366         msg.writeInt(tunnel.getDestination().getPort());
367         msg.writeString(destHost);
368         Request req = new Request(START_LOCAL_TUNNEL, msg.toByteArray());
369         return req;
370
371     }
372
373     void stopLocalTunnels(MultiplexedConnection agent, Collection JavaDoc<Tunnel> tunnels) throws CoreException {
374
375         CoreException e = null;
376
377         for (Tunnel tunnel : tunnels) {
378             try {
379                 ByteArrayWriter msg = new ByteArrayWriter();
380                 msg.writeInt(tunnel.getResourceId());
381                 if (!agent.sendRequest(new Request(STOP_LOCAL_TUNNEL, msg.toByteArray()), false) && e == null) {
382                     e = new TunnelException(TunnelException.AGENT_REFUSED_LOCAL_TUNNEL_STOP, (Throwable JavaDoc)null);
383                 }
384             } catch (IOException JavaDoc ex) {
385                 throw new TunnelException(TunnelException.INTERNAL_ERROR, ex);
386             }
387         }
388         if (e != null) {
389             throw e;
390         }
391     }
392
393     void stopRemoteTunnels(MultiplexedConnection agent, Collection JavaDoc<Tunnel> tunnels) throws CoreException {
394
395         CoreException e = null;
396
397         for (Tunnel tunnel : tunnels) {
398             try {
399                 RemoteTunnel rt = RemoteTunnelManagerFactory.getInstance().getRemoteTunnel(tunnel.getResourceId());
400                 if (rt != null) {
401                     rt.stopListener();
402                 } else {
403                     throw new Exception JavaDoc("No active with ID for " + tunnel.getResourceId());
404                 }
405             } catch (Exception JavaDoc ex) {
406                 throw new TunnelException(TunnelException.INTERNAL_ERROR, ex);
407             }
408         }
409         if (e != null) {
410             throw e;
411         }
412     }
413 }
414
Popular Tags