comparison src/ch/ethz/ssh2/auth/AuthenticationManager.java @ 308:42b15aaa7ac7 ganymed

merge
author Carl Byington <carl@five-ten-sg.com>
date Wed, 30 Jul 2014 14:21:50 -0700
parents 071eccdff8ea
children 5afb8c1a54b9
comparison
equal deleted inserted replaced
306:90e47d99ea54 308:42b15aaa7ac7
47 */ 47 */
48 public class AuthenticationManager implements MessageHandler { 48 public class AuthenticationManager implements MessageHandler {
49 private ClientTransportManager tm; 49 private ClientTransportManager tm;
50 50
51 private final BlockingQueue<byte[]> packets 51 private final BlockingQueue<byte[]> packets
52 = new ArrayBlockingQueue<byte[]>(5); 52 = new ArrayBlockingQueue<byte[]>(5);
53 53
54 private boolean connectionClosed = false; 54 private boolean connectionClosed = false;
55 55
56 private String banner; 56 private String banner;
57 57
58 private Set<String> remainingMethods 58 private Set<String> remainingMethods
59 = new HashSet<String>(); 59 = new HashSet<String>();
60 60
61 private boolean isPartialSuccess = false; 61 private boolean isPartialSuccess = false;
62 62
63 private boolean authenticated = false; 63 private boolean authenticated = false;
64 private boolean initDone = false; 64 private boolean initDone = false;
66 public AuthenticationManager(ClientTransportManager tm) { 66 public AuthenticationManager(ClientTransportManager tm) {
67 this.tm = tm; 67 this.tm = tm;
68 } 68 }
69 69
70 private byte[] deQueue() throws IOException { 70 private byte[] deQueue() throws IOException {
71 if(connectionClosed) { 71 if (connectionClosed) {
72 throw tm.getReasonClosedCause(); 72 throw tm.getReasonClosedCause();
73 } 73 }
74
74 // Wait for packet 75 // Wait for packet
75 try { 76 try {
76 return packets.take(); 77 return packets.take();
77 } 78 }
78 catch(InterruptedException e) { 79 catch (InterruptedException e) {
79 throw new InterruptedIOException(e.getMessage()); 80 throw new InterruptedIOException(e.getMessage());
80 } 81 }
81 } 82 }
82 83
83 byte[] getNextMessage() throws IOException { 84 byte[] getNextMessage() throws IOException {
84 while(true) { 85 while (true) {
85 byte[] message = deQueue(); 86 byte[] message = deQueue();
86 switch(message[0]) { 87
88 switch (message[0]) {
87 case Packets.SSH_MSG_USERAUTH_BANNER: 89 case Packets.SSH_MSG_USERAUTH_BANNER:
88 // The server may send an SSH_MSG_USERAUTH_BANNER message at any 90 // The server may send an SSH_MSG_USERAUTH_BANNER message at any
89 // time after this authentication protocol starts and before 91 // time after this authentication protocol starts and before
90 // authentication is successful. 92 // authentication is successful.
91 PacketUserauthBanner sb = new PacketUserauthBanner(message); 93 PacketUserauthBanner sb = new PacketUserauthBanner(message);
92 banner = sb.getBanner(); 94 banner = sb.getBanner();
93 break; 95 break;
96
94 default: 97 default:
95 return message; 98 return message;
96 } 99 }
97 } 100 }
98 } 101 }
109 public boolean getPartialSuccess() { 112 public boolean getPartialSuccess() {
110 return isPartialSuccess; 113 return isPartialSuccess;
111 } 114 }
112 115
113 private boolean initialize(String user) throws IOException { 116 private boolean initialize(String user) throws IOException {
114 if(initDone == false) { 117 if (initDone == false) {
115 tm.registerMessageHandler(this, 0, 255); 118 tm.registerMessageHandler(this, 0, 255);
116
117 PacketServiceRequest sr = new PacketServiceRequest("ssh-userauth"); 119 PacketServiceRequest sr = new PacketServiceRequest("ssh-userauth");
118 tm.sendMessage(sr.getPayload()); 120 tm.sendMessage(sr.getPayload());
119
120 final PacketServiceAccept accept = new PacketServiceAccept(this.getNextMessage()); 121 final PacketServiceAccept accept = new PacketServiceAccept(this.getNextMessage());
121
122 PacketUserauthRequestNone auth = new PacketUserauthRequestNone("ssh-connection", user); 122 PacketUserauthRequestNone auth = new PacketUserauthRequestNone("ssh-connection", user);
123 tm.sendMessage(auth.getPayload()); 123 tm.sendMessage(auth.getPayload());
124
125 byte[] message = this.getNextMessage(); 124 byte[] message = this.getNextMessage();
126 initDone = true; 125 initDone = true;
127 switch(message[0]) { 126
127 switch (message[0]) {
128 case Packets.SSH_MSG_USERAUTH_SUCCESS: 128 case Packets.SSH_MSG_USERAUTH_SUCCESS:
129 authenticated = true; 129 authenticated = true;
130 tm.removeMessageHandler(this); 130 tm.removeMessageHandler(this);
131 return true; 131 return true;
132
132 case Packets.SSH_MSG_USERAUTH_FAILURE: 133 case Packets.SSH_MSG_USERAUTH_FAILURE:
133 PacketUserauthFailure puf = new PacketUserauthFailure(message); 134 PacketUserauthFailure puf = new PacketUserauthFailure(message);
134 remainingMethods = puf.getAuthThatCanContinue(); 135 remainingMethods = puf.getAuthThatCanContinue();
135 isPartialSuccess = puf.isPartialSuccess(); 136 isPartialSuccess = puf.isPartialSuccess();
136 return false; 137 return false;
137 } 138 }
139
138 throw new PacketTypeException(message[0]); 140 throw new PacketTypeException(message[0]);
139 } 141 }
142
140 return authenticated; 143 return authenticated;
141 } 144 }
142 145
143 public boolean authenticatePublicKey(String user, AgentProxy proxy) throws IOException { 146 public boolean authenticatePublicKey(String user, AgentProxy proxy) throws IOException {
144 initialize(user); 147 initialize(user);
145
146 boolean success; 148 boolean success;
147 for(AgentIdentity identity : proxy.getIdentities()) { 149
150 for (AgentIdentity identity : proxy.getIdentities()) {
148 success = authenticatePublicKey(user, identity); 151 success = authenticatePublicKey(user, identity);
149 if(success) { 152
153 if (success) {
150 return true; 154 return true;
151 } 155 }
152 } 156 }
157
153 return false; 158 return false;
154 } 159 }
155 160
156 private boolean authenticatePublicKey(String user, AgentIdentity identity) throws IOException { 161 private boolean authenticatePublicKey(String user, AgentIdentity identity) throws IOException {
157 if(!remainingMethods.contains("publickey")) { 162 if (!remainingMethods.contains("publickey")) {
158 throw new IOException("Authentication method not supported"); 163 throw new IOException("Authentication method not supported");
159 } 164 }
160 165
161 byte[] pubKeyBlob = identity.getPublicKeyBlob(); 166 byte[] pubKeyBlob = identity.getPublicKeyBlob();
162 if(pubKeyBlob == null) { 167
168 if (pubKeyBlob == null) {
163 return false; 169 return false;
164 } 170 }
165 171
166 TypesWriter tw = new TypesWriter(); 172 TypesWriter tw = new TypesWriter();
167 byte[] H = tm.getSessionIdentifier(); 173 byte[] H = tm.getSessionIdentifier();
168
169 tw.writeString(H, 0, H.length); 174 tw.writeString(H, 0, H.length);
170 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); 175 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
171 tw.writeString(user); 176 tw.writeString(user);
172 tw.writeString("ssh-connection"); 177 tw.writeString("ssh-connection");
173 tw.writeString("publickey"); 178 tw.writeString("publickey");
174 tw.writeBoolean(true); 179 tw.writeBoolean(true);
175 tw.writeString(identity.getAlgName()); 180 tw.writeString(identity.getAlgName());
176 tw.writeString(pubKeyBlob, 0, pubKeyBlob.length); 181 tw.writeString(pubKeyBlob, 0, pubKeyBlob.length);
177
178 byte[] msg = tw.getBytes(); 182 byte[] msg = tw.getBytes();
179 byte[] response = identity.sign(msg); 183 byte[] response = identity.sign(msg);
180
181 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey( 184 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey(
182 "ssh-connection", user, identity.getAlgName(), pubKeyBlob, response); 185 "ssh-connection", user, identity.getAlgName(), pubKeyBlob, response);
183 tm.sendMessage(ua.getPayload()); 186 tm.sendMessage(ua.getPayload());
184
185 byte[] message = getNextMessage(); 187 byte[] message = getNextMessage();
186 final int type = message[0]; 188 final int type = message[0];
187 switch(type) { 189
190 switch (type) {
188 case Packets.SSH_MSG_USERAUTH_SUCCESS: 191 case Packets.SSH_MSG_USERAUTH_SUCCESS:
189 authenticated = true; 192 authenticated = true;
190 tm.removeMessageHandler(this); 193 tm.removeMessageHandler(this);
191 return true; 194 return true;
195
192 case Packets.SSH_MSG_USERAUTH_FAILURE: 196 case Packets.SSH_MSG_USERAUTH_FAILURE:
193 PacketUserauthFailure puf = new PacketUserauthFailure(message); 197 PacketUserauthFailure puf = new PacketUserauthFailure(message);
194
195 remainingMethods = puf.getAuthThatCanContinue(); 198 remainingMethods = puf.getAuthThatCanContinue();
196 isPartialSuccess = puf.isPartialSuccess(); 199 isPartialSuccess = puf.isPartialSuccess();
197
198 return false; 200 return false;
199 } 201 }
202
200 throw new PacketTypeException(type); 203 throw new PacketTypeException(type);
201 } 204 }
202 205
203 public boolean authenticatePublicKey(String user, char[] PEMPrivateKey, String password, SecureRandom rnd) 206 public boolean authenticatePublicKey(String user, char[] PEMPrivateKey, String password, SecureRandom rnd)
204 throws IOException { 207 throws IOException {
207 } 210 }
208 211
209 public boolean authenticatePublicKey(String user, KeyPair pair, SecureRandom rnd) 212 public boolean authenticatePublicKey(String user, KeyPair pair, SecureRandom rnd)
210 throws IOException { 213 throws IOException {
211 PrivateKey key = pair.getPrivate(); 214 PrivateKey key = pair.getPrivate();
215
212 try { 216 try {
213 initialize(user); 217 initialize(user);
214 218
215 if(!remainingMethods.contains("publickey")) { 219 if (!remainingMethods.contains("publickey")) {
216 throw new IOException("Authentication method publickey not supported by the server at this stage."); 220 throw new IOException("Authentication method publickey not supported by the server at this stage.");
217 } 221 }
218 222
219 if (key instanceof DSAPrivateKey) { 223 if (key instanceof DSAPrivateKey) {
220 DSAPrivateKey pk = (DSAPrivateKey) key; 224 DSAPrivateKey pk = (DSAPrivateKey) key;
221
222 byte[] pk_enc = DSASHA1Verify.encodeSSHDSAPublicKey((DSAPublicKey) pair.getPublic()); 225 byte[] pk_enc = DSASHA1Verify.encodeSSHDSAPublicKey((DSAPublicKey) pair.getPublic());
223
224 TypesWriter tw = new TypesWriter(); 226 TypesWriter tw = new TypesWriter();
225
226 byte[] H = tm.getSessionIdentifier(); 227 byte[] H = tm.getSessionIdentifier();
227
228 tw.writeString(H, 0, H.length); 228 tw.writeString(H, 0, H.length);
229 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); 229 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
230 tw.writeString(user); 230 tw.writeString(user);
231 tw.writeString("ssh-connection"); 231 tw.writeString("ssh-connection");
232 tw.writeString("publickey"); 232 tw.writeString("publickey");
233 tw.writeBoolean(true); 233 tw.writeBoolean(true);
234 tw.writeString("ssh-dss"); 234 tw.writeString("ssh-dss");
235 tw.writeString(pk_enc, 0, pk_enc.length); 235 tw.writeString(pk_enc, 0, pk_enc.length);
236
237 byte[] msg = tw.getBytes(); 236 byte[] msg = tw.getBytes();
238
239 byte[] ds = DSASHA1Verify.generateSignature(msg, pk, rnd); 237 byte[] ds = DSASHA1Verify.generateSignature(msg, pk, rnd);
240
241 byte[] ds_enc = DSASHA1Verify.encodeSSHDSASignature(ds); 238 byte[] ds_enc = DSASHA1Verify.encodeSSHDSASignature(ds);
242
243 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user, 239 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user,
244 "ssh-dss", pk_enc, ds_enc); 240 "ssh-dss", pk_enc, ds_enc);
245 tm.sendMessage(ua.getPayload()); 241 tm.sendMessage(ua.getPayload());
246 } 242 }
247 else if(key instanceof RSAPrivateKey) { 243 else if (key instanceof RSAPrivateKey) {
248 RSAPrivateKey pk = (RSAPrivateKey) key; 244 RSAPrivateKey pk = (RSAPrivateKey) key;
249
250 byte[] pk_enc = RSASHA1Verify.encodeSSHRSAPublicKey((RSAPublicKey) pair.getPublic()); 245 byte[] pk_enc = RSASHA1Verify.encodeSSHRSAPublicKey((RSAPublicKey) pair.getPublic());
251
252 TypesWriter tw = new TypesWriter(); 246 TypesWriter tw = new TypesWriter();
253 { 247 {
254 byte[] H = tm.getSessionIdentifier(); 248 byte[] H = tm.getSessionIdentifier();
255
256 tw.writeString(H, 0, H.length); 249 tw.writeString(H, 0, H.length);
257 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); 250 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
258 tw.writeString(user); 251 tw.writeString(user);
259 tw.writeString("ssh-connection"); 252 tw.writeString("ssh-connection");
260 tw.writeString("publickey"); 253 tw.writeString("publickey");
261 tw.writeBoolean(true); 254 tw.writeBoolean(true);
262 tw.writeString("ssh-rsa"); 255 tw.writeString("ssh-rsa");
263 tw.writeString(pk_enc, 0, pk_enc.length); 256 tw.writeString(pk_enc, 0, pk_enc.length);
264 } 257 }
265
266 byte[] msg = tw.getBytes(); 258 byte[] msg = tw.getBytes();
267
268 byte[] ds = RSASHA1Verify.generateSignature(msg, pk); 259 byte[] ds = RSASHA1Verify.generateSignature(msg, pk);
269
270 byte[] rsa_sig_enc = RSASHA1Verify.encodeSSHRSASignature(ds); 260 byte[] rsa_sig_enc = RSASHA1Verify.encodeSSHRSASignature(ds);
271
272 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user, 261 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user,
273 "ssh-rsa", pk_enc, rsa_sig_enc); 262 "ssh-rsa", pk_enc, rsa_sig_enc);
274 tm.sendMessage(ua.getPayload()); 263 tm.sendMessage(ua.getPayload());
275 } 264 }
276 else if (key instanceof ECPrivateKey) { 265 else if (key instanceof ECPrivateKey) {
298 tm.sendMessage(ua.getPayload()); 287 tm.sendMessage(ua.getPayload());
299 } 288 }
300 else { 289 else {
301 throw new IOException("Unknown private key type returned by the PEM decoder."); 290 throw new IOException("Unknown private key type returned by the PEM decoder.");
302 } 291 }
292
303 byte[] message = getNextMessage(); 293 byte[] message = getNextMessage();
304 final int type = message[0]; 294 final int type = message[0];
305 switch(type) { 295
296 switch (type) {
306 case Packets.SSH_MSG_USERAUTH_SUCCESS: 297 case Packets.SSH_MSG_USERAUTH_SUCCESS:
307 authenticated = true; 298 authenticated = true;
308 tm.removeMessageHandler(this); 299 tm.removeMessageHandler(this);
309 return true; 300 return true;
310 case Packets.SSH_MSG_USERAUTH_FAILURE: 301
311 PacketUserauthFailure puf = new PacketUserauthFailure(message);
312
313 remainingMethods = puf.getAuthThatCanContinue();
314 isPartialSuccess = puf.isPartialSuccess();
315
316 return false;
317 }
318 throw new PacketTypeException(type);
319 }
320 catch(IOException e) {
321 tm.close(e);
322 throw e;
323 }
324 }
325
326 public boolean authenticateNone(String user) throws IOException {
327 try {
328 initialize(user);
329 return authenticated;
330 }
331 catch(IOException e) {
332 tm.close(e);
333 throw e;
334 }
335 }
336
337 public boolean authenticatePassword(String user, String pass) throws IOException {
338 try {
339 initialize(user);
340
341 if(!remainingMethods.contains("password")) {
342 throw new IOException("Authentication method not supported");
343 }
344
345 PacketUserauthRequestPassword ua = new PacketUserauthRequestPassword("ssh-connection", user, pass);
346 tm.sendMessage(ua.getPayload());
347
348 byte[] message = getNextMessage();
349 final int type = message[0];
350 switch(type) {
351 case Packets.SSH_MSG_USERAUTH_SUCCESS:
352 authenticated = true;
353 tm.removeMessageHandler(this);
354 return true;
355 case Packets.SSH_MSG_USERAUTH_FAILURE: 302 case Packets.SSH_MSG_USERAUTH_FAILURE:
356 PacketUserauthFailure puf = new PacketUserauthFailure(message); 303 PacketUserauthFailure puf = new PacketUserauthFailure(message);
357 remainingMethods = puf.getAuthThatCanContinue(); 304 remainingMethods = puf.getAuthThatCanContinue();
358 isPartialSuccess = puf.isPartialSuccess(); 305 isPartialSuccess = puf.isPartialSuccess();
359 return false; 306 return false;
360 } 307 }
308
361 throw new PacketTypeException(type); 309 throw new PacketTypeException(type);
362 } 310 }
363 catch(IOException e) { 311 catch (IOException e) {
312 tm.close(e);
313 throw e;
314 }
315 }
316
317 public boolean authenticateNone(String user) throws IOException {
318 try {
319 initialize(user);
320 return authenticated;
321 }
322 catch (IOException e) {
323 tm.close(e);
324 throw e;
325 }
326 }
327
328 public boolean authenticatePassword(String user, String pass) throws IOException {
329 try {
330 initialize(user);
331
332 if (!remainingMethods.contains("password")) {
333 throw new IOException("Authentication method not supported");
334 }
335
336 PacketUserauthRequestPassword ua = new PacketUserauthRequestPassword("ssh-connection", user, pass);
337 tm.sendMessage(ua.getPayload());
338 byte[] message = getNextMessage();
339 final int type = message[0];
340
341 switch (type) {
342 case Packets.SSH_MSG_USERAUTH_SUCCESS:
343 authenticated = true;
344 tm.removeMessageHandler(this);
345 return true;
346
347 case Packets.SSH_MSG_USERAUTH_FAILURE:
348 PacketUserauthFailure puf = new PacketUserauthFailure(message);
349 remainingMethods = puf.getAuthThatCanContinue();
350 isPartialSuccess = puf.isPartialSuccess();
351 return false;
352 }
353
354 throw new PacketTypeException(type);
355 }
356 catch (IOException e) {
364 tm.close(e); 357 tm.close(e);
365 throw e; 358 throw e;
366 } 359 }
367 } 360 }
368 361
369 public boolean authenticateInteractive(String user, String[] submethods, InteractiveCallback cb) throws IOException { 362 public boolean authenticateInteractive(String user, String[] submethods, InteractiveCallback cb) throws IOException {
370 try { 363 try {
371 initialize(user); 364 initialize(user);
372 365
373 if(!remainingMethods.contains("keyboard-interactive")) { 366 if (!remainingMethods.contains("keyboard-interactive")) {
374 throw new IOException( 367 throw new IOException(
375 "Authentication method keyboard-interactive not supported by the server at this stage."); 368 "Authentication method keyboard-interactive not supported by the server at this stage.");
376 } 369 }
377 370
378 PacketUserauthRequestInteractive ua = new PacketUserauthRequestInteractive("ssh-connection", user, 371 PacketUserauthRequestInteractive ua = new PacketUserauthRequestInteractive("ssh-connection", user,
379 submethods); 372 submethods);
380
381 tm.sendMessage(ua.getPayload()); 373 tm.sendMessage(ua.getPayload());
382 374
383 while(true) { 375 while (true) {
384 byte[] message = getNextMessage(); 376 byte[] message = getNextMessage();
385 final int type = message[0]; 377 final int type = message[0];
386 switch(type) { 378
379 switch (type) {
387 case Packets.SSH_MSG_USERAUTH_SUCCESS: 380 case Packets.SSH_MSG_USERAUTH_SUCCESS:
388 authenticated = true; 381 authenticated = true;
389 tm.removeMessageHandler(this); 382 tm.removeMessageHandler(this);
390 return true; 383 return true;
384
391 case Packets.SSH_MSG_USERAUTH_FAILURE: 385 case Packets.SSH_MSG_USERAUTH_FAILURE:
392 PacketUserauthFailure puf = new PacketUserauthFailure(message); 386 PacketUserauthFailure puf = new PacketUserauthFailure(message);
393
394 remainingMethods = puf.getAuthThatCanContinue(); 387 remainingMethods = puf.getAuthThatCanContinue();
395 isPartialSuccess = puf.isPartialSuccess(); 388 isPartialSuccess = puf.isPartialSuccess();
396
397 return false; 389 return false;
390
398 case Packets.SSH_MSG_USERAUTH_INFO_REQUEST: 391 case Packets.SSH_MSG_USERAUTH_INFO_REQUEST:
399 PacketUserauthInfoRequest info = new PacketUserauthInfoRequest(message); 392 PacketUserauthInfoRequest info = new PacketUserauthInfoRequest(message);
400 String[] responses; 393 String[] responses;
394
401 try { 395 try {
402 responses = cb.replyToChallenge(info.getName(), info.getInstruction(), info.getNumPrompts(), 396 responses = cb.replyToChallenge(info.getName(), info.getInstruction(), info.getNumPrompts(),
403 info.getPrompt(), info.getEcho()); 397 info.getPrompt(), info.getEcho());
404 } 398 }
405 catch(Exception e) { 399 catch (Exception e) {
406 throw new IOException("Exception in callback.", e); 400 throw new IOException("Exception in callback.", e);
407 } 401 }
402
408 PacketUserauthInfoResponse puir = new PacketUserauthInfoResponse(responses); 403 PacketUserauthInfoResponse puir = new PacketUserauthInfoResponse(responses);
409 tm.sendMessage(puir.getPayload()); 404 tm.sendMessage(puir.getPayload());
410 continue; 405 continue;
411 } 406 }
407
412 throw new PacketTypeException(type); 408 throw new PacketTypeException(type);
413 } 409 }
414 } 410 }
415 catch(IOException e) { 411 catch (IOException e) {
416 tm.close(e); 412 tm.close(e);
417 throw e; 413 throw e;
418 } 414 }
419 } 415 }
420 416