KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > HTTPClient > DefaultAuthHandler


1 /*
2  * @(#)DefaultAuthHandler.java 0.3-2 18/06/1999
3  *
4  * This file is part of the HTTPClient package
5  * Copyright (C) 1996-1999 Ronald Tschalär
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307, USA
21  *
22  * For questions, suggestions, bug-reports, enhancement-requests etc.
23  * I may be contacted at:
24  *
25  * ronald@innovation.ch
26  *
27  */

28
29 package HTTPClient;
30
31
32 import java.io.IOException JavaDoc;
33 import java.io.FileInputStream JavaDoc;
34 import java.io.DataInputStream JavaDoc;
35 import java.util.Vector JavaDoc;
36 import java.util.StringTokenizer JavaDoc;
37
38 import java.awt.Frame JavaDoc;
39 import java.awt.Panel JavaDoc;
40 import java.awt.Label JavaDoc;
41 import java.awt.Button JavaDoc;
42 import java.awt.Dimension JavaDoc;
43 import java.awt.TextField JavaDoc;
44 import java.awt.GridLayout JavaDoc;
45 import java.awt.BorderLayout JavaDoc;
46 import java.awt.GridBagLayout JavaDoc;
47 import java.awt.GridBagConstraints JavaDoc;
48 import java.awt.event.ActionEvent JavaDoc;
49 import java.awt.event.ActionListener JavaDoc;
50 import java.awt.event.WindowEvent JavaDoc;
51 import java.awt.event.WindowAdapter JavaDoc;
52
53 /**
54  * A simple authorization handler that throws up a message box requesting
55  * both a username and password. This is default authorization handler.
56  * Currently only handles the authentication types "Basic", "Digest" and
57  * "SOCKS5" (used for the SocksClient and not part of HTTP per se).
58  *
59  * @version 0.3-2 18/06/1999
60  * @author Ronald Tschalär
61  * @since V0.2
62  */

