Source Code Cross Referenced for DefaultAuthHandler.java in  » Net » SkunkDAV » HTTPClient » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » SkunkDAV » HTTPClient 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * @(#)DefaultAuthHandler.java				0.3-2 18/06/1999
0003:         *
0004:         *  This file is part of the HTTPClient package
0005:         *  Copyright (C) 1996-1999  Ronald Tschalär
0006:         *
0007:         *  This library is free software; you can redistribute it and/or
0008:         *  modify it under the terms of the GNU Lesser General Public
0009:         *  License as published by the Free Software Foundation; either
0010:         *  version 2 of the License, or (at your option) any later version.
0011:         *
0012:         *  This library is distributed in the hope that it will be useful,
0013:         *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015:         *  Lesser General Public License for more details.
0016:         *
0017:         *  You should have received a copy of the GNU Lesser General Public
0018:         *  License along with this library; if not, write to the Free
0019:         *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
0020:         *  MA 02111-1307, USA
0021:         *
0022:         *  For questions, suggestions, bug-reports, enhancement-requests etc.
0023:         *  I may be contacted at:
0024:         *
0025:         *  ronald@innovation.ch
0026:         *
0027:         */
0028:
0029:        package HTTPClient;
0030:
0031:        import java.io.IOException;
0032:        import java.io.FileInputStream;
0033:        import java.io.DataInputStream;
0034:        import java.util.Vector;
0035:        import java.util.StringTokenizer;
0036:
0037:        import java.awt.Frame;
0038:        import java.awt.Panel;
0039:        import java.awt.Label;
0040:        import java.awt.Button;
0041:        import java.awt.Dimension;
0042:        import java.awt.TextField;
0043:        import java.awt.GridLayout;
0044:        import java.awt.BorderLayout;
0045:        import java.awt.GridBagLayout;
0046:        import java.awt.GridBagConstraints;
0047:        import java.awt.event.ActionEvent;
0048:        import java.awt.event.ActionListener;
0049:        import java.awt.event.WindowEvent;
0050:        import java.awt.event.WindowAdapter;
0051:
0052:        /**
0053:         * A simple authorization handler that throws up a message box requesting
0054:         * both a username and password. This is default authorization handler.
0055:         * Currently only handles the authentication types "Basic", "Digest" and
0056:         * "SOCKS5" (used for the SocksClient and not part of HTTP per se).
0057:         *
0058:         * @version	0.3-2  18/06/1999
0059:         * @author	Ronald Tschalär
0060:         * @since	V0.2
0061:         */
0062:
0063:        class DefaultAuthHandler implements  AuthorizationHandler,
0064:                GlobalConstants {
0065:            private static final byte[] NUL = new byte[0];
0066:
0067:            private static final int DI_A1 = 0;
0068:            private static final int DI_A1S = 1;
0069:            private static final int DI_QOP = 2;
0070:
0071:            private static byte[] digest_secret = null;
0072:
0073:            private BasicAuthBox inp = null;
0074:
0075:            /**
0076:             * For Digest authentication we need to set the uri, response and
0077:             * opaque parameters. For "Basic" and "SOCKS5" nothing is done.
0078:             */
0079:            public AuthorizationInfo fixupAuthInfo(AuthorizationInfo info,
0080:                    RoRequest req, AuthorizationInfo challenge, RoResponse resp)
0081:                    throws AuthSchemeNotImplException {
0082:                // nothing to do for Basic and SOCKS5 schemes
0083:
0084:                if (info.getScheme().equalsIgnoreCase("Basic")
0085:                        || info.getScheme().equalsIgnoreCase("SOCKS5"))
0086:                    return info;
0087:                else if (!info.getScheme().equalsIgnoreCase("Digest"))
0088:                    throw new AuthSchemeNotImplException(info.getScheme());
0089:
0090:                if (DebugAuth)
0091:                    System.err
0092:                            .println("Auth:  fixing up Authorization for host "
0093:                                    + info.getHost() + ":" + info.getPort()
0094:                                    + "; scheme: " + info.getScheme()
0095:                                    + "; realm: " + info.getRealm());
0096:
0097:                return digest_fixup(info, req, challenge, resp);
0098:            }
0099:
0100:            /**
0101:             * returns the requested authorization, or null if none was given.
0102:             *
0103:             * @param challenge the parsed challenge from the server.
0104:             * @param req the request which solicited this response
0105:             * @param resp the full response received
0106:             * @return a structure containing the necessary authorization info,
0107:             *         or null
0108:             * @exception AuthSchemeNotImplException if the authentication scheme
0109:             *             in the challenge cannot be handled.
0110:             */
0111:            public AuthorizationInfo getAuthorization(
0112:                    AuthorizationInfo challenge, RoRequest req, RoResponse resp)
0113:                    throws AuthSchemeNotImplException {
0114:                AuthorizationInfo cred;
0115:
0116:                if (DebugAuth)
0117:                    System.err
0118:                            .println("Auth:  Requesting Authorization for host "
0119:                                    + challenge.getHost()
0120:                                    + ":"
0121:                                    + challenge.getPort()
0122:                                    + "; scheme: "
0123:                                    + challenge.getScheme()
0124:                                    + "; realm: "
0125:                                    + challenge.getRealm());
0126:
0127:                // we only handle Basic, Digest and SOCKS5 authentication
0128:
0129:                if (!challenge.getScheme().equalsIgnoreCase("Basic")
0130:                        && !challenge.getScheme().equalsIgnoreCase("Digest")
0131:                        && !challenge.getScheme().equalsIgnoreCase("SOCKS5"))
0132:                    throw new AuthSchemeNotImplException(challenge.getScheme());
0133:
0134:                // For digest authentication, check if stale is set
0135:
0136:                if (challenge.getScheme().equalsIgnoreCase("Digest")) {
0137:                    cred = digest_check_stale(challenge, req, resp);
0138:                    if (cred != null)
0139:                        return cred;
0140:                }
0141:
0142:                // Ask the user for username/password
0143:
0144:                if (!req.allowUI())
0145:                    return null;
0146:
0147:                if (inp == null) {
0148:                    synchronized (getClass()) {
0149:                        if (inp == null)
0150:                            inp = new BasicAuthBox();
0151:                    }
0152:                }
0153:
0154:                NVPair answer;
0155:                if (challenge.getScheme().equalsIgnoreCase("basic")
0156:                        || challenge.getScheme().equalsIgnoreCase("Digest")) {
0157:                    answer = inp.getInput(
0158:                            "Enter username and password for realm `"
0159:                                    + challenge.getRealm() + "'", "on host "
0160:                                    + challenge.getHost() + ":"
0161:                                    + challenge.getPort(),
0162:                            "Authentication Scheme: " + challenge.getScheme());
0163:                } else {
0164:                    answer = inp.getInput(
0165:                            "Enter username and password for SOCKS "
0166:                                    + "server on host ", challenge.getHost(),
0167:                            "Authentication Method: username/password");
0168:                }
0169:
0170:                if (answer == null)
0171:                    return null;
0172:
0173:                // Now process the username/password
0174:
0175:                if (challenge.getScheme().equalsIgnoreCase("basic")) {
0176:                    cred = new AuthorizationInfo(challenge.getHost(), challenge
0177:                            .getPort(), challenge.getScheme(), challenge
0178:                            .getRealm(), Codecs.base64Encode(answer.getName()
0179:                            + ":" + answer.getValue()));
0180:                } else if (challenge.getScheme().equalsIgnoreCase("Digest")) {
0181:                    cred = digest_gen_auth_info(challenge.getHost(), challenge
0182:                            .getPort(), challenge.getRealm(), answer.getName(),
0183:                            answer.getValue(), req.getConnection().getContext());
0184:                    cred = digest_fixup(cred, req, challenge, null);
0185:                } else // SOCKS5
0186:                {
0187:                    NVPair[] upwd = { answer };
0188:                    cred = new AuthorizationInfo(challenge.getHost(), challenge
0189:                            .getPort(), challenge.getScheme(), challenge
0190:                            .getRealm(), upwd, null);
0191:                }
0192:
0193:                // try to get rid of any unencoded passwords in memory
0194:
0195:                answer = null;
0196:                System.gc();
0197:
0198:                // Done
0199:
0200:                if (DebugAuth)
0201:                    System.err.println("Auth:  Got Authorization");
0202:
0203:                return cred;
0204:            }
0205:
0206:            /**
0207:             * We handle the "Authentication-Info" and "Proxy-Authentication-Info"
0208:             * headers here.
0209:             */
0210:            public void handleAuthHeaders(Response resp, RoRequest req,
0211:                    AuthorizationInfo prev, AuthorizationInfo prxy)
0212:                    throws IOException {
0213:                String auth_info = resp.getHeader("Authentication-Info");
0214:                String prxy_info = resp.getHeader("Proxy-Authentication-Info");
0215:
0216:                if (auth_info == null && prev != null
0217:                        && hasParam(prev.getParams(), "qop", "auth-int"))
0218:                    auth_info = "";
0219:
0220:                if (prxy_info == null && prxy != null
0221:                        && hasParam(prxy.getParams(), "qop", "auth-int"))
0222:                    prxy_info = "";
0223:
0224:                try {
0225:                    handleAuthInfo(auth_info, "Authentication-Info", prev,
0226:                            resp, req, true);
0227:                    handleAuthInfo(prxy_info, "Proxy-Authentication-Info",
0228:                            prxy, resp, req, true);
0229:                } catch (ParseException pe) {
0230:                    throw new IOException(pe.toString());
0231:                }
0232:            }
0233:
0234:            /**
0235:             * We handle the "Authentication-Info" and "Proxy-Authentication-Info"
0236:             * trailers here.
0237:             */
0238:            public void handleAuthTrailers(Response resp, RoRequest req,
0239:                    AuthorizationInfo prev, AuthorizationInfo prxy)
0240:                    throws IOException {
0241:                String auth_info = resp.getTrailer("Authentication-Info");
0242:                String prxy_info = resp.getTrailer("Proxy-Authentication-Info");
0243:
0244:                try {
0245:                    handleAuthInfo(auth_info, "Authentication-Info", prev,
0246:                            resp, req, false);
0247:                    handleAuthInfo(prxy_info, "Proxy-Authentication-Info",
0248:                            prxy, resp, req, false);
0249:                } catch (ParseException pe) {
0250:                    throw new IOException(pe.toString());
0251:                }
0252:            }
0253:
0254:            private static void handleAuthInfo(String auth_info,
0255:                    String hdr_name, AuthorizationInfo prev, Response resp,
0256:                    RoRequest req, boolean in_headers) throws ParseException,
0257:                    IOException {
0258:                if (auth_info == null)
0259:                    return;
0260:
0261:                Vector pai = Util.parseHeader(auth_info);
0262:                HttpHeaderElement elem;
0263:
0264:                if (handle_nextnonce(prev, req, elem = Util.getElement(pai,
0265:                        "nextnonce")))
0266:                    pai.removeElement(elem);
0267:                if (handle_discard(prev, req, elem = Util.getElement(pai,
0268:                        "discard")))
0269:                    pai.removeElement(elem);
0270:
0271:                if (in_headers) {
0272:                    HttpHeaderElement qop = null;
0273:
0274:                    if (pai != null
0275:                            && (qop = Util.getElement(pai, "qop")) != null
0276:                            && qop.getValue() != null) {
0277:                        handle_rspauth(prev, resp, req, pai, hdr_name);
0278:                    } else if (prev != null
0279:                            && (Util.hasToken(resp.getHeader("Trailer"),
0280:                                    hdr_name)
0281:                                    && hasParam(prev.getParams(), "qop", null) || hasParam(
0282:                                    prev.getParams(), "qop", "auth-int"))) {
0283:                        handle_rspauth(prev, resp, req, null, hdr_name);
0284:                    }
0285:
0286:                    else if ((pai != null && qop == null && pai
0287:                            .contains(new HttpHeaderElement("digest")))
0288:                            || (Util.hasToken(resp.getHeader("Trailer"),
0289:                                    hdr_name)
0290:                                    && prev != null && !hasParam(prev
0291:                                    .getParams(), "qop", null))) {
0292:                        handle_digest(prev, resp, req, hdr_name);
0293:                    }
0294:                }
0295:
0296:                if (pai.size() > 0)
0297:                    resp.setHeader(hdr_name, Util.assembleHeader(pai));
0298:                else
0299:                    resp.deleteHeader(hdr_name);
0300:            }
0301:
0302:            private static final boolean hasParam(NVPair[] params, String name,
0303:                    String val) {
0304:                for (int idx = 0; idx < params.length; idx++)
0305:                    if (params[idx].getName().equalsIgnoreCase(name)
0306:                            && (val == null || params[idx].getValue()
0307:                                    .equalsIgnoreCase(val)))
0308:                        return true;
0309:
0310:                return false;
0311:            }
0312:
0313:            /*
0314:             * Here are all the Digest specific methods
0315:             */
0316:
0317:            private static AuthorizationInfo digest_gen_auth_info(String host,
0318:                    int port, String realm, String user, String pass,
0319:                    Object context) {
0320:                String A1 = user + ":" + realm + ":" + pass;
0321:                String[] info = { new MD5(A1).asHex(), null, null };
0322:
0323:                AuthorizationInfo prev = AuthorizationInfo.getAuthorization(
0324:                        host, port, "Digest", realm, context);
0325:                NVPair[] params;
0326:                if (prev == null) {
0327:                    params = new NVPair[4];
0328:                    params[0] = new NVPair("username", user);
0329:                    params[1] = new NVPair("uri", "");
0330:                    params[2] = new NVPair("nonce", "");
0331:                    params[3] = new NVPair("response", "");
0332:                } else {
0333:                    params = prev.getParams();
0334:                    for (int idx = 0; idx < params.length; idx++) {
0335:                        if (params[idx].getName().equalsIgnoreCase("username")) {
0336:                            params[idx] = new NVPair("username", user);
0337:                            break;
0338:                        }
0339:                    }
0340:                }
0341:
0342:                return new AuthorizationInfo(host, port, "Digest", realm,
0343:                        params, info);
0344:            }
0345:
0346:            /**
0347:             * The fixup handler
0348:             */
0349:            private static AuthorizationInfo digest_fixup(
0350:                    AuthorizationInfo info, RoRequest req,
0351:                    AuthorizationInfo challenge, RoResponse resp)
0352:                    throws AuthSchemeNotImplException {
0353:                // get various parameters from challenge
0354:
0355:                int ch_domain = -1, ch_nonce = -1, ch_alg = -1, ch_opaque = -1, ch_stale = -1, ch_dreq = -1, ch_qop = -1;
0356:                NVPair[] ch_params = null;
0357:                if (challenge != null) {
0358:                    ch_params = challenge.getParams();
0359:
0360:                    for (int idx = 0; idx < ch_params.length; idx++) {
0361:                        String name = ch_params[idx].getName().toLowerCase();
0362:                        if (name.equals("domain"))
0363:                            ch_domain = idx;
0364:                        else if (name.equals("nonce"))
0365:                            ch_nonce = idx;
0366:                        else if (name.equals("opaque"))
0367:                            ch_opaque = idx;
0368:                        else if (name.equals("algorithm"))
0369:                            ch_alg = idx;
0370:                        else if (name.equals("stale"))
0371:                            ch_stale = idx;
0372:                        else if (name.equals("digest-required"))
0373:                            ch_dreq = idx;
0374:                        else if (name.equals("qop"))
0375:                            ch_qop = idx;
0376:                    }
0377:                }
0378:
0379:                // get various parameters from info
0380:
0381:                int uri = -1, user = -1, alg = -1, response = -1, nonce = -1, cnonce = -1, nc = -1, opaque = -1, digest = -1, dreq = -1, qop = -1;
0382:                NVPair[] params;
0383:                String[] extra;
0384:
0385:                synchronized (info) // we need to juggle nonce, nc, etc
0386:                {
0387:                    params = info.getParams();
0388:
0389:                    for (int idx = 0; idx < params.length; idx++) {
0390:                        String name = params[idx].getName().toLowerCase();
0391:                        if (name.equals("uri"))
0392:                            uri = idx;
0393:                        else if (name.equals("username"))
0394:                            user = idx;
0395:                        else if (name.equals("algorithm"))
0396:                            alg = idx;
0397:                        else if (name.equals("nonce"))
0398:                            nonce = idx;
0399:                        else if (name.equals("cnonce"))
0400:                            cnonce = idx;
0401:                        else if (name.equals("nc"))
0402:                            nc = idx;
0403:                        else if (name.equals("response"))
0404:                            response = idx;
0405:                        else if (name.equals("opaque"))
0406:                            opaque = idx;
0407:                        else if (name.equals("digest"))
0408:                            digest = idx;
0409:                        else if (name.equals("digest-required"))
0410:                            dreq = idx;
0411:                        else if (name.equals("qop"))
0412:                            qop = idx;
0413:                    }
0414:
0415:                    extra = (String[]) info.getExtraInfo();
0416:
0417:                    // currently only MD5 hash (and "MD5-sess") is supported
0418:
0419:                    if (alg != -1
0420:                            && !params[alg].getValue().equalsIgnoreCase("MD5")
0421:                            && !params[alg].getValue().equalsIgnoreCase(
0422:                                    "MD5-sess"))
0423:                        throw new AuthSchemeNotImplException(
0424:                                "Digest auth scheme: " + "Algorithm "
0425:                                        + params[alg].getValue()
0426:                                        + " not implemented");
0427:
0428:                    if (ch_alg != -1
0429:                            && !ch_params[ch_alg].getValue().equalsIgnoreCase(
0430:                                    "MD5")
0431:                            && !ch_params[ch_alg].getValue().equalsIgnoreCase(
0432:                                    "MD5-sess"))
0433:                        throw new AuthSchemeNotImplException(
0434:                                "Digest auth scheme: " + "Algorithm "
0435:                                        + ch_params[ch_alg].getValue()
0436:                                        + " not implemented");
0437:
0438:                    // fix up uri and nonce
0439:
0440:                    params[uri] = new NVPair("uri", req.getRequestURI());
0441:                    String old_nonce = params[nonce].getValue();
0442:                    if (ch_nonce != -1
0443:                            && !old_nonce
0444:                                    .equals(ch_params[ch_nonce].getValue()))
0445:                        params[nonce] = ch_params[ch_nonce];
0446:
0447:                    // update or add optional attributes (opaque, algorithm, cnonce,
0448:                    // nonce-count, and qop
0449:
0450:                    if (ch_opaque != -1) {
0451:                        if (opaque == -1) {
0452:                            params = Util
0453:                                    .resizeArray(params, params.length + 1);
0454:                            opaque = params.length - 1;
0455:                        }
0456:                        params[opaque] = ch_params[ch_opaque];
0457:                    }
0458:
0459:                    if (ch_alg != -1) {
0460:                        if (alg == -1) {
0461:                            params = Util
0462:                                    .resizeArray(params, params.length + 1);
0463:                            alg = params.length - 1;
0464:                        }
0465:                        params[alg] = ch_params[ch_alg];
0466:                    }
0467:
0468:                    if (ch_qop != -1
0469:                            || (ch_alg != -1 && ch_params[ch_alg].getValue()
0470:                                    .equalsIgnoreCase("MD5-sess"))) {
0471:                        if (cnonce == -1) {
0472:                            params = Util
0473:                                    .resizeArray(params, params.length + 1);
0474:                            cnonce = params.length - 1;
0475:                        }
0476:
0477:                        if (digest_secret == null)
0478:                            digest_secret = gen_random_bytes(20);
0479:
0480:                        long l_time = System.currentTimeMillis();
0481:                        byte[] time = new byte[8];
0482:                        time[0] = (byte) (l_time & 0xFF);
0483:                        time[1] = (byte) ((l_time >> 8) & 0xFF);
0484:                        time[2] = (byte) ((l_time >> 16) & 0xFF);
0485:                        time[3] = (byte) ((l_time >> 24) & 0xFF);
0486:                        time[4] = (byte) ((l_time >> 32) & 0xFF);
0487:                        time[5] = (byte) ((l_time >> 40) & 0xFF);
0488:                        time[6] = (byte) ((l_time >> 48) & 0xFF);
0489:                        time[7] = (byte) ((l_time >> 56) & 0xFF);
0490:
0491:                        MD5 hash = new MD5(digest_secret);
0492:                        hash.Update(time);
0493:                        params[cnonce] = new NVPair("cnonce", hash.asHex());
0494:                    }
0495:
0496:                    // select qop option
0497:
0498:                    if (ch_qop != -1) {
0499:                        if (qop == -1) {
0500:                            params = Util
0501:                                    .resizeArray(params, params.length + 1);
0502:                            qop = params.length - 1;
0503:                        }
0504:                        extra[DI_QOP] = ch_params[ch_qop].getValue();
0505:
0506:                        // select qop option
0507:
0508:                        String[] qops = splitList(extra[DI_QOP], ",");
0509:                        String p = null;
0510:                        for (int idx = 0; idx < qops.length; idx++) {
0511:                            if (qops[idx].equalsIgnoreCase("auth-int")
0512:                                    && (req.getStream() == null || req
0513:                                            .getConnection().ServProtVersKnown
0514:                                            && req.getConnection().ServerProtocolVersion >= HTTP_1_1)) {
0515:                                p = "auth-int";
0516:                                break;
0517:                            }
0518:                            if (qops[idx].equalsIgnoreCase("auth"))
0519:                                p = "auth";
0520:                        }
0521:                        if (p == null) {
0522:                            for (int idx = 0; idx < qops.length; idx++)
0523:                                if (qops[idx].equalsIgnoreCase("auth-int"))
0524:                                    throw new AuthSchemeNotImplException(
0525:                                            "Digest auth scheme: Can't comply with qop "
0526:                                                    + "option 'auth-int' because an HttpOutputStream "
0527:                                                    + "is being used and the server doesn't speak "
0528:                                                    + "HTTP/1.1");
0529:
0530:                            throw new AuthSchemeNotImplException(
0531:                                    "Digest auth scheme: "
0532:                                            + "None of the available qop options '"
0533:                                            + ch_params[ch_qop].getValue()
0534:                                            + "' implemented");
0535:                        }
0536:                        params[qop] = new NVPair("qop", p);
0537:                    }
0538:
0539:                    // increment nonce-count.
0540:
0541:                    if (qop != -1) {
0542:                        /* Note: we should actually be serializing all requests through
0543:                         *       here so that the server sees the nonce-count in a
0544:                         *       strictly increasing order. However, this would be a
0545:                         *       *major* hassle to do, so we're just winging it. Most
0546:                         *       of the time the requests will go over the wire in the
0547:                         *       same order as they pass through here, but in MT apps
0548:                         *       it's possible for one request to "overtake" another
0549:                         *       between here and the synchronized block in
0550:                         *       sendRequest().
0551:                         */
0552:                        if (nc == -1) {
0553:                            params = Util
0554:                                    .resizeArray(params, params.length + 1);
0555:                            nc = params.length - 1;
0556:                            params[nc] = new NVPair("nc", "00000001");
0557:                        } else if (old_nonce.equals(params[nonce].getValue())) {
0558:                            String c = Long.toHexString(Long.parseLong(
0559:                                    params[nc].getValue(), 16) + 1);
0560:                            params[nc] = new NVPair("nc", "00000000"
0561:                                    .substring(c.length())
0562:                                    + c);
0563:                        } else
0564:                            params[nc] = new NVPair("nc", "00000001");
0565:                    }
0566:
0567:                    // calc new session key if necessary
0568:
0569:                    if (challenge != null
0570:                            && (ch_stale == -1 || !ch_params[ch_stale]
0571:                                    .getValue().equalsIgnoreCase("true"))
0572:                            && alg != -1
0573:                            && params[alg].getValue().equalsIgnoreCase(
0574:                                    "MD5-sess")) {
0575:                        extra[DI_A1S] = new MD5(extra[DI_A1] + ":"
0576:                                + params[nonce].getValue() + ":"
0577:                                + params[cnonce].getValue()).asHex();
0578:                    }
0579:
0580:                    // update parameters for next auth cycle
0581:
0582:                    info.setParams(params);
0583:                    info.setExtraInfo(extra);
0584:                }
0585:
0586:                // calc "response" attribute
0587:
0588:                String hash = null;
0589:                if (qop != -1
0590:                        && params[qop].getValue().equalsIgnoreCase("auth-int")
0591:                        && req.getStream() == null) {
0592:                    MD5 entity_hash = new MD5();
0593:                    entity_hash.Update(req.getData() == null ? NUL : req
0594:                            .getData());
0595:                    hash = entity_hash.asHex();
0596:                }
0597:
0598:                if (req.getStream() == null)
0599:                    params[response] = new NVPair("response", calcResponseAttr(
0600:                            hash, extra, params, alg, uri, qop, nonce, nc,
0601:                            cnonce, req.getMethod()));
0602:
0603:                // calc digest if necessary
0604:
0605:                AuthorizationInfo new_info;
0606:
0607:                boolean ch_dreq_val = false;
0608:                if (ch_dreq != -1
0609:                        && (ch_params[ch_dreq].getValue() == null || ch_params[ch_dreq]
0610:                                .getValue().equalsIgnoreCase("true")))
0611:                    ch_dreq_val = true;
0612:
0613:                if ((ch_dreq_val || digest != -1) && req.getStream() == null) {
0614:                    NVPair[] d_params;
0615:                    if (digest == -1) {
0616:                        d_params = Util.resizeArray(params, params.length + 1);
0617:                        digest = params.length;
0618:                    } else
0619:                        d_params = params;
0620:                    d_params[digest] = new NVPair("digest", calc_digest(req,
0621:                            extra[DI_A1], params[nonce].getValue()));
0622:
0623:                    if (dreq == -1) // if server requires digest, then so do we...
0624:                    {
0625:                        dreq = d_params.length;
0626:                        d_params = Util.resizeArray(d_params,
0627:                                d_params.length + 1);
0628:                        d_params[dreq] = new NVPair("digest-required", "true");
0629:                    }
0630:
0631:                    new_info = new AuthorizationInfo(info.getHost(), info
0632:                            .getPort(), info.getScheme(), info.getRealm(),
0633:                            d_params, extra);
0634:                } else if (ch_dreq_val)
0635:                    new_info = null;
0636:                else
0637:                    new_info = new AuthorizationInfo(info.getHost(), info
0638:                            .getPort(), info.getScheme(), info.getRealm(),
0639:                            params, extra);
0640:
0641:                // add info for other domains, if listed
0642:
0643:                boolean from_server = (challenge != null)
0644:                        && challenge.getHost().equalsIgnoreCase(
0645:                                req.getConnection().getHost());
0646:                if (ch_domain != -1) {
0647:                    URI base = null;
0648:                    try {
0649:                        base = new URI(req.getConnection().getProtocol(), req
0650:                                .getConnection().getHost(), req.getConnection()
0651:                                .getPort(), req.getRequestURI());
0652:                    } catch (ParseException pe) {
0653:                    }
0654:
0655:                    StringTokenizer tok = new StringTokenizer(
0656:                            ch_params[ch_domain].getValue());
0657:                    while (tok.hasMoreTokens()) {
0658:                        URI Uri;
0659:                        try {
0660:                            Uri = new URI(base, tok.nextToken());
0661:                        } catch (ParseException pe) {
0662:                            continue;
0663:                        }
0664:
0665:                        AuthorizationInfo tmp = AuthorizationInfo
0666:                                .getAuthorization(Uri.getHost(), Uri.getPort(),
0667:                                        info.getScheme(), info.getRealm(), req
0668:                                                .getConnection().getContext());
0669:                        if (tmp == null) {
0670:                            params[uri] = new NVPair("uri", Uri.getPath());
0671:                            tmp = new AuthorizationInfo(Uri.getHost(), Uri
0672:                                    .getPort(), info.getScheme(), info
0673:                                    .getRealm(), params, extra);
0674:                            AuthorizationInfo.addAuthorization(tmp);
0675:                        }
0676:                        if (from_server)
0677:                            tmp.addPath(Uri.getPath());
0678:                    }
0679:                } else if (from_server && challenge != null) {
0680:                    // Spec says that if no domain attribute is present then the
0681:                    // whole server should be considered being in the same space
0682:                    AuthorizationInfo tmp = AuthorizationInfo.getAuthorization(
0683:                            challenge.getHost(), challenge.getPort(), info
0684:                                    .getScheme(), info.getRealm(), req
0685:                                    .getConnection().getContext());
0686:                    if (tmp != null)
0687:                        tmp.addPath("/");
0688:                }
0689:
0690:                // now return the one to use
0691:
0692:                return new_info;
0693:            }
0694:
0695:            /**
0696:             * @return the fixed info is stale=true; null otherwise
0697:             */
0698:            private static AuthorizationInfo digest_check_stale(
0699:                    AuthorizationInfo challenge, RoRequest req, RoResponse resp)
0700:                    throws AuthSchemeNotImplException {
0701:                AuthorizationInfo cred = null;
0702:
0703:                NVPair[] params = challenge.getParams();
0704:                for (int idx = 0; idx < params.length; idx++) {
0705:                    String name = params[idx].getName();
0706:                    if (name.equalsIgnoreCase("stale")
0707:                            && params[idx].getValue().equalsIgnoreCase("true")) {
0708:                        cred = AuthorizationInfo.getAuthorization(challenge,
0709:                                req, resp, false);
0710:                        if (cred != null) // should always be the case
0711:                            return digest_fixup(cred, req, challenge, resp);
0712:                        break; // should never be reached
0713:                    }
0714:                }
0715:
0716:                return cred;
0717:            }
0718:
0719:            /**
0720:             * Handle nextnonce field.
0721:             */
0722:            private static boolean handle_nextnonce(AuthorizationInfo prev,
0723:                    RoRequest req, HttpHeaderElement nextnonce) {
0724:                if (prev == null || nextnonce == null
0725:                        || nextnonce.getValue() == null)
0726:                    return false;
0727:
0728:                AuthorizationInfo ai;
0729:                try {
0730:                    ai = AuthorizationInfo.getAuthorization(prev, req, null,
0731:                            false);
0732:                } catch (AuthSchemeNotImplException asnie) {
0733:                    ai = prev; /* shouldn't happen */
0734:                }
0735:                synchronized (ai) {
0736:                    NVPair[] params = ai.getParams();
0737:                    params = setValue(params, "nonce", nextnonce.getValue());
0738:                    params = setValue(params, "nc", "00000000");
0739:                    ai.setParams(params);
0740:                }
0741:
0742:                return true;
0743:            }
0744:
0745:            /**
0746:             * Handle digest field of the Authentication-Info response header.
0747:             */
0748:            private static boolean handle_digest(AuthorizationInfo prev,
0749:                    Response resp, RoRequest req, String hdr_name)
0750:                    throws IOException {
0751:                if (prev == null)
0752:                    return false;
0753:
0754:                NVPair[] params = prev.getParams();
0755:                VerifyDigest verifier = new VerifyDigest(((String[]) prev
0756:                        .getExtraInfo())[0], getValue(params, "nonce"), req
0757:                        .getMethod(), getValue(params, "uri"), hdr_name, resp);
0758:
0759:                if (resp.hasEntity()) {
0760:                    if (DebugAuth)
0761:                        System.err
0762:                                .println("Auth:  pushing md5-check-stream to verify "
0763:                                        + "digest from " + hdr_name);
0764:                    resp.inp_stream = new MD5InputStream(resp.inp_stream,
0765:                            verifier);
0766:                } else {
0767:                    if (DebugAuth)
0768:                        System.err.println("Auth:  verifying digest from "
0769:                                + hdr_name);
0770:                    verifier.verifyHash(new MD5().Final(), 0);
0771:                }
0772:
0773:                return true;
0774:            }
0775:
0776:            /**
0777:             * Handle rspauth field of the Authentication-Info response header.
0778:             */
0779:            private static boolean handle_rspauth(AuthorizationInfo prev,
0780:                    Response resp, RoRequest req, Vector auth_info,
0781:                    String hdr_name) throws IOException {
0782:                if (prev == null)
0783:                    return false;
0784:
0785:                // get the parameters we sent
0786:
0787:                NVPair[] params = prev.getParams();
0788:                int uri = -1, alg = -1, nonce = -1, cnonce = -1, nc = -1;
0789:                for (int idx = 0; idx < params.length; idx++) {
0790:                    String name = params[idx].getName().toLowerCase();
0791:                    if (name.equals("uri"))
0792:                        uri = idx;
0793:                    else if (name.equals("algorithm"))
0794:                        alg = idx;
0795:                    else if (name.equals("nonce"))
0796:                        nonce = idx;
0797:                    else if (name.equals("cnonce"))
0798:                        cnonce = idx;
0799:                    else if (name.equals("nc"))
0800:                        nc = idx;
0801:                }
0802:
0803:                // create hash verifier to verify rspauth
0804:
0805:                VerifyRspAuth verifier = new VerifyRspAuth(params[uri]
0806:                        .getValue(), ((String[]) prev.getExtraInfo())[0],
0807:                        (alg == -1 ? null : params[alg].getValue()),
0808:                        params[nonce].getValue(), (cnonce == -1 ? ""
0809:                                : params[cnonce].getValue()), (nc == -1 ? ""
0810:                                : params[nc].getValue()), hdr_name, resp);
0811:
0812:                // if Authentication-Info in header and qop=auth then verify immediately
0813:
0814:                HttpHeaderElement qop = null;
0815:                if (auth_info != null
0816:                        && (qop = Util.getElement(auth_info, "qop")) != null
0817:                        && qop.getValue() != null
0818:                        && (qop.getValue().equalsIgnoreCase("auth") || !resp
0819:                                .hasEntity()
0820:                                && qop.getValue().equalsIgnoreCase("auth-int"))) {
0821:                    if (DebugAuth)
0822:                        System.err.println("Auth:  verifying rspauth from "
0823:                                + hdr_name);
0824:                    verifier.verifyHash(new MD5().Final(), 0);
0825:                } else {
0826:                    // else push md5 stream and verify after body
0827:
0828:                    if (DebugAuth)
0829:                        System.err
0830:                                .println("Auth:  pushing md5-check-stream to verify "
0831:                                        + "rspauth from " + hdr_name);
0832:                    resp.inp_stream = new MD5InputStream(resp.inp_stream,
0833:                            verifier);
0834:                }
0835:
0836:                return true;
0837:            }
0838:
0839:            /**
0840:             * Calc "response" attribute for a request.
0841:             */
0842:            private static String calcResponseAttr(String hash, String[] extra,
0843:                    NVPair[] params, int alg, int uri, int qop, int nonce,
0844:                    int nc, int cnonce, String method) {
0845:                String A1, A2, resp_val;
0846:
0847:                if (alg != -1
0848:                        && params[alg].getValue().equalsIgnoreCase("MD5-sess"))
0849:                    A1 = extra[DI_A1S];
0850:                else
0851:                    A1 = extra[DI_A1];
0852:
0853:                A2 = method + ":" + params[uri].getValue();
0854:                if (qop != -1
0855:                        && params[qop].getValue().equalsIgnoreCase("auth-int")) {
0856:                    A2 += ":" + hash;
0857:                }
0858:                A2 = new MD5(A2).asHex();
0859:
0860:                if (qop == -1)
0861:                    resp_val = new MD5(A1 + ":" + params[nonce].getValue()
0862:                            + ":" + A2).asHex();
0863:                else
0864:                    resp_val = new MD5(A1 + ":" + params[nonce].getValue()
0865:                            + ":" + params[nc].getValue() + ":"
0866:                            + params[cnonce].getValue() + ":"
0867:                            + params[qop].getValue() + ":" + A2).asHex();
0868:
0869:                return resp_val;
0870:            }
0871:
0872:            /**
0873:             * Calculates the digest of the request body. This was in RFC-2069
0874:             * and draft-ietf-http-authentication-00.txt, but has subsequently
0875:             * been removed. Here for backwards compatibility.
0876:             */
0877:            private static String calc_digest(RoRequest req, String A1_hash,
0878:                    String nonce) {
0879:                if (req.getStream() != null)
0880:                    return "";
0881:
0882:                int ct = -1, ce = -1, lm = -1, ex = -1, dt = -1;
0883:                for (int idx = 0; idx < req.getHeaders().length; idx++) {
0884:                    String name = req.getHeaders()[idx].getName();
0885:                    if (name.equalsIgnoreCase("Content-type"))
0886:                        ct = idx;
0887:                    else if (name.equalsIgnoreCase("Content-Encoding"))
0888:                        ce = idx;
0889:                    else if (name.equalsIgnoreCase("Last-Modified"))
0890:                        lm = idx;
0891:                    else if (name.equalsIgnoreCase("Expires"))
0892:                        ex = idx;
0893:                    else if (name.equalsIgnoreCase("Date"))
0894:                        dt = idx;
0895:                }
0896:
0897:                NVPair[] hdrs = req.getHeaders();
0898:                byte[] entity_body = (req.getData() == null ? NUL : req
0899:                        .getData());
0900:                MD5 entity_hash = new MD5();
0901:                entity_hash.Update(entity_body);
0902:
0903:                String entity_info = new MD5(req.getRequestURI() + ":"
0904:                        + (ct == -1 ? "" : hdrs[ct].getValue()) + ":"
0905:                        + entity_body.length + ":"
0906:                        + (ce == -1 ? "" : hdrs[ce].getValue()) + ":"
0907:                        + (lm == -1 ? "" : hdrs[lm].getValue()) + ":"
0908:                        + (ex == -1 ? "" : hdrs[ex].getValue())).asHex();
0909:                String entity_digest = A1_hash + ":" + nonce + ":"
0910:                        + req.getMethod() + ":"
0911:                        + (dt == -1 ? "" : hdrs[dt].getValue()) + ":"
0912:                        + entity_info + ":" + entity_hash.asHex();
0913:
0914:                if (DebugAuth) {
0915:                    System.err.println("Auth:  Entity-Info: '"
0916:                            + req.getRequestURI() + ":"
0917:                            + (ct == -1 ? "" : hdrs[ct].getValue()) + ":"
0918:                            + entity_body.length + ":"
0919:                            + (ce == -1 ? "" : hdrs[ce].getValue()) + ":"
0920:                            + (lm == -1 ? "" : hdrs[lm].getValue()) + ":"
0921:                            + (ex == -1 ? "" : hdrs[ex].getValue()) + "'");
0922:                    System.err.println("Auth:  Entity-Body: '"
0923:                            + entity_hash.asHex() + "'");
0924:                    System.err.println("Auth:  Entity-Digest: '"
0925:                            + entity_digest + "'");
0926:                }
0927:
0928:                return new MD5(entity_digest).asHex();
0929:            }
0930:
0931:            /**
0932:             * Handle discard token
0933:             */
0934:            private static boolean handle_discard(AuthorizationInfo prev,
0935:                    RoRequest req, HttpHeaderElement discard) {
0936:                if (discard != null && prev != null) {
0937:                    AuthorizationInfo.removeAuthorization(prev, req
0938:                            .getConnection().getContext());
0939:                    return true;
0940:                }
0941:
0942:                return false;
0943:            }
0944:
0945:            /**
0946:             * Generate <var>num</var> bytes of random data.
0947:             *
0948:             * @param num  the number of bytes to generate
0949:             * @return a byte array of random data
0950:             */
0951:            private static byte[] gen_random_bytes(int num) {
0952:                // first try /dev/random
0953:                try {
0954:                    FileInputStream rnd = new FileInputStream("/dev/random");
0955:                    DataInputStream din = new DataInputStream(rnd);
0956:                    byte[] data = new byte[num];
0957:                    din.readFully(data);
0958:                    try {
0959:                        din.close();
0960:                    } catch (IOException ioe) {
0961:                    }
0962:                    return data;
0963:                } catch (Throwable t) {
0964:                }
0965:
0966:                /* This is probably a much better generator, but it can be awfully
0967:                 * slow (~ 6 secs / byte on my old LX)
0968:                 */
0969:                //return new java.security.SecureRandom().getSeed(num);
0970:                /* this is faster, but needs to be done better... */
0971:                byte[] data = new byte[num];
0972:                try {
0973:                    long fm = Runtime.getRuntime().freeMemory();
0974:                    data[0] = (byte) (fm & 0xFF);
0975:                    data[1] = (byte) ((fm >> 8) & 0xFF);
0976:
0977:                    int h = data.hashCode();
0978:                    data[2] = (byte) (h & 0xFF);
0979:                    data[3] = (byte) ((h >> 8) & 0xFF);
0980:                    data[4] = (byte) ((h >> 16) & 0xFF);
0981:                    data[5] = (byte) ((h >> 24) & 0xFF);
0982:
0983:                    long time = System.currentTimeMillis();
0984:                    data[6] = (byte) (time & 0xFF);
0985:                    data[7] = (byte) ((time >> 8) & 0xFF);
0986:                } catch (ArrayIndexOutOfBoundsException aioobe) {
0987:                }
0988:
0989:                return data;
0990:            }
0991:
0992:            /**
0993:             * Return the value of the first NVPair whose name matches the key
0994:             * using a case-insensitive search.
0995:             *
0996:             * @param list an array of NVPair's
0997:             * @param key  the key to search for
0998:             * @return the value of the NVPair with that key, or null if not
0999:             *         found.
1000:             */
1001:            private final static String getValue(NVPair[] list, String key) {
1002:                int len = list.length;
1003:
1004:                for (int idx = 0; idx < len; idx++)
1005:                    if (list[idx].getName().equalsIgnoreCase(key))
1006:                        return list[idx].getValue();
1007:
1008:                return null;
1009:            }
1010:
1011:            /**
1012:             * Return the index of the first NVPair whose name matches the key
1013:             * using a case-insensitive search.
1014:             *
1015:             * @param list an array of NVPair's
1016:             * @param key  the key to search for
1017:             * @return the index of the NVPair with that key, or -1 if not
1018:             *         found.
1019:             */
1020:            private final static int getIndex(NVPair[] list, String key) {
1021:                int len = list.length;
1022:
1023:                for (int idx = 0; idx < len; idx++)
1024:                    if (list[idx].getName().equalsIgnoreCase(key))
1025:                        return idx;
1026:
1027:                return -1;
1028:            }
1029:
1030:            /**
1031:             * Sets the value of the NVPair with the name that matches the key
1032:             * (case-insensitive). If no name matches, a new entry is created.
1033:             *
1034:             * @param list an array of NVPair's
1035:             * @param key  the name of the NVPair
1036:             * @param val  the value of the new NVPair
1037:             * @return the (possibly) new list
1038:             */
1039:            private final static NVPair[] setValue(NVPair[] list, String key,
1040:                    String val) {
1041:                int idx = getIndex(list, key);
1042:                if (idx == -1) {
1043:                    idx = list.length;
1044:                    list = Util.resizeArray(list, list.length + 1);
1045:                }
1046:
1047:                list[idx] = new NVPair(key, val);
1048:                return list;
1049:            }
1050:
1051:            /**
1052:             * Split a list into an array of Strings, using sep as the
1053:             * separator and removing whitespace around the separator.
1054:             */
1055:            private static String[] splitList(String str, String sep) {
1056:                if (str == null)
1057:                    return new String[0];
1058:
1059:                StringTokenizer tok = new StringTokenizer(str, sep);
1060:                String[] list = new String[tok.countTokens()];
1061:                for (int idx = 0; idx < list.length; idx++)
1062:                    list[idx] = tok.nextToken().trim();
1063:
1064:                return list;
1065:            }
1066:
1067:            /**
1068:             * Produce a string of the form "A5:22:F1:0B:53"
1069:             */
1070:            static String hex(byte[] buf) {
1071:                StringBuffer str = new StringBuffer(buf.length * 3);
1072:                for (int idx = 0; idx < buf.length; idx++) {
1073:                    str.append(Character.forDigit(buf[idx] >>> 4, 16));
1074:                    str.append(Character.forDigit(buf[idx] & 16, 16));
1075:                    str.append(':');
1076:                }
1077:                str.setLength(str.length() - 1);
1078:
1079:                return str.toString();
1080:            }
1081:
1082:            static final byte[] unHex(String hex) {
1083:                byte[] digest = new byte[hex.length() / 2];
1084:
1085:                for (int idx = 0; idx < digest.length; idx++) {
1086:                    digest[idx] = (byte) (0xFF & Integer.parseInt(hex
1087:                            .substring(2 * idx, 2 * (idx + 1)), 16));
1088:                }
1089:
1090:                return digest;
1091:            }
1092:        }
1093:
1094:        /**
1095:         * This verifies the "rspauth" from draft-ietf-http-authentication-03
1096:         */
1097:        class VerifyRspAuth implements  HashVerifier, GlobalConstants {
1098:            private String uri;
1099:            private String HA1;
1100:            private String alg;
1101:            private String nonce;
1102:            private String cnonce;
1103:            private String nc;
1104:            private String hdr;
1105:            private RoResponse resp;
1106:
1107:            public VerifyRspAuth(String uri, String HA1, String alg,
1108:                    String nonce, String cnonce, String nc, String hdr,
1109:                    RoResponse resp) {
1110:                this .uri = uri;
1111:                this .HA1 = HA1;
1112:                this .alg = alg;
1113:                this .nonce = nonce;
1114:                this .cnonce = cnonce;
1115:                this .nc = nc;
1116:                this .hdr = hdr;
1117:                this .resp = resp;
1118:            }
1119:
1120:            public void verifyHash(byte[] hash, long len) throws IOException {
1121:                String auth_info = resp.getHeader(hdr);
1122:                if (auth_info == null)
1123:                    auth_info = resp.getTrailer(hdr);
1124:                if (auth_info == null)
1125:                    return;
1126:
1127:                Vector pai;
1128:                try {
1129:                    pai = Util.parseHeader(auth_info);
1130:                } catch (ParseException pe) {
1131:                    throw new IOException(pe.toString());
1132:                }
1133:
1134:                String qop;
1135:                HttpHeaderElement elem = Util.getElement(pai, "qop");
1136:                if (elem == null
1137:                        || (qop = elem.getValue()) == null
1138:                        || (!qop.equalsIgnoreCase("auth") && !qop
1139:                                .equalsIgnoreCase("auth-int")))
1140:                    return;
1141:
1142:                elem = Util.getElement(pai, "rspauth");
1143:                if (elem == null || elem.getValue() == null)
1144:                    return;
1145:                byte[] digest = DefaultAuthHandler.unHex(elem.getValue());
1146:
1147:                elem = Util.getElement(pai, "cnonce");
1148:                if (elem != null && elem.getValue() != null
1149:                        && !elem.getValue().equals(cnonce))
1150:                    throw new IOException("Digest auth scheme: received wrong "
1151:                            + "client-nonce '" + elem.getValue()
1152:                            + "' - expected '" + cnonce + "'");
1153:
1154:                elem = Util.getElement(pai, "nc");
1155:                if (elem != null && elem.getValue() != null
1156:                        && !elem.getValue().equals(nc))
1157:                    throw new IOException("Digest auth scheme: received wrong "
1158:                            + "nonce-count '" + elem.getValue()
1159:                            + "' - expected '" + nc + "'");
1160:
1161:                String A1, A2;
1162:                if (alg != null && alg.equalsIgnoreCase("MD5-sess"))
1163:                    A1 = new MD5(HA1 + ":" + nonce + ":" + cnonce).asHex();
1164:                else
1165:                    A1 = HA1;
1166:
1167:                // draft-01 was: A2 = resp.getStatusCode() + ":" + uri;
1168:                A2 = ":" + uri;
1169:                if (qop.equalsIgnoreCase("auth-int"))
1170:                    A2 += ":" + MD5.asHex(hash);
1171:                A2 = new MD5(A2).asHex();
1172:
1173:                hash = new MD5(A1 + ":" + nonce + ":" + nc + ":" + cnonce + ":"
1174:                        + qop + ":" + A2).Final();
1175:
1176:                for (int idx = 0; idx < hash.length; idx++) {
1177:                    if (hash[idx] != digest[idx])
1178:                        throw new IOException("MD5-Digest mismatch: expected "
1179:                                + DefaultAuthHandler.hex(digest)
1180:                                + " but calculated "
1181:                                + DefaultAuthHandler.hex(hash));
1182:                }
1183:
1184:                if (DebugAuth)
1185:                    System.err.println("Auth:  rspauth from " + hdr
1186:                            + " successfully verified");
1187:            }
1188:        }
1189:
1190:        /**
1191:         * This verifies the "digest" from rfc-2069
1192:         */
1193:        class VerifyDigest implements  HashVerifier, GlobalConstants {
1194:            private String HA1;
1195:            private String nonce;
1196:            private String method;
1197:            private String uri;
1198:            private String hdr;
1199:            private RoResponse resp;
1200:
1201:            public VerifyDigest(String HA1, String nonce, String method,
1202:                    String uri, String hdr, RoResponse resp) {
1203:                this .HA1 = HA1;
1204:                this .nonce = nonce;
1205:                this .method = method;
1206:                this .uri = uri;
1207:                this .hdr = hdr;
1208:                this .resp = resp;
1209:            }
1210:
1211:            public void verifyHash(byte[] hash, long len) throws IOException {
1212:                String auth_info = resp.getHeader(hdr);
1213:                if (auth_info == null)
1214:                    auth_info = resp.getTrailer(hdr);
1215:                if (auth_info == null)
1216:                    return;
1217:
1218:                Vector pai;
1219:                try {
1220:                    pai = Util.parseHeader(auth_info);
1221:                } catch (ParseException pe) {
1222:                    throw new IOException(pe.toString());
1223:                }
1224:                HttpHeaderElement elem = Util.getElement(pai, "digest");
1225:                if (elem == null || elem.getValue() == null)
1226:                    return;
1227:
1228:                byte[] digest = DefaultAuthHandler.unHex(elem.getValue());
1229:
1230:                String entity_info = new MD5(uri + ":"
1231:                        + header_val("Content-Type", resp) + ":"
1232:                        + header_val("Content-Length", resp) + ":"
1233:                        + header_val("Content-Encoding", resp) + ":"
1234:                        + header_val("Last-Modified", resp) + ":"
1235:                        + header_val("Expires", resp)).asHex();
1236:                hash = new MD5(HA1 + ":" + nonce + ":" + method + ":"
1237:                        + header_val("Date", resp) + ":" + entity_info + ":"
1238:                        + MD5.asHex(hash)).Final();
1239:
1240:                for (int idx = 0; idx < hash.length; idx++) {
1241:                    if (hash[idx] != digest[idx])
1242:                        throw new IOException("MD5-Digest mismatch: expected "
1243:                                + DefaultAuthHandler.hex(digest)
1244:                                + " but calculated "
1245:                                + DefaultAuthHandler.hex(hash));
1246:                }
1247:
1248:                if (DebugAuth)
1249:                    System.err.println("Auth:  digest from " + hdr
1250:                            + " successfully verified");
1251:            }
1252:
1253:            private static final String header_val(String hdr_name,
1254:                    RoResponse resp) throws IOException {
1255:                String hdr = resp.getHeader(hdr_name);
1256:                String tlr = resp.getTrailer(hdr_name);
1257:                return (hdr != null ? hdr : (tlr != null ? tlr : ""));
1258:            }
1259:        }
1260:
1261:        /**
1262:         * This class implements a simple popup that request username and password
1263:         * used for the "basic" and "digest" authentication schemes.
1264:         *
1265:         * @version	0.3-2  18/06/1999
1266:         * @author	Ronald Tschalär
1267:         */
1268:        class BasicAuthBox extends Frame {
1269:            private final static String title = "Authorization Request";
1270:            private Dimension screen;
1271:            private Label line1, line2, line3;
1272:            private TextField user, pass;
1273:            private int done;
1274:            private final static int OK = 1, CANCEL = 0;
1275:
1276:            /**
1277:             * Constructs the popup with two lines of text above the input fields
1278:             */
1279:            BasicAuthBox() {
1280:                super (title);
1281:
1282:                screen = getToolkit().getScreenSize();
1283:
1284:                addNotify();
1285:                addWindowListener(new Close());
1286:                setLayout(new BorderLayout());
1287:
1288:                Panel p = new Panel(new GridLayout(3, 1));
1289:                p.add(line1 = new Label());
1290:                p.add(line2 = new Label());
1291:                p.add(line3 = new Label());
1292:                add("North", p);
1293:
1294:                p = new Panel(new GridLayout(2, 1));
1295:                p.add(new Label("Username:"));
1296:                p.add(new Label("Password:"));
1297:                add("West", p);
1298:                p = new Panel(new GridLayout(2, 1));
1299:                p.add(user = new TextField(30));
1300:                p.add(pass = new TextField(30));
1301:                pass.addActionListener(new Ok());
1302:                pass.setEchoChar('*');
1303:                add("East", p);
1304:
1305:                GridBagLayout gb = new GridBagLayout();
1306:                p = new Panel(gb);
1307:                GridBagConstraints constr = new GridBagConstraints();
1308:                Panel pp = new Panel();
1309:                p.add(pp);
1310:                constr.gridwidth = GridBagConstraints.REMAINDER;
1311:                gb.setConstraints(pp, constr);
1312:                constr.gridwidth = 1;
1313:                constr.weightx = 1.0;
1314:                Button b;
1315:                p.add(b = new Button("  OK  "));
1316:                b.addActionListener(new Ok());
1317:                constr.weightx = 1.0;
1318:                gb.setConstraints(b, constr);
1319:                p.add(b = new Button("Clear"));
1320:                b.addActionListener(new Clear());
1321:                constr.weightx = 2.0;
1322:                gb.setConstraints(b, constr);
1323:                p.add(b = new Button("Cancel"));
1324:                b.addActionListener(new Cancel());
1325:                constr.weightx = 1.0;
1326:                gb.setConstraints(b, constr);
1327:                add("South", p);
1328:
1329:                pack();
1330:                setResizable(false);
1331:            }
1332:
1333:            /**
1334:             * our event handlers
1335:             */
1336:            private class Ok implements  ActionListener {
1337:                public void actionPerformed(ActionEvent ae) {
1338:                    done = OK;
1339:                    synchronized (BasicAuthBox.this ) {
1340:                        BasicAuthBox.this .notifyAll();
1341:                    }
1342:                }
1343:            }
1344:
1345:            private class Clear implements  ActionListener {
1346:                public void actionPerformed(ActionEvent ae) {
1347:                    user.setText("");
1348:                    pass.setText("");
1349:                    user.requestFocus();
1350:                }
1351:            }
1352:
1353:            private class Cancel implements  ActionListener {
1354:                public void actionPerformed(ActionEvent ae) {
1355:                    done = CANCEL;
1356:                    synchronized (BasicAuthBox.this ) {
1357:                        BasicAuthBox.this .notifyAll();
1358:                    }
1359:                }
1360:            }
1361:
1362:            private class Close extends WindowAdapter {
1363:                public void windowClosing(WindowEvent we) {
1364:                    new Cancel().actionPerformed(null);
1365:                }
1366:            }
1367:
1368:            /**
1369:             * the method called by DefaultAuthHandler.
1370:             *
1371:             * @return the username/password pair
1372:             */
1373:            synchronized NVPair getInput(String l1, String l2, String l3) {
1374:                line1.setText(l1);
1375:                line2.setText(l2);
1376:                line3.setText(l3);
1377:
1378:                line1.invalidate();
1379:                line2.invalidate();
1380:                line3.invalidate();
1381:
1382:                setResizable(true);
1383:                pack();
1384:                setResizable(false);
1385:                setLocation(
1386:                        (screen.width - getPreferredSize().width) / 2,
1387:                        (int) ((screen.height - getPreferredSize().height) / 2 * .7));
1388:                user.requestFocus();
1389:                setVisible(true);
1390:
1391:                try {
1392:                    wait();
1393:                } catch (InterruptedException e) {
1394:                }
1395:
1396:                setVisible(false);
1397:
1398:                NVPair result = new NVPair(user.getText(), pass.getText());
1399:                user.setText("");
1400:                pass.setText("");
1401:
1402:                if (done == CANCEL)
1403:                    return null;
1404:                else
1405:                    return result;
1406:            }
1407:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.