KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > ch > ethz > ssh2 > auth > AuthenticationManager


1
2 package ch.ethz.ssh2.auth;
3
4 import java.io.IOException JavaDoc;
5 import java.security.SecureRandom JavaDoc;
6 import java.util.Vector JavaDoc;
7
8 import ch.ethz.ssh2.InteractiveCallback;
9 import ch.ethz.ssh2.crypto.PEMDecoder;
10 import ch.ethz.ssh2.packets.PacketServiceAccept;
11 import ch.ethz.ssh2.packets.PacketServiceRequest;
12 import ch.ethz.ssh2.packets.PacketUserauthBanner;
13 import ch.ethz.ssh2.packets.PacketUserauthFailure;
14 import ch.ethz.ssh2.packets.PacketUserauthInfoRequest;
15 import ch.ethz.ssh2.packets.PacketUserauthInfoResponse;
16 import ch.ethz.ssh2.packets.PacketUserauthRequestInteractive;
17 import ch.ethz.ssh2.packets.PacketUserauthRequestNone;
18 import ch.ethz.ssh2.packets.PacketUserauthRequestPassword;
19 import ch.ethz.ssh2.packets.PacketUserauthRequestPublicKey;
20 import ch.ethz.ssh2.packets.Packets;
21 import ch.ethz.ssh2.packets.TypesWriter;
22 import ch.ethz.ssh2.signature.DSAPrivateKey;
23 import ch.ethz.ssh2.signature.DSASHA1Verify;
24 import ch.ethz.ssh2.signature.DSASignature;
25 import ch.ethz.ssh2.signature.RSAPrivateKey;
26 import ch.ethz.ssh2.signature.RSASHA1Verify;
27 import ch.ethz.ssh2.signature.RSASignature;
28 import ch.ethz.ssh2.transport.MessageHandler;
29 import ch.ethz.ssh2.transport.TransportManager;
30
31 /**
32  * AuthenticationManager.
33  *
34  * @author Christian Plattner, plattner@inf.ethz.ch
35  * @version $Id: AuthenticationManager.java,v 1.15 2006/12/05 14:18:02 cplattne Exp $
36  */