63
64 class DefaultAuthHandler implements AuthorizationHandler, GlobalConstants
65 {
66     private static final byte[] NUL = new byte[0];
67
68     private static final int DI_A1 = 0;
69     private static final int DI_A1S = 1;
70     private static final int DI_QOP = 2;
71
72     private static byte[] digest_secret = null;
73
74     private BasicAuthBox inp = null;
75
76
77
78     /**
79      * For Digest authentication we need to set the uri, response and
80      * opaque parameters. For "Basic" and "SOCKS5" nothing is done.
81      */

82     public AuthorizationInfo fixupAuthInfo(AuthorizationInfo info,
83                        RoRequest req,
84                        AuthorizationInfo challenge,
85                        RoResponse resp)
86             throws AuthSchemeNotImplException
87     {
88     // nothing to do for Basic and SOCKS5 schemes
89

90     if (info.getScheme().equalsIgnoreCase("Basic") ||
91         info.getScheme().equalsIgnoreCase("SOCKS5"))
92         return info;
93     else if (!info.getScheme().equalsIgnoreCase("Digest"))
94         throw new AuthSchemeNotImplException(info.getScheme());
95
96     if (DebugAuth)
97         System.err.println("Auth: fixing up Authorization for host " +
98                 info.getHost()+":"+info.getPort() +
99                 "; scheme: " + info.getScheme() +
100                 "; realm: " + info.getRealm());
101
102     return digest_fixup(info, req, challenge, resp);
103     }
104
105
106     /**
107      * returns the requested authorization, or null if none was given.
108      *
109      * @param challenge the parsed challenge from the server.
110      * @param req the request which solicited this response
111      * @param resp the full response received
112      * @return a structure containing the necessary authorization info,
113      * or null
114      * @exception AuthSchemeNotImplException if the authentication scheme
115      * in the challenge cannot be handled.
116      */

117     public AuthorizationInfo getAuthorization(AuthorizationInfo challenge,
118                           RoRequest req, RoResponse resp)
119             throws AuthSchemeNotImplException
120     {
121     AuthorizationInfo cred;
122
123
124     if (DebugAuth)
125         System.err.println("Auth: Requesting Authorization for host " +
126                 challenge.getHost()+":"+challenge.getPort() +
127                 "; scheme: " + challenge.getScheme() +
128                 "; realm: " + challenge.getRealm());
129
130
131     // we only handle Basic, Digest and SOCKS5 authentication
132

133     if (!challenge.getScheme().equalsIgnoreCase("Basic") &&
134         !challenge.getScheme().equalsIgnoreCase("Digest") &&
135         !challenge.getScheme().equalsIgnoreCase("SOCKS5"))
136         throw new AuthSchemeNotImplException(challenge.getScheme());
137
138
139     // For digest authentication, check if stale is set
140

141     if (challenge.getScheme().equalsIgnoreCase("Digest"))
142     {
143         cred = digest_check_stale(challenge, req, resp);
144         if (cred != null)
145         return cred;
146     }
147
148
149     // Ask the user for username/password
150

151     if (!req.allowUI())
152         return null;
153
154     if (inp == null)
155     {
156         synchronized(getClass())
157         {
158         if (inp == null)
159             inp = new BasicAuthBox();
160         }
161     }
162
163     NVPair answer;
164     if (challenge.getScheme().equalsIgnoreCase("basic") ||
165         challenge.getScheme().equalsIgnoreCase("Digest"))
166     {
167         answer = inp.getInput("Enter username and password for realm `" +
168                   challenge.getRealm() + "'",
169                   "on host " + challenge.getHost() + ":" +
170                   challenge.getPort(),
171                   "Authentication Scheme: " +
172                   challenge.getScheme());
173     }
174     else
175     {
176         answer = inp.getInput("Enter username and password for SOCKS " +
177                   "server on host ", challenge.getHost(),
178                   "Authentication Method: username/password");
179     }
180
181     if (answer == null)
182         return null;
183
184
185     // Now process the username/password
186

187     if (challenge.getScheme().equalsIgnoreCase("basic"))
188     {
189         cred = new AuthorizationInfo(challenge.getHost(),
190                      challenge.getPort(),
191                      challenge.getScheme(),
192                      challenge.getRealm(),
193                      Codecs.base64Encode(
194                         answer.getName() + ":" +
195                         answer.getValue()));
196     }
197     else if (challenge.getScheme().equalsIgnoreCase("Digest"))
198     {
199         cred = digest_gen_auth_info(challenge.getHost(),
200                     challenge.getPort(),
201                         challenge.getRealm(), answer.getName(),
202                     answer.getValue(),
203                     req.getConnection().getContext());
204         cred = digest_fixup(cred, req, challenge, null);
205     }
206     else // SOCKS5
207
{
208         NVPair[] upwd = { answer };
209         cred = new AuthorizationInfo(challenge.getHost(),
210                      challenge.getPort(),
211                      challenge.getScheme(),
212                      challenge.getRealm(),
213                      upwd, null);
214     }
215
216
217     // try to get rid of any unencoded passwords in memory
218

219     answer = null;
220     System.gc();
221
222
223     // Done
224

225     if (DebugAuth) System.err.println("Auth: Got Authorization");
226
227     return cred;
228     }
229
230
231     /**
232      * We handle the "Authentication-Info" and "Proxy-Authentication-Info"
233      * headers here.
234      */

235     public void handleAuthHeaders(Response resp, RoRequest req,
236                   AuthorizationInfo prev,
237                   AuthorizationInfo prxy)
238         throws IOException JavaDoc
239     {
240     String JavaDoc auth_info = resp.getHeader("Authentication-Info");
241     String JavaDoc prxy_info = resp.getHeader("Proxy-Authentication-Info");
242
243     if (auth_info == null && prev != null &&
244         hasParam(prev.getParams(), "qop", "auth-int"))
245         auth_info = "";
246
247     if (prxy_info == null && prxy != null &&
248         hasParam(prxy.getParams(), "qop", "auth-int"))
249         prxy_info = "";
250
251     try
252     {
253         handleAuthInfo(auth_info, "Authentication-Info", prev, resp, req,
254                true);
255         handleAuthInfo(prxy_info, "Proxy-Authentication-Info", prxy, resp,
256                req, true);
257     }
258     catch (ParseException pe)
259         { throw new IOException JavaDoc(pe.toString()); }
260     }
261
262
263     /**
264      * We handle the "Authentication-Info" and "Proxy-Authentication-Info"
265      * trailers here.
266      */

267     public void handleAuthTrailers(Response resp, RoRequest req,
268                    AuthorizationInfo prev,
269                    AuthorizationInfo prxy)
270         throws IOException JavaDoc
271     {
272     String JavaDoc auth_info = resp.getTrailer("Authentication-Info");
273     String JavaDoc prxy_info = resp.getTrailer("Proxy-Authentication-Info");
274
275     try
276     {
277         handleAuthInfo(auth_info, "Authentication-Info", prev, resp, req,
278                false);
279         handleAuthInfo(prxy_info, "Proxy-Authentication-Info", prxy, resp,
280                req, false);
281     }
282     catch (ParseException pe)
283         { throw new IOException JavaDoc(pe.toString()); }
284     }
285
286
287     private static void handleAuthInfo(String JavaDoc auth_info, String JavaDoc hdr_name,
288                        AuthorizationInfo prev, Response resp,
289                        RoRequest req, boolean in_headers)
290         throws ParseException, IOException JavaDoc
291     {
292     if (auth_info == null) return;
293
294     Vector JavaDoc pai = Util.parseHeader(auth_info);
295     HttpHeaderElement elem;
296
297     if (handle_nextnonce(prev, req,
298                  elem = Util.getElement(pai, "nextnonce")))
299         pai.removeElement(elem);
300     if (handle_discard(prev, req, elem = Util.getElement(pai, "discard")))
301         pai.removeElement(elem);
302
303     if (in_headers)
304     {
305         HttpHeaderElement qop = null;
306
307         if (pai != null &&
308         (qop = Util.getElement(pai, "qop")) != null &&
309         qop.getValue() != null)
310         {
311         handle_rspauth(prev, resp, req, pai, hdr_name);
312         }
313         else if (prev != null &&
314              (Util.hasToken(resp.getHeader("Trailer"), hdr_name) &&
315               hasParam(prev.getParams(), "qop", null) ||
316               hasParam(prev.getParams(), "qop", "auth-int")))
317         {
318         handle_rspauth(prev, resp, req, null, hdr_name);
319         }
320
321         else if ((pai != null && qop == null &&
322               pai.contains(new HttpHeaderElement("digest"))) ||
323              (Util.hasToken(resp.getHeader("Trailer"), hdr_name) &&
324               prev != null &&
325               !hasParam(prev.getParams(), "qop", null)))
326         {
327         handle_digest(prev, resp, req, hdr_name);
328         }
329     }
330
331     if (pai.size() > 0)
332         resp.setHeader(hdr_name, Util.assembleHeader(pai));
333     else
334         resp.deleteHeader(hdr_name);
335     }
336
337
338     private static final boolean hasParam(NVPair[] params, String JavaDoc name,
339                       String JavaDoc val)
340     {
341     for (int idx=0; idx<params.length; idx++)
342         if (params[idx].getName().equalsIgnoreCase(name) &&
343         (val == null || params[idx].getValue().equalsIgnoreCase(val)))
344         return true;
345
346     return false;
347     }
348
349
350     /*
351      * Here are all the Digest specific methods
352      */

353
354     private static AuthorizationInfo digest_gen_auth_info(String JavaDoc host, int port,
355                               String JavaDoc realm,
356                               String JavaDoc user,
357                               String JavaDoc pass,
358                               Object JavaDoc context)
359     {
360     String JavaDoc A1 = user + ":" + realm + ":" + pass;
361     String JavaDoc[] info = { new MD5(A1).asHex(), null, null };
362
363     AuthorizationInfo prev = AuthorizationInfo.getAuthorization(host, port,
364                             "Digest", realm, context);
365     NVPair[] params;
366     if (prev == null)
367     {
368         params = new NVPair[4];
369         params[0] = new NVPair("username", user);
370         params[1] = new NVPair("uri", "");
371         params[2] = new NVPair("nonce", "");
372         params[3] = new NVPair("response", "");
373     }
374     else
375     {
376         params = prev.getParams();
377         for (int idx=0; idx<params.length; idx++)
378         {
379         if (params[idx].getName().equalsIgnoreCase("username"))
380         {
381             params[idx] = new NVPair("username", user);
382             break;
383         }
384         }
385     }
386
387     return new AuthorizationInfo(host, port, "Digest", realm, params, info);
388     }
389
390
391     /**
392      * The fixup handler
393      */

394     private static AuthorizationInfo digest_fixup(AuthorizationInfo info,
395                           RoRequest req,
396                           AuthorizationInfo challenge,
397                           RoResponse resp)
398         throws AuthSchemeNotImplException
399     {
400     // get various parameters from challenge
401

402     int ch_domain=-1, ch_nonce=-1, ch_alg=-1, ch_opaque=-1, ch_stale=-1,
403         ch_dreq=-1, ch_qop=-1;
404     NVPair[] ch_params = null;
405     if (challenge != null)
406     {
407         ch_params = challenge.getParams();
408
409         for (int idx=0; idx<ch_params.length; idx++)
410         {
411         String JavaDoc name = ch_params[idx].getName().toLowerCase();
412         if (name.equals("domain")) ch_domain = idx;
413         else if (name.equals("nonce")) ch_nonce = idx;
414         else if (name.equals("opaque")) ch_opaque = idx;
415         else if (name.equals("algorithm")) ch_alg = idx;
416         else if (name.equals("stale")) ch_stale = idx;
417         else if (name.equals("digest-required")) ch_dreq = idx;
418         else if (name.equals("qop")) ch_qop = idx;
419         }
420     }
421
422
423     // get various parameters from info
424

425     int uri=-1, user=-1, alg=-1, response=-1, nonce=-1, cnonce=-1, nc=-1,
426         opaque=-1, digest=-1, dreq=-1, qop=-1;
427     NVPair[] params;
428     String JavaDoc[] extra;
429
430     synchronized(info) // we need to juggle nonce, nc, etc
431
{
432         params = info.getParams();
433
434         for (int idx=0; idx<params.length; idx++)
435         {
436         String JavaDoc name = params[idx].getName().toLowerCase();
437         if (name.equals("uri")) uri = idx;
438         else if (name.equals("username")) user = idx;
439         else if (name.equals("algorithm")) alg = idx;
440         else if (name.equals("nonce")) nonce = idx;
441         else if (name.equals("cnonce")) cnonce = idx;
442         else if (name.equals("nc")) nc = idx;
443         else if (name.equals("response")) response = idx;
444         else if (name.equals("opaque")) opaque = idx;
445         else if (name.equals("digest")) digest = idx;
446         else if (name.equals("digest-required")) dreq = idx;
447         else if (name.equals("qop")) qop = idx;
448         }
449
450         extra = (String JavaDoc[]) info.getExtraInfo();
451
452
453         // currently only MD5 hash (and "MD5-sess") is supported
454

455         if (alg != -1 &&
456         !params[alg].getValue().equalsIgnoreCase("MD5") &&
457         !params[alg].getValue().equalsIgnoreCase("MD5-sess"))
458         throw new AuthSchemeNotImplException("Digest auth scheme: " +
459                     "Algorithm " + params[alg].getValue() +
460                     " not implemented");
461
462         if (ch_alg != -1 &&
463         !ch_params[ch_alg].getValue().equalsIgnoreCase("MD5") &&
464         !ch_params[ch_alg].getValue().equalsIgnoreCase("MD5-sess"))
465         throw new AuthSchemeNotImplException("Digest auth scheme: " +
466                     "Algorithm " + ch_params[ch_alg].getValue()+
467                     " not implemented");
468
469
470         // fix up uri and nonce
471

472         params[uri] = new NVPair("uri", req.getRequestURI());
473         String JavaDoc old_nonce = params[nonce].getValue();
474         if (ch_nonce != -1 &&
475         !old_nonce.equals(ch_params[ch_nonce].getValue()))
476         params[nonce] = ch_params[ch_nonce];
477
478
479         // update or add optional attributes (opaque, algorithm, cnonce,
480
// nonce-count, and qop
481

482         if (ch_opaque != -1)
483         {
484         if (opaque == -1)
485         {
486             params = Util.resizeArray(params, params.length+1);
487             opaque = params.length-1;
488         }
489         params[opaque] = ch_params[ch_opaque];
490         }
491
492         if (ch_alg != -1)
493         {
494         if (alg == -1)
495         {
496             params = Util.resizeArray(params, params.length+1);
497             alg = params.length-1;
498         }
499         params[alg] = ch_params[ch_alg];
500         }
501
502         if (ch_qop != -1 ||
503         (ch_alg != -1 &&
504          ch_params[ch_alg].getValue().equalsIgnoreCase("MD5-sess")))
505         {
506         if (cnonce == -1)
507         {
508             params = Util.resizeArray(params, params.length+1);
509             cnonce = params.length-1;
510         }
511
512         if (digest_secret == null)
513             digest_secret = gen_random_bytes(20);
514
515         long l_time = System.currentTimeMillis();
516         byte[] time = new byte[8];
517         time[0] = (byte) (l_time & 0xFF);
518         time[1] = (byte) ((l_time >> 8) & 0xFF);
519         time[2] = (byte) ((l_time >> 16) & 0xFF);
520         time[3] = (byte) ((l_time >> 24) & 0xFF);
521         time[4] = (byte) ((l_time >> 32) & 0xFF);
522         time[5] = (byte) ((l_time >> 40) & 0xFF);
523         time[6] = (byte) ((l_time >> 48) & 0xFF);
524         time[7] = (byte) ((l_time >> 56) & 0xFF);
525
526         MD5 hash = new MD5(digest_secret);
527         hash.Update(time);
528         params[cnonce] = new NVPair("cnonce", hash.asHex());
529         }
530
531
532         // select qop option
533

534         if (ch_qop != -1)
535         {
536         if (qop == -1)
537         {
538             params = Util.resizeArray(params, params.length+1);
539             qop = params.length-1;
540         }
541         extra[DI_QOP] = ch_params[ch_qop].getValue();
542
543
544         // select qop option
545

546         String JavaDoc[] qops = splitList(extra[DI_QOP], ",");
547         String JavaDoc p = null;
548         for (int idx=0; idx<qops.length; idx++)
549         {
550             if (qops[idx].equalsIgnoreCase("auth-int") &&
551             (req.getStream() == null ||
552              req.getConnection().ServProtVersKnown &&
553              req.getConnection().ServerProtocolVersion >= HTTP_1_1))
554             {
555             p = "auth-int";
556             break;
557             }
558             if (qops[idx].equalsIgnoreCase("auth"))
559             p = "auth";
560         }
561         if (p == null)
562         {
563             for (int idx=0; idx<qops.length; idx++)
564             if (qops[idx].equalsIgnoreCase("auth-int"))
565                 throw new AuthSchemeNotImplException(
566                 "Digest auth scheme: Can't comply with qop " +
567                 "option 'auth-int' because an HttpOutputStream " +
568                 "is being used and the server doesn't speak " +
569                 "HTTP/1.1");
570
571             throw new AuthSchemeNotImplException("Digest auth scheme: "+
572                 "None of the available qop options '" +
573                 ch_params[ch_qop].getValue() + "' implemented");
574         }
575         params[qop] = new NVPair("qop", p);
576         }
577
578
579         // increment nonce-count.
580

581         if (qop != -1)
582         {
583         /* Note: we should actually be serializing all requests through
584          * here so that the server sees the nonce-count in a
585          * strictly increasing order. However, this would be a
586          * *major* hassle to do, so we're just winging it. Most
587          * of the time the requests will go over the wire in the
588          * same order as they pass through here, but in MT apps
589          * it's possible for one request to "overtake" another
590          * between here and the synchronized block in
591          * sendRequest().
592          */

593         if (nc == -1)
594         {
595             params = Util.resizeArray(params, params.length+1);
596             nc = params.length-1;
597             params[nc] = new NVPair("nc", "00000001");
598         }
599         else if (old_nonce.equals(params[nonce].getValue()))
600         {
601             String JavaDoc c = Long.toHexString(
602                 Long.parseLong(params[nc].getValue(), 16) + 1);
603             params[nc] =
604             new NVPair("nc", "00000000".substring(c.length()) + c);
605         }
606         else
607             params[nc] = new NVPair("nc", "00000001");
608         }
609
610
611         // calc new session key if necessary
612

613         if (challenge != null &&
614         (ch_stale == -1 ||
615          !ch_params[ch_stale].getValue().equalsIgnoreCase("true")) &&
616         alg != -1 &&
617         params[alg].getValue().equalsIgnoreCase("MD5-sess"))
618         {
619         extra[DI_A1S] = new MD5(extra[DI_A1] + ":" +
620                     params[nonce].getValue() + ":" +
621                     params[cnonce].getValue()).asHex();
622         }
623
624
625         // update parameters for next auth cycle
626

627         info.setParams(params);
628         info.setExtraInfo(extra);
629     }
630
631
632     // calc "response" attribute
633

634     String JavaDoc hash = null;
635     if (qop != -1 && params[qop].getValue().equalsIgnoreCase("auth-int") &&
636         req.getStream() == null)
637     {
638         MD5 entity_hash = new MD5();
639         entity_hash.Update(req.getData() == null ? NUL : req.getData());
640         hash = entity_hash.asHex();
641     }
642
643     if (req.getStream() == null)
644         params[response] = new NVPair("response",
645           calcResponseAttr(hash, extra, params, alg, uri, qop, nonce,
646                    nc, cnonce, req.getMethod()));
647
648
649     // calc digest if necessary
650

651     AuthorizationInfo new_info;
652
653     boolean ch_dreq_val = false;
654     if (ch_dreq != -1 &&
655         (ch_params[ch_dreq].getValue() == null ||
656          ch_params[ch_dreq].getValue().equalsIgnoreCase("true")))
657         ch_dreq_val = true;
658
659     if ((ch_dreq_val || digest != -1) && req.getStream() == null)
660     {
661         NVPair[] d_params;
662         if (digest == -1)
663         {
664         d_params = Util.resizeArray(params, params.length+1);
665         digest = params.length;
666         }
667         else
668         d_params = params;
669         d_params[digest] = new NVPair("digest",
670            calc_digest(req, extra[DI_A1], params[nonce].getValue()));
671
672         if (dreq == -1) // if server requires digest, then so do we...
673
{
674         dreq = d_params.length;
675         d_params = Util.resizeArray(d_params, d_params.length+1);
676         d_params[dreq] = new NVPair("digest-required", "true");
677         }
678
679         new_info = new AuthorizationInfo(info.getHost(), info.getPort(),
680                          info.getScheme(), info.getRealm(),
681                          d_params, extra);
682     }
683     else if (ch_dreq_val)
684         new_info = null;
685     else
686         new_info = new AuthorizationInfo(info.getHost(), info.getPort(),
687                          info.getScheme(), info.getRealm(),
688                          params, extra);
689
690
691     // add info for other domains, if listed
692

693     boolean from_server = (challenge != null) &&
694         challenge.getHost().equalsIgnoreCase(req.getConnection().getHost());
695     if (ch_domain != -1)
696     {
697         URI base = null;
698         try
699         {
700         base = new URI(req.getConnection().getProtocol(),
701                    req.getConnection().getHost(),
702                    req.getConnection().getPort(),
703                    req.getRequestURI());
704         }
705         catch (ParseException pe)
706         { }
707
708         StringTokenizer JavaDoc tok =
709             new StringTokenizer JavaDoc(ch_params[ch_domain].getValue());
710         while (tok.hasMoreTokens())
711         {
712         URI Uri;
713         try
714             { Uri = new URI(base, tok.nextToken()); }
715         catch (ParseException pe)
716             { continue; }
717
718         AuthorizationInfo tmp =
719             AuthorizationInfo.getAuthorization(Uri.getHost(),
720                                Uri.getPort(),
721                                info.getScheme(),
722                                info.getRealm(),
723                          req.getConnection().getContext());
724         if (tmp == null)
725         {
726             params[uri] = new NVPair("uri", Uri.getPath());
727             tmp = new AuthorizationInfo(Uri.getHost(), Uri.getPort(),
728                             info.getScheme(),
729                         info.getRealm(), params,
730                         extra);
731             AuthorizationInfo.addAuthorization(tmp);
732         }
733         if (from_server)
734             tmp.addPath(Uri.getPath());
735         }
736     }
737     else if (from_server && challenge != null)
738     {
739         // Spec says that if no domain attribute is present then the
740
// whole server should be considered being in the same space
741
AuthorizationInfo tmp =
742         AuthorizationInfo.getAuthorization(challenge.getHost(),
743                            challenge.getPort(),
744                            info.getScheme(),
745                            info.getRealm(),
746                          req.getConnection().getContext());
747         if (tmp != null) tmp.addPath("/");
748     }
749
750
751     // now return the one to use
752

753     return new_info;
754     }
755
756
757     /**
758      * @return the fixed info is stale=true; null otherwise
759      */

760     private static AuthorizationInfo digest_check_stale(
761                           AuthorizationInfo challenge,
762                           RoRequest req, RoResponse resp)
763         throws AuthSchemeNotImplException
764     {
765     AuthorizationInfo cred = null;
766
767     NVPair[] params = challenge.getParams();
768     for (int idx=0; idx<params.length; idx++)
769     {
770         String JavaDoc name = params[idx].getName();
771         if (name.equalsIgnoreCase("stale") &&
772         params[idx].getValue().equalsIgnoreCase("true"))
773         {
774         cred = AuthorizationInfo.getAuthorization(challenge, req, resp,
775                               false);
776         if (cred != null) // should always be the case
777
return digest_fixup(cred, req, challenge, resp);
778         break; // should never be reached
779
}
780     }
781
782     return cred;
783     }
784
785
786     /**
787      * Handle nextnonce field.
788      */

789     private static boolean handle_nextnonce(AuthorizationInfo prev,
790                         RoRequest req,
791                         HttpHeaderElement nextnonce)
792     {
793     if (prev == null || nextnonce == null ||
794         nextnonce.getValue() == null)
795         return false;
796
797     AuthorizationInfo ai;
798     try
799         { ai = AuthorizationInfo.getAuthorization(prev, req, null, false); }
800     catch (AuthSchemeNotImplException asnie)
801         { ai = prev; /* shouldn't happen */ }
802     synchronized(ai)
803     {
804         NVPair[] params = ai.getParams();
805         params = setValue(params, "nonce", nextnonce.getValue());
806         params = setValue(params, "nc", "00000000");
807         ai.setParams(params);
808     }
809
810     return true;
811     }
812
813
814     /**
815      * Handle digest field of the Authentication-Info response header.
816      */

817     private static boolean handle_digest(AuthorizationInfo prev, Response resp,
818                      RoRequest req, String JavaDoc hdr_name)
819         throws IOException JavaDoc
820     {
821     if (prev == null)
822         return false;
823
824     NVPair[] params = prev.getParams();
825     VerifyDigest
826         verifier = new VerifyDigest(((String JavaDoc[]) prev.getExtraInfo())[0],
827                     getValue(params, "nonce"),
828                     req.getMethod(),
829                     getValue(params, "uri"),
830                     hdr_name, resp);
831
832     if (resp.hasEntity())
833     {
834         if (DebugAuth)
835         System.err.println("Auth: pushing md5-check-stream to verify "+
836                    "digest from " + hdr_name);
837         resp.inp_stream = new MD5InputStream(resp.inp_stream, verifier);
838     }
839     else
840     {
841         if (DebugAuth)
842         System.err.println("Auth: verifying digest from " + hdr_name);
843         verifier.verifyHash(new MD5().Final(), 0);
844     }
845
846     return true;
847     }
848
849
850     /**
851      * Handle rspauth field of the Authentication-Info response header.
852      */

853     private static boolean handle_rspauth(AuthorizationInfo prev, Response resp,
854                       RoRequest req, Vector JavaDoc auth_info,
855                       String JavaDoc hdr_name)
856         throws IOException JavaDoc
857     {
858     if (prev == null)
859         return false;
860
861
862     // get the parameters we sent
863

864     NVPair[] params = prev.getParams();
865     int uri=-1, alg=-1, nonce=-1, cnonce=-1, nc=-1;
866     for (int idx=0; idx<params.length; idx++)
867     {
868         String JavaDoc name = params[idx].getName().toLowerCase();
869         if (name.equals("uri")) uri = idx;
870         else if (name.equals("algorithm")) alg = idx;
871         else if (name.equals("nonce")) nonce = idx;
872         else if (name.equals("cnonce")) cnonce = idx;
873         else if (name.equals("nc")) nc = idx;
874     }
875
876
877     // create hash verifier to verify rspauth
878

879     VerifyRspAuth
880         verifier = new VerifyRspAuth(params[uri].getValue(),
881                   ((String JavaDoc[]) prev.getExtraInfo())[0],
882                   (alg == -1 ? null : params[alg].getValue()),
883                           params[nonce].getValue(),
884                   (cnonce == -1 ? "" : params[cnonce].getValue()),
885                   (nc == -1 ? "" : params[nc].getValue()),
886                   hdr_name, resp);
887
888
889     // if Authentication-Info in header and qop=auth then verify immediately
890

891     HttpHeaderElement qop = null;
892     if (auth_info != null &&
893         (qop = Util.getElement(auth_info, "qop")) != null &&
894         qop.getValue() != null &&
895         (qop.getValue().equalsIgnoreCase("auth") ||
896          !resp.hasEntity() && qop.getValue().equalsIgnoreCase("auth-int"))
897        )
898     {
899         if (DebugAuth)
900         System.err.println("Auth: verifying rspauth from " + hdr_name);
901         verifier.verifyHash(new MD5().Final(), 0);
902     }
903     else
904     {
905         // else push md5 stream and verify after body
906

907         if (DebugAuth)
908         System.err.println("Auth: pushing md5-check-stream to verify "+
909                    "rspauth from " + hdr_name);
910         resp.inp_stream = new MD5InputStream(resp.inp_stream, verifier);
911     }
912
913     return true;
914     }
915
916
917     /**
918      * Calc "response" attribute for a request.
919      */

920     private static String JavaDoc calcResponseAttr(String JavaDoc hash, String JavaDoc[] extra,
921                        NVPair[] params, int alg,
922                        int uri, int qop, int nonce,
923                        int nc, int cnonce, String JavaDoc method)
924     {
925     String JavaDoc A1, A2, resp_val;
926
927     if (alg != -1 &&
928         params[alg].getValue().equalsIgnoreCase("MD5-sess"))
929         A1 = extra[DI_A1S];
930     else
931         A1 = extra[DI_A1];
932
933     A2 = method + ":" + params[uri].getValue();
934     if (qop != -1 &&
935         params[qop].getValue().equalsIgnoreCase("auth-int"))
936     {
937         A2 += ":" + hash;
938     }
939     A2 = new MD5(A2).asHex();
940
941     if (qop == -1)
942         resp_val = new MD5(A1 + ":" + params[nonce].getValue() + ":" +
943                    A2).asHex();
944     else
945         resp_val =
946         new MD5(A1 + ":" + params[nonce].getValue() + ":" +
947             params[nc].getValue() + ":" +
948             params[cnonce].getValue() + ":" +
949             params[qop].getValue() + ":" + A2).asHex();
950
951     return resp_val;
952     }
953
954
955     /**
956      * Calculates the digest of the request body. This was in RFC-2069
957      * and draft-ietf-http-authentication-00.txt, but has subsequently
958      * been removed. Here for backwards compatibility.
959      */

960     private static String JavaDoc calc_digest(RoRequest req, String JavaDoc A1_hash,
961                       String JavaDoc nonce)
962     {
963     if (req.getStream() != null)
964         return "";
965
966     int ct=-1, ce=-1, lm=-1, ex=-1, dt=-1;
967     for (int idx=0; idx<req.getHeaders().length; idx++)
968     {
969         String JavaDoc name = req.getHeaders()[idx].getName();
970         if (name.equalsIgnoreCase("Content-type"))
971         ct = idx;
972         else if (name.equalsIgnoreCase("Content-Encoding"))
973         ce = idx;
974         else if (name.equalsIgnoreCase("Last-Modified"))
975         lm = idx;
976         else if (name.equalsIgnoreCase("Expires"))
977         ex = idx;
978         else if (name.equalsIgnoreCase("Date"))
979         dt = idx;
980     }
981
982
983     NVPair[] hdrs = req.getHeaders();
984     byte[] entity_body = (req.getData() == null ? NUL : req.getData());
985     MD5 entity_hash = new MD5();
986     entity_hash.Update(entity_body);
987
988     String JavaDoc entity_info = new MD5(req.getRequestURI() + ":" +
989          (ct == -1 ? "" : hdrs[ct].getValue()) + ":" +
990          entity_body.length + ":" +
991          (ce == -1 ? "" : hdrs[ce].getValue()) + ":" +
992          (lm == -1 ? "" : hdrs[lm].getValue()) + ":" +
993          (ex == -1 ? "" : hdrs[ex].getValue())).asHex();
994     String JavaDoc entity_digest = A1_hash + ":" + nonce + ":" + req.getMethod() +
995             ":" + (dt == -1 ? "" : hdrs[dt].getValue()) +
996             ":" + entity_info + ":" + entity_hash.asHex();
997
998     if (DebugAuth)
999     {
1000        System.err.println("Auth: Entity-Info: '" + req.getRequestURI() + ":" +
1001         (ct == -1 ? "" : hdrs[ct].getValue()) + ":" +
1002         entity_body.length + ":" +
1003         (ce == -1 ? "" : hdrs[ce].getValue()) + ":" +
1004         (lm == -1 ? "" : hdrs[lm].getValue()) + ":" +
1005         (ex == -1 ? "" : hdrs[ex].getValue()) +"'");
1006        System.err.println("Auth: Entity-Body: '" + entity_hash.asHex() + "'");
1007        System.err.println("Auth: Entity-Digest: '" + entity_digest + "'");
1008    }
1009
1010    return new MD5(entity_digest).asHex();
1011    }
1012
1013
1014    /**
1015     * Handle discard token
1016     */

1017    private static boolean handle_discard(AuthorizationInfo prev, RoRequest req,
1018                      HttpHeaderElement discard)
1019    {
1020    if (discard != null && prev != null)
1021    {
1022        AuthorizationInfo.removeAuthorization(prev,
1023                        req.getConnection().getContext());
1024        return true;
1025    }
1026
1027    return false;
1028    }
1029
1030
1031    /**
1032     * Generate <var>num</var> bytes of random data.
1033     *
1034     * @param num the number of bytes to generate
1035     * @return a byte array of random data
1036     */

1037    private static byte[] gen_random_bytes(int num)
1038    {
1039    // first try /dev/random
1040
try
1041    {
1042        FileInputStream JavaDoc rnd = new FileInputStream JavaDoc("/dev/random");
1043        DataInputStream JavaDoc din = new DataInputStream JavaDoc(rnd);
1044        byte[] data = new byte[num];
1045        din.readFully(data);
1046        try { din.close(); } catch (IOException JavaDoc ioe) { }
1047        return data;
1048    }
1049    catch (Throwable JavaDoc t)
1050        { }
1051
1052    /* This is probably a much better generator, but it can be awfully
1053     * slow (~ 6 secs / byte on my old LX)
1054     */

1055    //return new java.security.SecureRandom().getSeed(num);
1056

1057    /* this is faster, but needs to be done better... */
1058    byte[] data = new byte[num];
1059    try
1060    {
1061        long fm = Runtime.getRuntime().freeMemory();
1062        data[0] = (byte) (fm & 0xFF);
1063        data[1] = (byte) ((fm >> 8) & 0xFF);
1064
1065        int h = data.hashCode();
1066        data[2] = (byte) (h & 0xFF);
1067        data[3] = (byte) ((h >> 8) & 0xFF);
1068        data[4] = (byte) ((h >> 16) & 0xFF);
1069        data[5] = (byte) ((h >> 24) & 0xFF);
1070
1071        long time = System.currentTimeMillis();
1072        data[6] = (byte) (time & 0xFF);
1073        data[7] = (byte) ((time >> 8) & 0xFF);
1074    }
1075    catch (ArrayIndexOutOfBoundsException JavaDoc aioobe)
1076        { }
1077
1078    return data;
1079    }
1080
1081
1082    /**
1083     * Return the value of the first NVPair whose name matches the key
1084     * using a case-insensitive search.
1085     *
1086     * @param list an array of NVPair's
1087     * @param key the key to search for
1088     * @return the value of the NVPair with that key, or null if not
1089     * found.
1090     */

1091    private final static String JavaDoc getValue(NVPair[] list, String JavaDoc key)
1092    {
1093    int len = list.length;
1094
1095    for (int idx=0; idx<len; idx++)
1096        if (list[idx].getName().equalsIgnoreCase(key))
1097        return list[idx].getValue();
1098
1099    return null;
1100    }
1101
1102    /**
1103     * Return the index of the first NVPair whose name matches the key
1104     * using a case-insensitive search.
1105     *
1106     * @param list an array of NVPair's
1107     * @param key the key to search for
1108     * @return the index of the NVPair with that key, or -1 if not
1109     * found.
1110     */

1111    private final static int getIndex(NVPair[] list, String JavaDoc key)
1112    {
1113    int len = list.length;
1114
1115    for (int idx=0; idx<len; idx++)
1116        if (list[idx].getName().equalsIgnoreCase(key))
1117        return idx;
1118
1119    return -1;
1120    }
1121
1122    /**
1123     * Sets the value of the NVPair with the name that matches the key
1124     * (case-insensitive). If no name matches, a new entry is created.
1125     *
1126     * @param list an array of NVPair's
1127     * @param key the name of the NVPair
1128     * @param val the value of the new NVPair
1129     * @return the (possibly) new list
1130     */

1131    private final static NVPair[] setValue(NVPair[] list, String JavaDoc key, String JavaDoc val)
1132    {
1133    int idx = getIndex(list, key);
1134    if (idx == -1)
1135    {
1136        idx = list.length;
1137        list = Util.resizeArray(list, list.length+1);
1138    }
1139
1140    list[idx] = new NVPair(key, val);
1141    return list;
1142    }
1143
1144
1145    /**
1146     * Split a list into an array of Strings, using sep as the
1147     * separator and removing whitespace around the separator.
1148     */

1149    private static String JavaDoc[] splitList(String JavaDoc str, String JavaDoc sep)
1150    {
1151    if (str == null) return new String JavaDoc[0];
1152
1153    StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(str, sep);
1154    String JavaDoc[] list = new String JavaDoc[tok.countTokens()];
1155    for (int idx=0; idx<list.length; idx++)
1156        list[idx] = tok.nextToken().trim();
1157
1158    return list;
1159    }
1160
1161
1162    /**
1163     * Produce a string of the form "A5:22:F1:0B:53"
1164     */

1165    static String JavaDoc hex(byte[] buf)
1166    {
1167    StringBuffer JavaDoc str = new StringBuffer JavaDoc(buf.length*3);
1168    for (int idx=0; idx<buf.length; idx++)
1169    {
1170        str.append(Character.forDigit(buf[idx] >>> 4, 16));
1171        str.append(Character.forDigit(buf[idx] & 16, 16));
1172        str.append(':');
1173    }
1174    str.setLength(str.length()-1);
1175
1176    return str.toString();
1177    }
1178
1179
1180    static final byte[] unHex(String JavaDoc hex)
1181    {
1182    byte[] digest = new byte[hex.length()/2];
1183
1184    for (int idx=0; idx<digest.length; idx++)
1185    {
1186        digest[idx] = (byte) (0xFF & Integer.parseInt(
1187                  hex.substring(2*idx, 2*(idx+1)), 16));
1188    }
1189
1190    return digest;
1191    }
1192}
1193
1194
1195/**
1196 * This verifies the "rspauth" from draft-ietf-http-authentication-03
1197 */

