View Javadoc

1   /*
2    * Copyright (c) 2005 The University of Reading
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    * 1. Redistributions of source code must retain the above copyright
9    *    notice, this list of conditions and the following disclaimer.
10   * 2. Redistributions in binary form must reproduce the above copyright
11   *    notice, this list of conditions and the following disclaimer in the
12   *    documentation and/or other materials provided with the distribution.
13   * 3. Neither the name of the University of Reading, nor the names of the
14   *    authors or contributors may be used to endorse or promote products
15   *    derived from this software without specific prior written permission.
16   * 
17   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27   */
28  
29  package uk.ac.rdg.resc.jstyx.server;
30  
31  import java.net.InetSocketAddress;
32  import java.io.IOException;
33  
34  import org.apache.mina.common.TransportType;
35  import org.apache.mina.registry.Service;
36  import org.apache.mina.registry.ServiceRegistry;
37  import org.apache.mina.registry.SimpleServiceRegistry;
38  import org.apache.mina.io.IoAcceptor;
39  import org.apache.mina.io.filter.SSLFilter;
40  import org.apache.mina.protocol.ProtocolProvider;
41  
42  import org.apache.log4j.Logger;
43  
44  import uk.ac.rdg.resc.jstyx.StyxException;
45  import uk.ac.rdg.resc.jstyx.StyxUtils;
46  import uk.ac.rdg.resc.jstyx.ssl.JonSSLContextFactory;
47  
48  /***
49   * A Styx server.
50   *
51   * @author Jon Blower
52   * $Revision: 604 $
53   * $Date: 2006-03-21 14:58:42 +0000 (Tue, 21 Mar 2006) $
54   * $Log$
55   * Revision 1.10  2006/03/21 14:58:42  jonblower
56   * Implemented clear-text password-based authentication and did some simple tests
57   *
58   * Revision 1.9  2006/03/21 09:06:15  jonblower
59   * Still implementing authentication
60   *
61   * Revision 1.8  2006/03/20 17:51:50  jonblower
62   * Adding authentication to base JStyx system
63   *
64   * Revision 1.7  2005/08/30 16:28:23  jonblower
65   * Subsumed TestServer program into StyxServer class
66   *
67   * Revision 1.6  2005/05/05 16:57:38  jonblower
68   * Updated MINA library to revision 168337 and changed code accordingly
69   *
70   * Revision 1.5  2005/03/24 07:57:41  jonblower
71   * Improved code for reading SSL info from SGSconfig file and included parameter information for the Grid Services in the config file
72   *
73   * Revision 1.4  2005/03/14 16:40:02  jonblower
74   * Modifications for using SSL
75   *
76   * Revision 1.3  2005/03/11 14:02:16  jonblower
77   * Merged MINA-Test_20059309 into main line of development
78   *
79   * Revision 1.2.2.6  2005/03/11 08:30:30  jonblower
80   * Moved to log4j logging system (from apache commons logging)
81   *
82   * Revision 1.2.2.5  2005/03/10 18:32:18  jonblower
83   * Minor change to layout
84   *
85   * Revision 1.2.2.3 and 1.2.2.4  2005/03/10 14:38:10  jonblower
86   * Modified for MINA framework
87   *
88   * Revision 1.2.2.1  2005/03/09 19:44:18  jonblower
89   * Changes concerned with migration to MINA
90   *
91   * Revision 1.1.1.1  2005/02/16 18:58:33  jonblower
92   * Initial import
93   *
94   */
95  public class StyxServer
96  {
97      
98      private static final Logger log = Logger.getLogger(StyxServer.class);
99      
100     private ProtocolProvider provider;
101     private int port;
102     
103     private StyxSecurityContext securityContext; // If this is null, access to the
104                                                  // server is anonymous and unsecured
105     
106     /***
107      * Creates a Styx server that exposes the given directory under the given
108      * port.  No security information is used: server will allow anonymous access
109      * and no traffic will be encrypted.
110      * @throws IllegalArgumentException if the port number is invalid or the
111      * root is null.
112      * @throws StyxSecurityException if there was an error setting up the
113      * security context (should never happen since this will be an unsecured
114      * server).
115      */
116     public StyxServer(int port, StyxDirectory root) throws StyxSecurityException
117     {
118         this(port, root, null);
119     }
120     
121     /***
122      * Creates a Styx server that listens on the given port and uses the
123      * given protocol provider (This is used by the Styx interloper class)
124      * Connections are anonymous and unsecured.
125      * @throws IllegalArgumentException if the port number is invalid or the
126      * provider is null.
127      */
128     public StyxServer(int port, ProtocolProvider provider)
129     {
130         if (provider == null)
131         {
132             throw new IllegalArgumentException("ProtocolProvider cannot be null");
133         }
134         setPortNumber(port);
135         this.provider = provider;
136         this.securityContext = new StyxSecurityContext();
137     }
138     
139     /***
140      * Creates a Styx server.
141      * @param port The port number on which the server will listen
142      * @param root The root of the Styx filesystem to serve
143      * @param securityConfigFile The file containing security information
144      * (user details, SSL setup etc).  If this is null, the server will allow
145      * anonymous access and no traffic will be encrypted.
146      * @throws IllegalArgumentException if the port number is invalid or 
147      * root == null.
148      * @throws StyxSecurityException if there was an error reading security
149      * configuration from <code>securityConfigFile</code>.
150      */
151     public StyxServer(int port, StyxDirectory root, String securityConfigFile)
152         throws StyxSecurityException
153     {
154         if (root == null)
155         {
156             throw new IllegalArgumentException("root cannot be null");
157         }
158         // Set the port number, checking that it is valid
159         setPortNumber(port);
160         if (securityConfigFile == null)
161         {
162             this.securityContext = new StyxSecurityContext();
163         }
164         else
165         {
166             this.securityContext = new StyxSecurityContext(securityConfigFile);
167         }
168         this.provider = new StyxServerProtocolProvider(root, this.securityContext);
169     }
170     
171     /***
172      * Checks to see if the given port number is valid, throwing an 
173      * IllegalArgumentException if it isn't.  If it is valid, sets it
174      */
175     private void setPortNumber(int port)
176     {
177         // TODO: should we disallow other port numbers?
178         if (port < 0 || port > StyxUtils.MAXUSHORT)
179         {
180             throw new IllegalArgumentException("Invalid port number");
181         }
182         this.port = port;
183     }
184     
185     /***
186      * Starts the Styx server.
187      * @throws IOException if an error occurred
188      */
189     public void start() throws IOException
190     {
191         ServiceRegistry registry = new SimpleServiceRegistry();
192 
193         //addLogger( registry );
194 
195         // Add SSL filter if SSL is enabled.
196         if( this.securityContext.getSSLContext() != null )
197         {
198             SSLFilter sslFilter = new SSLFilter( this.securityContext.getSSLContext() );
199             IoAcceptor acceptor = registry.getIoAcceptor( TransportType.SOCKET );
200             acceptor.getFilterChain().addLast( "sslFilter", sslFilter );
201         }
202 
203         // Bind
204         Service service = new Service( "styx", TransportType.SOCKET, this.port );
205         registry.bind( service, this.provider );
206         
207         log.info( "Listening on port " + this.port + ", SSL " +
208             (this.securityContext.getSSLContext() == null ? "disabled" : "enabled"));
209     }
210     
211     /***
212      * Simple test Styx server that exposes the contents of a local directory.
213      * The TestServer takes two arguments, both optional.  The first is the
214      * port number under which the server will listen (defaults to 8080 if
215      * not set). The second is the directory in the host filesystem which
216      * will be at the root of the Styx server. This defaults to the user's
217      * home directory (i.e. the output of System.getProperty("user.home"))
218      * if not set.
219      */
220     public static void main(String[] args) throws Throwable
221     {
222         // Set the default port and root directory of the server
223         int port = 8080;
224         // Default root directory is the user's home directory
225         String home = System.getProperty("user.home");
226         String securityFile = null;
227         
228         if (args.length > 0)
229         {
230             try
231             {
232                 port = Integer.parseInt(args[0]);
233             }
234             catch (NumberFormatException nfe)
235             {
236                 System.err.println(args[0] + " is not a valid port number");
237                 return;
238             }
239         }
240         if (args.length > 1)
241         {
242             home = args[1];
243         }
244         if (args.length > 2)
245         {
246             securityFile = args[2];
247         }
248         if (args.length > 3)
249         {
250             System.err.println("Usage: TestServer [port] [root directory] [security file]");
251             return;
252         }
253         
254         // Set up the file tree
255         System.out.println("Building directory tree (this can take some time)");
256         StyxDirectory root = new DirectoryOnDisk(home);
257         
258         // Add some files with different users and groups
259         root.addChild(new StyxDirectory("jdbandusers", "jdb", StyxUtils.DEFAULT_GROUP, 0755));
260         root.addChild(new StyxDirectory("jdbonly", "jdb", StyxUtils.DEFAULT_GROUP, 0700));
261         root.addChild(new StyxDirectory("adminsonly", "jim", "admins", 0750));
262         
263         // Set up the server and start it with the given configuration file
264         StyxServer server = new StyxServer(port, root, securityFile);
265         server.start();
266     }
267 }