001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015:
016: package org.griphyn.cPlanner.engine;
017:
018: import org.griphyn.cPlanner.classes.AuthenticateRequest;
019:
020: import org.griphyn.cPlanner.common.LogManager;
021: import org.griphyn.cPlanner.common.PegasusProperties;
022:
023: import org.griphyn.cPlanner.poolinfo.PoolInfoProvider;
024:
025: import org.globus.gram.Gram;
026: import org.globus.gram.GramException;
027:
028: import org.ietf.jgss.GSSCredential;
029: import org.ietf.jgss.GSSException;
030:
031: import java.io.BufferedReader;
032: import java.io.BufferedWriter;
033: import java.io.IOException;
034: import java.io.InputStreamReader;
035: import java.io.InterruptedIOException;
036: import java.io.OutputStreamWriter;
037:
038: import java.net.ConnectException;
039: import java.net.InetSocketAddress;
040: import java.net.Socket;
041:
042: import java.util.StringTokenizer;
043:
044: /**
045: * It takes in a authenticate request and authenticates against the resource
046: * on the basis of the type of the resource against which authentication is
047: * required.
048: *
049: * @author Karan Vahi
050: * @version $Revision: 50 $
051: */
052:
053: public class Authenticate {
054:
055: /**
056: * The standard port at which Grid FTP runs.
057: */
058: public static final int GRID_FTP_STANDARD_PORT = 2811;
059:
060: /**
061: * The timeout in seconds. All sockets opened timeout after this period.
062: */
063: public static final int TIMEOUT_VALUE = 120;
064:
065: /**
066: * The timeout value that is to be used in milliseconds
067: */
068: private int mTimeout;
069:
070: /**
071: * The object containing the authenticate request.
072: */
073: private AuthenticateRequest mAuthRequest;
074:
075: /**
076: * The handle to the Pool Info Provider.
077: */
078: private PoolInfoProvider mPoolHandle;
079:
080: /**
081: * The handle to the LogManager object.
082: */
083: private LogManager mLogger;
084:
085: /**
086: * The handle to the PegasusProperties object.
087: */
088: private PegasusProperties mProps;
089:
090: /**
091: * The credential to be used while authentication to jobmanager.
092: */
093: private GSSCredential mCredential;
094:
095: /**
096: * The overloaded constructor.
097: *
098: * @param properties the <code>PegasusProperties</code> to be used.
099: */
100: public Authenticate(PegasusProperties properties,
101: PoolInfoProvider poolHandle) {
102: mPoolHandle = poolHandle;
103: mLogger = LogManager.getInstance();
104: mProps = properties;
105: mTimeout = (mProps.getGridFTPTimeout() == null) ? this .TIMEOUT_VALUE
106: : Integer.parseInt(mProps.getGridFTPTimeout());
107: mTimeout *= 1000;
108: }
109:
110: /**
111: * Sets the credential that has to be used for authentication.
112: *
113: * @param credential the credential to be set.
114: */
115: public void setCredential(GSSCredential credential) {
116: mCredential = credential;
117: }
118:
119: /**
120: * Authenticates against a resource referred to in the authenticate request
121: * object.
122: */
123: public boolean authenticate(AuthenticateRequest ar) {
124: mAuthRequest = ar;
125: char type = ar.getResourceType();
126: boolean alive = false;
127:
128: //check if the request is invalid
129: if (ar.requestInvalid()) {
130: throw new RuntimeException(
131: "Invalid authentication request " + ar);
132: }
133:
134: if (type == AuthenticateRequest.GRIDFTP_RESOURCE) {
135: //check if the grid ftp server is alive.
136: HostPort hp = getHostPort(ar.getResourceContact());
137: alive = gridFTPAlive(hp.getHost(), hp.getPort());
138:
139: }
140: if (type == AuthenticateRequest.JOBMANAGER_RESOURCE) {
141: alive = authenticateJobManager(ar.getResourceContact());
142: }
143:
144: return alive;
145: }
146:
147: /**
148: * It tries to remove a resource from the soft state of the pool. This is
149: * possible only if the underlying pool interface implementation is soft
150: * state.
151: *
152: * @param ar the AuthenticateRequest containing the resource info
153: *
154: * @return boolean true removal was successful.
155: * false unable to remove.
156: */
157: public boolean removeResource(AuthenticateRequest ar) {
158: char type = ar.getResourceType();
159:
160: if (type == AuthenticateRequest.GRIDFTP_RESOURCE) {
161: return mPoolHandle.removeGridFtp(ar.getPool(), ar
162: .getResourceContact());
163: }
164: if (type == AuthenticateRequest.JOBMANAGER_RESOURCE) {
165: return mPoolHandle.removeJobManager(ar.getPool(), null, ar
166: .getResourceContact());
167: }
168:
169: return false;
170: }
171:
172: /**
173: * It authenticates against the jobmanager specifyied.
174: *
175: * @param contact the jobmanager contact.
176: */
177: public boolean authenticateJobManager(String contact) {
178: boolean val = true;
179: try {
180: mLogger.log("Authenticating " + contact,
181: LogManager.DEBUG_MESSAGE_LEVEL);
182:
183: if (mCredential == null) {
184: //try authenticating the default credential
185: Gram.ping(contact);
186: } else
187: Gram.ping(mCredential, contact);
188: } catch (GramException gex) {
189: mLogger.log("Unable authenticate against jobmanager "
190: + contact + " because " + gex.getMessage(),
191: LogManager.ERROR_MESSAGE_LEVEL);
192: val = false;
193: } catch (GSSException gss) {
194: String message = (gss.getMajor() == GSSException.CREDENTIALS_EXPIRED) ? "Your credentials have expired. You need to do a grid-proxy-init."
195: : "GssException caught " + gss.getMajorString()
196: + gss.getMinorString();
197: mLogger.log(message, LogManager.ERROR_MESSAGE_LEVEL);
198: val = false;
199: } catch (Exception e) {
200: //an unknown exception occured. print a message and return false
201: mLogger.log("Unknown Exception occured " + e.getMessage(),
202: LogManager.ERROR_MESSAGE_LEVEL);
203: val = false;
204: } finally {
205: mLogger.logCompletion("Authenticating ",
206: LogManager.DEBUG_MESSAGE_LEVEL);
207: }
208: return val;
209: }
210:
211: /**
212: * It checks with a grid ftp server running at a particular host
213: * and port, to see if it is up or not. This is done by opening a
214: * socket to the specified host at the specified port. If the socket
215: * timesout (which could be due to excessive load on the server or
216: * server being hung) false is returned.
217: *
218: * @param host the host at which the gridftp server is running .
219: * @param port the port at which server is running on the host.
220: *
221: * @return true the gridftp server is alive and kicking.
222: * false - the submit host is not connected to the network.
223: * - the server is not running.
224: * - we were able to connect but timeout.
225: * - version is not compatible.
226: *
227: */
228: public boolean gridFTPAlive(String host, int port) {
229: Socket s = new Socket();
230: String hp = combine(host, port);
231: boolean alive = false;
232:
233: mLogger.log("Checking status of " + hp,
234: LogManager.DEBUG_MESSAGE_LEVEL);
235: InetSocketAddress addrs = new InetSocketAddress(host, port);
236: if (addrs.isUnresolved()) {
237: //either the host on which Pegasus is running is not connected
238: //to the network, or the hostname is invalid. Either way we return
239: //false;
240: mLogger.log("Unresolved address to " + hp,
241: LogManager.DEBUG_MESSAGE_LEVEL);
242: return false;
243: }
244:
245: try {
246: s.connect(addrs, mTimeout);
247: //set the timeout for the input streams
248: // gotten from this socket
249: s.setSoTimeout(mTimeout);
250: String response;
251: char type = 'c';
252: BufferedReader rd = new BufferedReader(
253: new InputStreamReader(s.getInputStream()));
254:
255: BufferedWriter out = new BufferedWriter(
256: new OutputStreamWriter(s.getOutputStream()));
257:
258: while ((response = rd.readLine()) != null) {
259: /*mLogger.logMessage("Response from server " + hp + " " +
260: response,
261: 1);*/
262:
263: alive = parseGridFTPResponse(response, type);
264:
265: if (type == 'c' && alive) {
266: //send the quit command to the server
267: out.write("quit\r\n");
268: //do a half close. We just need to wait for the response
269: //from server now
270: s.shutdownOutput();
271: type = 'q';
272: } else {
273: //invalid response or the server is stuck.
274: //break out of the infinite waiting.
275: break;
276: }
277:
278: }
279: } catch (java.net.SocketTimeoutException se) {
280: //means we experienced a timeout on read
281: mLogger.log("Timeout experienced while reading from ip"
282: + " stream of " + hp,
283: LogManager.ERROR_MESSAGE_LEVEL);
284: alive = false;
285: } catch (InterruptedIOException e) {
286: //timeout was reached.
287: mLogger.log("Timeout experienced while contacting " + hp,
288: LogManager.ERROR_MESSAGE_LEVEL);
289: alive = false;
290: } catch (ConnectException ce) {
291: //probably no process running at the port
292: mLogger.log("GridFtp server on " + host
293: + " not running on port " + port + " .Exception "
294: + ce.getMessage(), LogManager.ERROR_MESSAGE_LEVEL);
295: alive = false;
296: } catch (IOException ie) {
297: mLogger.log("Unable to contact " + hp + " due to "
298: + ie.getMessage(), LogManager.ERROR_MESSAGE_LEVEL);
299: alive = false;
300: } catch (Exception e) {
301: //an unknown exception occured. print a message and return false
302: mLogger.log("Unknown Exception occured " + e.getMessage(),
303: LogManager.ERROR_MESSAGE_LEVEL);
304: alive = false;
305: } finally {
306: try {
307: s.close();
308: } catch (IOException e) {
309: mLogger.log("Unable to close socket to " + hp
310: + " because" + e.getMessage(),
311: LogManager.ERROR_MESSAGE_LEVEL);
312: alive = false;
313: }
314: }
315:
316: return alive;
317: }
318:
319: /**
320: * The parses the grid ftp server response and returns if the response
321: * was valid or not.
322: *
323: * @param response the response got from the grid ftp server.
324: * @param type c response when first connected to server.
325: * q response when sent the quit command.
326: *
327: * @return boolean true if the response was valid
328: * false invalid response.
329: */
330: private boolean parseGridFTPResponse(String response, char type) {
331: StringTokenizer st = new StringTokenizer(response);
332: boolean valid = false;
333:
334: switch (type) {
335: case 'c':
336:
337: //valid response should be of type 220 blah
338: while (st.hasMoreTokens()) {
339: if (st.nextToken().equals("220")) {
340: valid = true;
341: }
342: break;
343: }
344: break;
345:
346: case 'q':
347:
348: //valid response would be type 221 blah
349: while (st.hasMoreTokens()) {
350: if (st.nextToken().equals("221")) {
351: valid = true;
352: }
353: break;
354: }
355: break;
356:
357: default:
358: valid = false;
359:
360: }
361:
362: if (valid == false)
363: mLogger.log(response, LogManager.ERROR_MESSAGE_LEVEL);
364: return valid;
365:
366: }
367:
368: /**
369: * A small helper method that returns the standard host and port
370: * combination to be used for logging purposes.
371: *
372: * @param host the host.
373: * @param port the port.
374: *
375: * @return combined string.
376: */
377: private String combine(String host, int port) {
378: String st = host + ":" + port;
379: return st;
380: }
381:
382: /**
383: * Determines the hostname from the urlPrefix string in the pool file.
384: *
385: * @param urlPrefix the protocol, hostname and port combination.
386: *
387: * @return the host name.
388: */
389: private HostPort getHostPort(String urlPrefix) {
390: StringTokenizer st = new StringTokenizer(urlPrefix);
391: String hostPort;
392: String hostName = new String();
393: String token = new String();
394: int count = 0;
395: int port = this .GRID_FTP_STANDARD_PORT;
396: HostPort hp = null;
397:
398: while (st.hasMoreTokens()) {
399: token = st.nextToken("/");
400: count++;
401: if (count == 2) {
402: hostPort = token.trim();
403: StringTokenizer st1 = new StringTokenizer(hostPort, ":");
404: hostName = st1.nextToken();
405: if (st1.hasMoreTokens()) {
406: //port is specified
407: try {
408: port = Integer.parseInt(st1.nextToken());
409: } catch (NumberFormatException e) {
410: port = this .GRID_FTP_STANDARD_PORT;
411: }
412: }
413: //System.out.println("Host->" + hostName + " Port->" + port);
414: hp = new HostPort(hostName, port);
415: //System.out.println(hp);
416: return hp;
417: }
418:
419: }
420: return null;
421:
422: }
423:
424: /**
425: * A convenience inner class that stores the host and the port associated
426: * with a server.
427: */
428: class HostPort {
429:
430: /**
431: * The host at which the server is running.
432: */
433: private String mHost;
434:
435: /**
436: * The port at which the server is running.
437: */
438: private int mPort;
439:
440: /**
441: * The overloaded constructor
442: */
443: public HostPort(String host, int port) {
444: mHost = host;
445: mPort = port;
446: }
447:
448: /**
449: * Returns the host associated with this object.
450: *
451: * @return String
452: */
453: public String getHost() {
454: return mHost;
455: }
456:
457: /**
458: * Returns the port associated with this object.
459: *
460: * @return int
461: */
462: public int getPort() {
463: return mPort;
464: }
465:
466: /**
467: * Returns the string version of this object.
468: */
469: public String toString() {
470: StringBuffer sb = new StringBuffer();
471: sb.append("host name ").append(mHost).append(" port ")
472: .append(mPort);
473:
474: return sb.toString();
475: }
476: }
477:
478: public static void main(String[] args) {
479: Authenticate a = new Authenticate(PegasusProperties
480: .getInstance(), null);
481: String contact = "dc-user2.isi.edu/jobmanager-lsf";
482: String contact1 = "dc-n1.isi.edu";
483: System.out.println("Authenticating " + contact1);
484: //a.authenticateJobManager(contact);
485: a.gridFTPAlive("dc-n1.isi.edu", a.GRID_FTP_STANDARD_PORT);
486: }
487: }
|