1198class VerifyRspAuth implements HashVerifier, GlobalConstants
1199{
1200    private String JavaDoc uri;
1201    private String JavaDoc HA1;
1202    private String JavaDoc alg;
1203    private String JavaDoc nonce;
1204    private String JavaDoc cnonce;
1205    private String JavaDoc nc;
1206    private String JavaDoc hdr;
1207    private RoResponse resp;
1208
1209
1210    public VerifyRspAuth(String JavaDoc uri, String JavaDoc HA1, String JavaDoc alg, String JavaDoc nonce,
1211             String JavaDoc cnonce, String JavaDoc nc, String JavaDoc hdr, RoResponse resp)
1212    {
1213    this.uri = uri;
1214    this.HA1 = HA1;
1215    this.alg = alg;
1216    this.nonce = nonce;
1217    this.cnonce = cnonce;
1218    this.nc = nc;
1219    this.hdr = hdr;
1220    this.resp = resp;
1221    }
1222
1223
1224    public void verifyHash(byte[] hash, long len) throws IOException JavaDoc
1225    {
1226    String JavaDoc auth_info = resp.getHeader(hdr);
1227    if (auth_info == null)
1228        auth_info = resp.getTrailer(hdr);
1229    if (auth_info == null)
1230        return;
1231
1232    Vector JavaDoc pai;
1233    try
1234        { pai = Util.parseHeader(auth_info); }
1235    catch (ParseException pe)
1236        { throw new IOException JavaDoc(pe.toString()); }
1237
1238    String JavaDoc qop;
1239    HttpHeaderElement elem = Util.getElement(pai, "qop");
1240    if (elem == null || (qop = elem.getValue()) == null ||
1241        (!qop.equalsIgnoreCase("auth") &&
1242         !qop.equalsIgnoreCase("auth-int")))
1243        return;
1244
1245    elem = Util.getElement(pai, "rspauth");
1246    if (elem == null || elem.getValue() == null) return;
1247    byte[] digest = DefaultAuthHandler.unHex(elem.getValue());
1248
1249    elem = Util.getElement(pai, "cnonce");
1250    if (elem != null && elem.getValue() != null &&
1251        !elem.getValue().equals(cnonce))
1252        throw new IOException JavaDoc("Digest auth scheme: received wrong " +
1253                  "client-nonce '" + elem.getValue() +
1254                  "' - expected '" + cnonce + "'");
1255
1256    elem = Util.getElement(pai, "nc");
1257    if (elem != null && elem.getValue() != null &&
1258        !elem.getValue().equals(nc))
1259        throw new IOException JavaDoc("Digest auth scheme: received wrong " +
1260                  "nonce-count '" + elem.getValue() +
1261                  "' - expected '" + nc + "'");
1262
1263    String JavaDoc A1, A2;
1264    if (alg != null && alg.equalsIgnoreCase("MD5-sess"))
1265        A1 = new MD5(HA1 + ":" + nonce + ":" + cnonce).asHex();
1266    else
1267        A1 = HA1;
1268
1269    // draft-01 was: A2 = resp.getStatusCode() + ":" + uri;
1270
A2 = ":" + uri;
1271    if (qop.equalsIgnoreCase("auth-int"))
1272        A2 += ":" + MD5.asHex(hash);
1273    A2 = new MD5(A2).asHex();
1274
1275    hash = new MD5(A1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" +
1276               qop + ":" + A2).Final();
1277
1278    for (int idx=0; idx<hash.length; idx++)
1279    {
1280        if (hash[idx] != digest[idx])
1281        throw new IOException JavaDoc("MD5-Digest mismatch: expected " +
1282                      DefaultAuthHandler.hex(digest) +
1283                      " but calculated " +
1284                      DefaultAuthHandler.hex(hash));
1285    }
1286
1287    if (DebugAuth)
1288        System.err.println("Auth: rspauth from " + hdr +
1289                   " successfully verified");
1290    }
1291}
1292
1293
1294/**
1295 * This verifies the "digest" from rfc-2069
1296 */