37 public class AuthenticationManager implements MessageHandler
38 {
39     TransportManager tm;
40
41     Vector JavaDoc packets = new Vector JavaDoc();
42     boolean connectionClosed = false;
43
44     String JavaDoc banner;
45
46     String JavaDoc[] remainingMethods = new String JavaDoc[0];
47     boolean isPartialSuccess = false;
48
49     boolean authenticated = false;
50     boolean initDone = false;
51
52     public AuthenticationManager(TransportManager tm)
53     {
54         this.tm = tm;
55     }
56
57     boolean methodPossible(String JavaDoc methName)
58     {
59         if (remainingMethods == null)
60             return false;
61
62         for (int i = 0; i < remainingMethods.length; i++)
63         {
64             if (remainingMethods[i].compareTo(methName) == 0)
65                 return true;
66         }
67         return false;
68     }
69
70     byte[] deQueue() throws IOException JavaDoc
71     {
72         synchronized (packets)
73         {
74             while (packets.size() == 0)
75             {
76                 if (connectionClosed)
77                     throw (IOException JavaDoc) new IOException JavaDoc("The connection is closed.").initCause(tm
78                             .getReasonClosedCause());
79
80                 try
81                 {
82                     packets.wait();
83                 }
84                 catch (InterruptedException JavaDoc ign)
85                 {
86                 }
87             }
88             /* This sequence works with J2ME */
89             byte[] res = (byte[]) packets.firstElement();
90             packets.removeElementAt(0);
91             return res;
92         }
93     }
94
95     byte[] getNextMessage() throws IOException JavaDoc
96     {
97         while (true)
98         {
99             byte[] msg = deQueue();
100
101             if (msg[0] != Packets.SSH_MSG_USERAUTH_BANNER)
102                 return msg;
103
104             PacketUserauthBanner sb = new PacketUserauthBanner(msg, 0, msg.length);
105
106             banner = sb.getBanner();
107         }
108     }
109
110     public String JavaDoc[] getRemainingMethods(String JavaDoc user) throws IOException JavaDoc
111     {
112         initialize(user);
113         return remainingMethods;
114     }
115
116     public boolean getPartialSuccess()
117     {
118         return isPartialSuccess;
119     }
120
121     private boolean initialize(String JavaDoc user) throws IOException JavaDoc
122     {
123         if (initDone == false)
124         {
125             tm.registerMessageHandler(this, 0, 255);
126
127             PacketServiceRequest sr = new PacketServiceRequest("ssh-userauth");
128             tm.sendMessage(sr.getPayload());
129
130             PacketUserauthRequestNone urn = new PacketUserauthRequestNone("ssh-connection", user);
131             tm.sendMessage(urn.getPayload());
132
133             byte[] msg = getNextMessage();
134             new PacketServiceAccept(msg, 0, msg.length);
135             msg = getNextMessage();
136
137             initDone = true;
138
139             if (msg[0] == Packets.SSH_MSG_USERAUTH_SUCCESS)
140             {
141                 authenticated = true;
142                 tm.removeMessageHandler(this, 0, 255);
143                 return true;
144             }
145
146             if (msg[0] == Packets.SSH_MSG_USERAUTH_FAILURE)
147             {
148                 PacketUserauthFailure puf = new PacketUserauthFailure(msg, 0, msg.length);
149
150                 remainingMethods = puf.getAuthThatCanContinue();
151                 isPartialSuccess = puf.isPartialSuccess();
152                 return false;
153             }
154
155             throw new IOException JavaDoc("Unexpected SSH message (type " + msg[0] + ")");
156         }
157         return authenticated;
158     }
159
160     public boolean authenticatePublicKey(String JavaDoc user, char[] PEMPrivateKey, String JavaDoc password, SecureRandom JavaDoc rnd)
161             throws IOException JavaDoc
162     {
163         try
164         {
165             initialize(user);
166
167             if (methodPossible("publickey") == false)
168                 throw new IOException JavaDoc("Authentication method publickey not supported by the server at this stage.");
169
170             Object JavaDoc key = PEMDecoder.decode(PEMPrivateKey, password);
171
172             if (key instanceof DSAPrivateKey)
173             {
174                 DSAPrivateKey pk = (DSAPrivateKey) key;
175
176                 byte[] pk_enc = DSASHA1Verify.encodeSSHDSAPublicKey(pk.getPublicKey());
177
178                 TypesWriter tw = new TypesWriter();
179
180                 byte[] H = tm.getSessionIdentifier();
181
182                 tw.writeString(H, 0, H.length);
183                 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
184                 tw.writeString(user);
185                 tw.writeString("ssh-connection");
186                 tw.writeString("publickey");
187                 tw.writeBoolean(true);
188                 tw.writeString("ssh-dss");
189                 tw.writeString(pk_enc, 0, pk_enc.length);
190
191                 byte[] msg = tw.getBytes();
192
193                 DSASignature ds = DSASHA1Verify.generateSignature(msg, pk, rnd);
194
195                 byte[] ds_enc = DSASHA1Verify.encodeSSHDSASignature(ds);
196
197                 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user,
198                         "ssh-dss", pk_enc, ds_enc);
199                 tm.sendMessage(ua.getPayload());
200             }
201             else if (key instanceof RSAPrivateKey)
202             {
203                 RSAPrivateKey pk = (RSAPrivateKey) key;
204
205                 byte[] pk_enc = RSASHA1Verify.encodeSSHRSAPublicKey(pk.getPublicKey());
206
207                 TypesWriter tw = new TypesWriter();
208                 {
209                     byte[] H = tm.getSessionIdentifier();
210
211                     tw.writeString(H, 0, H.length);
212                     tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
213                     tw.writeString(user);
214                     tw.writeString("ssh-connection");
215                     tw.writeString("publickey");
216                     tw.writeBoolean(true);
217                     tw.writeString("ssh-rsa");
218                     tw.writeString(pk_enc, 0, pk_enc.length);
219                 }
220
221                 byte[] msg = tw.getBytes();
222
223                 RSASignature ds = RSASHA1Verify.generateSignature(msg, pk);
224
225                 byte[] rsa_sig_enc = RSASHA1Verify.encodeSSHRSASignature(ds);
226
227                 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user,
228                         "ssh-rsa", pk_enc, rsa_sig_enc);
229                 tm.sendMessage(ua.getPayload());
230             }
231             else
232             {
233                 throw new IOException JavaDoc("Unknown private key type returned by the PEM decoder.");
234             }
235
236             byte[] ar = getNextMessage();
237
238             if (ar[0] == Packets.SSH_MSG_USERAUTH_SUCCESS)
239             {
240                 authenticated = true;
241                 tm.removeMessageHandler(this, 0, 255);
242                 return true;
243             }
244
245             if (ar[0] == Packets.SSH_MSG_USERAUTH_FAILURE)
246             {
247                 PacketUserauthFailure puf = new PacketUserauthFailure(ar, 0, ar.length);
248
249                 remainingMethods = puf.getAuthThatCanContinue();
250                 isPartialSuccess = puf.isPartialSuccess();
251
252                 return false;
253             }
254
255             throw new IOException JavaDoc("Unexpected SSH message (type " + ar[0] + ")");
256
257         }
258         catch (IOException JavaDoc e)
259         {
260             tm.close(e, false);
261             throw (IOException JavaDoc) new IOException JavaDoc("Publickey authentication failed.").initCause(e);
262         }
263     }
264
265     public boolean authenticateNone(String JavaDoc user) throws IOException JavaDoc
266     {
267         try
268         {
269             initialize(user);
270             return authenticated;
271         }
272         catch (IOException JavaDoc e)
273         {
274             tm.close(e, false);
275             throw (IOException JavaDoc) new IOException JavaDoc("None authentication failed.").initCause(e);
276         }
277     }
278
279     public boolean authenticatePassword(String JavaDoc user, String JavaDoc pass) throws IOException JavaDoc
280     {
281         try
282         {
283             initialize(user);
284
285             if (methodPossible("password") == false)
286                 throw new IOException JavaDoc("Authentication method password not supported by the server at this stage.");
287
288             PacketUserauthRequestPassword ua = new PacketUserauthRequestPassword("ssh-connection", user, pass);
289             tm.sendMessage(ua.getPayload());
290
291             byte[] ar = getNextMessage();
292
293             if (ar[0] == Packets.SSH_MSG_USERAUTH_SUCCESS)
294             {
295                 authenticated = true;
296                 tm.removeMessageHandler(this, 0, 255);
297                 return true;
298             }
299
300             if (ar[0] == Packets.SSH_MSG_USERAUTH_FAILURE)
301             {
302                 PacketUserauthFailure puf = new PacketUserauthFailure(ar, 0, ar.length);
303
304                 remainingMethods = puf.getAuthThatCanContinue();
305                 isPartialSuccess = puf.isPartialSuccess();
306
307                 return false;
308             }
309
310             throw new IOException JavaDoc("Unexpected SSH message (type " + ar[0] + ")");
311
312         }
313         catch (IOException JavaDoc e)
314         {
315             tm.close(e, false);
316             throw (IOException JavaDoc) new IOException JavaDoc("Password authentication failed.").initCause(e);
317         }
318     }
319
320     public boolean authenticateInteractive(String JavaDoc user, String JavaDoc[] submethods, InteractiveCallback cb) throws IOException JavaDoc
321     {
322         try
323         {
324             initialize(user);
325
326             if (methodPossible("keyboard-interactive") == false)
327                 throw new IOException JavaDoc(
328                         "Authentication method keyboard-interactive not supported by the server at this stage.");
329
330             if (submethods == null)
331                 submethods = new String JavaDoc[0];
332
333             PacketUserauthRequestInteractive ua = new PacketUserauthRequestInteractive("ssh-connection", user,
334                     submethods);
335
336             tm.sendMessage(ua.getPayload());
337
338             while (true)
339             {
340                 byte[] ar = getNextMessage();
341
342                 if (ar[0] == Packets.SSH_MSG_USERAUTH_SUCCESS)
343                 {
344                     authenticated = true;
345                     tm.removeMessageHandler(this, 0, 255);
346                     return true;
347                 }
348
349                 if (ar[0] == Packets.SSH_MSG_USERAUTH_FAILURE)
350                 {
351                     PacketUserauthFailure puf = new PacketUserauthFailure(ar, 0, ar.length);
352
353                     remainingMethods = puf.getAuthThatCanContinue();
354                     isPartialSuccess = puf.isPartialSuccess();
355
356                     return false;
357                 }
358
359                 if (ar[0] == Packets.SSH_MSG_USERAUTH_INFO_REQUEST)
360                 {
361                     PacketUserauthInfoRequest pui = new PacketUserauthInfoRequest(ar, 0, ar.length);
362
363                     String JavaDoc[] responses;
364
365                     try
366                     {
367                         responses = cb.replyToChallenge(pui.getName(), pui.getInstruction(), pui.getNumPrompts(), pui
368                                 .getPrompt(), pui.getEcho());
369                     }
370                     catch (Exception JavaDoc e)
371                     {
372                         throw (IOException JavaDoc) new IOException JavaDoc("Exception in callback.").initCause(e);
373                     }
374
375                     if (responses == null)
376                         throw new IOException JavaDoc("Your callback may not return NULL!");
377
378                     PacketUserauthInfoResponse puir = new PacketUserauthInfoResponse(responses);
379                     tm.sendMessage(puir.getPayload());
380
381                     continue;
382                 }
383
384                 throw new IOException JavaDoc("Unexpected SSH message (type " + ar[0] + ")");
385             }
386         }
387         catch (IOException JavaDoc e)
388         {
389             tm.close(e, false);
390             throw (IOException JavaDoc) new IOException JavaDoc("Keyboard-interactive authentication failed.").initCause(e);
391         }
392     }
393
394     public void handleMessage(byte[] msg, int msglen) throws IOException JavaDoc
395     {
396         synchronized (packets)
397         {
398             if (msg == null)
399             {
400                 connectionClosed = true;
401             }
402             else
403             {
404                 byte[] tmp = new byte[msglen];
405                 System.arraycopy(msg, 0, tmp, 0, msglen);
406                 packets.addElement(tmp);
407             }
408
409             packets.notifyAll();
410
411             if (packets.size() > 5)
412             {
413                 connectionClosed = true;
414                 throw new IOException JavaDoc("Error, peer is flooding us with authentication packets.");
415             }
416         }
417     }
418 }
419
Popular Tags