1297class VerifyDigest implements HashVerifier, GlobalConstants
1298{
1299    private String JavaDoc HA1;
1300    private String JavaDoc nonce;
1301    private String JavaDoc method;
1302    private String JavaDoc uri;
1303    private String JavaDoc hdr;
1304    private RoResponse resp;
1305
1306
1307    public VerifyDigest(String JavaDoc HA1, String JavaDoc nonce, String JavaDoc method, String JavaDoc uri,
1308            String JavaDoc hdr, RoResponse resp)
1309    {
1310    this.HA1 = HA1;
1311    this.nonce = nonce;
1312    this.method = method;
1313    this.uri = uri;
1314    this.hdr = hdr;
1315    this.resp = resp;
1316    }
1317
1318
1319    public void verifyHash(byte[] hash, long len) throws IOException JavaDoc
1320    {
1321    String JavaDoc auth_info = resp.getHeader(hdr);
1322    if (auth_info == null)
1323        auth_info = resp.getTrailer(hdr);
1324    if (auth_info == null)
1325        return;
1326
1327    Vector JavaDoc pai;
1328    try
1329        { pai = Util.parseHeader(auth_info); }
1330    catch (ParseException pe)
1331        { throw new IOException JavaDoc(pe.toString()); }
1332    HttpHeaderElement elem = Util.getElement(pai, "digest");
1333    if (elem == null || elem.getValue() == null)
1334        return;
1335
1336    byte[] digest = DefaultAuthHandler.unHex(elem.getValue());
1337
1338    String JavaDoc entity_info = new MD5(
1339                uri + ":" +
1340                header_val("Content-Type", resp) + ":" +
1341                header_val("Content-Length", resp) + ":" +
1342                header_val("Content-Encoding", resp) + ":" +
1343                header_val("Last-Modified", resp) + ":" +
1344                header_val("Expires", resp)).asHex();
1345    hash = new MD5(HA1 + ":" + nonce + ":" + method + ":" +
1346               header_val("Date", resp) +
1347               ":" + entity_info + ":" + MD5.asHex(hash)).Final();
1348
1349    for (int idx=0; idx<hash.length; idx++)
1350    {
1351        if (hash[idx] != digest[idx])
1352        throw new IOException JavaDoc("MD5-Digest mismatch: expected " +
1353                      DefaultAuthHandler.hex(digest) +
1354                      " but calculated " +
1355                      DefaultAuthHandler.hex(hash));
1356    }
1357
1358    if (DebugAuth)
1359        System.err.println("Auth: digest from " + hdr +
1360                   " successfully verified");
1361    }
1362
1363
1364    private static final String JavaDoc header_val(String JavaDoc hdr_name, RoResponse resp)
1365        throws IOException JavaDoc
1366    {
1367    String JavaDoc hdr = resp.getHeader(hdr_name);
1368    String JavaDoc tlr = resp.getTrailer(hdr_name);
1369    return (hdr != null ? hdr : (tlr != null ? tlr : ""));
1370    }
1371}
1372
1373
1374/**
1375 * This class implements a simple popup that request username and password
1376 * used for the "basic" and "digest" authentication schemes.
1377 *
1378 * @version 0.3-2 18/06/1999
1379 * @author Ronald Tschalär
1380 */

1381class BasicAuthBox extends Frame JavaDoc
1382{
1383    private final static String JavaDoc title = "Authorization Request";
1384    private Dimension JavaDoc screen;
1385    private Label JavaDoc line1, line2, line3;
1386    private TextField JavaDoc user, pass;
1387    private int done;
1388    private final static int OK = 1, CANCEL = 0;
1389
1390
1391    /**
1392     * Constructs the popup with two lines of text above the input fields
1393     */

1394    BasicAuthBox()
1395    {
1396    super(title);
1397
1398        screen = getToolkit().getScreenSize();
1399
1400    addNotify();
1401    addWindowListener(new Close());
1402    setLayout(new BorderLayout JavaDoc());
1403
1404    Panel JavaDoc p = new Panel JavaDoc(new GridLayout JavaDoc(3,1));
1405    p.add(line1 = new Label JavaDoc());
1406    p.add(line2 = new Label JavaDoc());
1407    p.add(line3 = new Label JavaDoc());
1408    add("North", p);
1409
1410    p = new Panel JavaDoc(new GridLayout JavaDoc(2,1));
1411    p.add(new Label JavaDoc("Username:"));
1412    p.add(new Label JavaDoc("Password:"));
1413    add("West", p);
1414    p = new Panel JavaDoc(new GridLayout JavaDoc(2,1));
1415    p.add(user = new TextField JavaDoc(30));
1416    p.add(pass = new TextField JavaDoc(30));
1417    pass.addActionListener(new Ok());
1418    pass.setEchoChar('*');
1419    add("East", p);
1420
1421    GridBagLayout JavaDoc gb = new GridBagLayout JavaDoc();
1422    p = new Panel JavaDoc(gb);
1423    GridBagConstraints JavaDoc constr = new GridBagConstraints JavaDoc();
1424    Panel JavaDoc pp = new Panel JavaDoc();
1425    p.add(pp);
1426    constr.gridwidth = GridBagConstraints.REMAINDER;
1427    gb.setConstraints(pp, constr);
1428    constr.gridwidth = 1;
1429    constr.weightx = 1.0;
1430    Button JavaDoc b;
1431    p.add(b = new Button JavaDoc(" OK "));
1432    b.addActionListener(new Ok());
1433    constr.weightx = 1.0;
1434    gb.setConstraints(b, constr);
1435    p.add(b = new Button JavaDoc("Clear"));
1436    b.addActionListener(new Clear());
1437    constr.weightx = 2.0;
1438    gb.setConstraints(b, constr);
1439    p.add(b = new Button JavaDoc("Cancel"));
1440    b.addActionListener(new Cancel());
1441    constr.weightx = 1.0;
1442    gb.setConstraints(b, constr);
1443    add("South", p);
1444
1445    pack();
1446    setResizable(false);
1447    }
1448
1449
1450    /**
1451     * our event handlers
1452     */

1453    private class Ok implements ActionListener JavaDoc
1454    {
1455    public void actionPerformed(ActionEvent JavaDoc ae)
1456    {
1457        done = OK;
1458        synchronized (BasicAuthBox.this) { BasicAuthBox.this.notifyAll(); }
1459    }
1460    }
1461
1462    private class Clear implements ActionListener JavaDoc
1463    {
1464    public void actionPerformed(ActionEvent JavaDoc ae)
1465    {
1466        user.setText("");
1467        pass.setText("");
1468        user.requestFocus();
1469    }
1470    }
1471
1472    private class Cancel implements ActionListener JavaDoc
1473    {
1474    public void actionPerformed(ActionEvent JavaDoc ae)
1475    {
1476        done = CANCEL;
1477        synchronized (BasicAuthBox.this) { BasicAuthBox.this.notifyAll(); }
1478    }
1479    }
1480
1481
1482    private class Close extends WindowAdapter JavaDoc
1483    {
1484    public void windowClosing(WindowEvent JavaDoc we)
1485    {
1486        new Cancel().actionPerformed(null);
1487    }
1488    }
1489
1490
1491    /**
1492     * the method called by DefaultAuthHandler.
1493     *
1494     * @return the username/password pair
1495     */

1496    synchronized NVPair getInput(String JavaDoc l1, String JavaDoc l2, String JavaDoc l3)
1497    {
1498    line1.setText(l1);
1499    line2.setText(l2);
1500    line3.setText(l3);
1501
1502    line1.invalidate();
1503    line2.invalidate();
1504    line3.invalidate();
1505
1506    setResizable(true);
1507    pack();
1508    setResizable(false);
1509    setLocation((screen.width-getPreferredSize().width)/2,
1510            (int) ((screen.height-getPreferredSize().height)/2*.7));
1511    user.requestFocus();
1512    setVisible(true);
1513
1514    try { wait(); } catch (InterruptedException JavaDoc e) { }
1515
1516    setVisible(false);
1517
1518    NVPair result = new NVPair(user.getText(), pass.getText());
1519    user.setText("");
1520    pass.setText("");
1521
1522    if (done == CANCEL)
1523        return null;
1524    else
1525        return result;
1526    }
1527}
1528
1529
Popular Tags