From: Dave B. <bla...@us...> - 2013-02-06 13:05:48
|
Update of /cvsroot/sblim/jsr48-client/src/org/sblim/cimclient/internal/http In directory sfp-cvs-1.v30.ch3.sourceforge.com:/tmp/cvs-serv5705/src/org/sblim/cimclient/internal/http Modified Files: Challenge.java Log Message: 3596303 windows http response WWW-Authenticate: Negotiate fails Index: Challenge.java =================================================================== RCS file: /cvsroot/sblim/jsr48-client/src/org/sblim/cimclient/internal/http/Challenge.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- Challenge.java 10 Mar 2009 16:32:42 -0000 1.6 +++ Challenge.java 6 Feb 2013 13:05:46 -0000 1.7 @@ -1,5 +1,5 @@ /** - * (C) Copyright IBM Corp. 2005, 2009 + * (C) Copyright IBM Corp. 2005, 2013 * * THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE * ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE @@ -18,7 +18,8 @@ * 1565892 2006-11-28 lupusalex Make SBLIM client JSR48 compliant * 2003590 2008-06-30 blaschke-oss Change licensing from CPL to EPL * 2524131 2009-01-21 raman_arora Upgrade client to JDK 1.5 (Phase 1) - * 2531371 2009-02-10 raman_arora Upgrade client to JDK 1.5 (Phase 2) + * 2531371 2009-02-10 raman_arora Upgrade client to JDK 1.5 (Phase 2) + * 3596303 2013-01-04 blaschke-oss windows http response WWW-Authenticate: Negotiate fails */ package org.sblim.cimclient.internal.http; @@ -67,7 +68,14 @@ } /** - * Parses the challenge as received from the host + * Parses the challenge as received from the host. RFC 2617 defines the + * following syntax for a challenge: + * + * <pre> + * challenge = auth-scheme 1*SP 1#auth-param + * auth-scheme = token + * auth-param = token "=" ( token | quoted-string ) + * </pre> * * @param pLine * The challenge string @@ -76,68 +84,153 @@ * If the challenge string is ill-formed */ public static Challenge[] parseChallenge(String pLine) throws HttpParseException { - Vector<Challenge> challeges = new Vector<Challenge>(); if (pLine == null || pLine.length() == 0) throw new IllegalArgumentException( - "Invalid challenge"); - Challenge challenge = new Challenge(); - challenge.iParams = new HttpHeader(); + "Invalid challenge, empty"); + pLine = pLine.trim(); + if (pLine.length() == 0) throw new IllegalArgumentException("Invalid challenge, empty"); + + Vector<Challenge> challenges = new Vector<Challenge>(); - char buf[] = pLine.toCharArray(); try { int start = 0, end = 0; - while (true) { - start = skipSpaces(buf, start); - end = findEndOfToken(buf, start); - String scheme = pLine.substring(start, end); - challenge.iScheme = scheme; - start = end; - boolean skipComma = true; - while (true) { - if (!skipComma) { - start = skipSpaces(buf, start); - if (start >= buf.length || buf[start] != ',') { - break; - } - } - start = skipSpaces(buf, start + 1); - if (start >= buf.length) break; - end = findEndOfToken(buf, start); - String paramname = pLine.substring(start, end); - start = end; - if (start >= buf.length) break; + // Break up comma-separated list into tokens + Vector<String> tokensBetweenCommas = new Vector<String>(); + while ((end = indexOfOutsideQuotedString(pLine, ',', start)) > 0) { + tokensBetweenCommas.add(removeWhitespace(pLine.substring(start, end))); + start = end + 1; + } + if (start < pLine.length()) tokensBetweenCommas.add(removeWhitespace(pLine + .substring(start))); - start = skipSpaces(buf, start); - if (start >= buf.length) break; + // Break up tokens into auth-scheme and auth-param + Vector<String> tokens = new Vector<String>(); + for (int i = 0; i < tokensBetweenCommas.size(); i++) { + String token = tokensBetweenCommas.elementAt(i); - if (buf[start] != '=') throw new HttpParseException("Invalid challenge"); - if (start + 1 >= buf.length) break; - start = skipSpaces(buf, start + 1); + if (token.length() == 0) continue; - if (start >= buf.length) break; - end = findEndOfToken(buf, start); - String value = pLine.substring(start, end); - start = end; + start = 0; + end = indexOfOutsideQuotedString(token, ' ', start); - if (value.startsWith("\"") && value.endsWith("\"") && value.length() > 1) challenge.iParams - .addField(paramname, value.substring(1, value.length() - 1)); - else challenge.iParams.addField(paramname, value); - skipComma = false; + if (end == -1) { + tokens.add(token); + } else { + tokens.add(token.substring(0, end)); + start = end + 1; + end = indexOfOutsideQuotedString(token, ' ', start); + + if (end == -1) { + // RFC 2617 indicates this token should be of the + // name=value format, but at least one old CIMOM (SVC + // ICAT) does not follow this rule. The Client + // effectively ignores this token, and so must continue + // to do so. + if (indexOfOutsideQuotedString(token, '=', start) == -1) { + // throw new + // HttpParseException("Invalid challenge, second token must be name=value in " + // + token); + } else { + tokens.add(token.substring(start)); + } + } else { + throw new HttpParseException("Invalid challenge, too many tokens in " + + token); + } } - // if (challenge.params.getField("realm") == null) - // challenge.params.addField("realm", ""); + } - challeges.add(challenge); - if (start >= buf.length) break; + Challenge challenge = new Challenge(); + challenge.iScheme = null; + challenge.iParams = new HttpHeader(); + + for (int i = 0; i < tokens.size(); i++) { + String token = tokens.elementAt(i); + + int equalSign = indexOfOutsideQuotedString(token, '=', 0); + if (equalSign == 0) { + throw new HttpParseException( + "Invalid challenge, no token before equal sign in " + token); + } else if (equalSign > 0) { + // param + if (challenge.iScheme == null) throw new HttpParseException( + "Invalid challenge, param without scheme"); + String name = token.substring(0, equalSign); + String value = token.substring(equalSign + 1); + if (value.length() == 0) { + throw new HttpParseException( + "Invalid challenge, no token after equal sign in " + token); + } else if (value.startsWith("\"") && value.endsWith("\"") && value.length() > 1) { + challenge.iParams.addField(name, value.substring(1, value.length() - 1)); + } else { + challenge.iParams.addField(name, value); + } + } else { + // scheme + if (challenge.iScheme != null) { + // new scheme + challenges.add(challenge); + + challenge = new Challenge(); + challenge.iParams = new HttpHeader(); + } + challenge.iScheme = new String(token); + } } + if (challenge.iScheme != null) { + challenges.add(challenge); + } } catch (HttpParseException e) { throw e; } catch (Exception e) { - throw new HttpParseException("Invalid challenge"); + throw new HttpParseException("Invalid challenge, " + e.getMessage()); } - return challeges.toArray(new Challenge[challeges.size()]); + return challenges.toArray(new Challenge[challenges.size()]); + + } + + /* + * Removes unnecessary whitespace from a challenge such that + * " scheme name = value " becomes "scheme name=value" + */ + private static String removeWhitespace(String str) throws HttpParseException { + char inBuf[] = str.trim().toCharArray(); + StringBuilder outStr = new StringBuilder(); + boolean inQuotes = false; + + for (int inIdx = 0; inIdx < inBuf.length; inIdx++) { + if (inQuotes || !Character.isSpaceChar(inBuf[inIdx])) { + if (inBuf[inIdx] == '=' && outStr.length() == 0) throw new HttpParseException( + "Invalid challenge, no token before equal sign in " + str); + + outStr.append(inBuf[inIdx]); + } else { + // Whitespace not within quoted string + int i = skipSpaces(inBuf, inIdx + 1); + if (i >= inBuf.length) throw new HttpParseException( + "Invalid challenge, no token after space in " + str); + + if (inBuf[i] == '=') { + // auth-param, remove all whitespace up to next token + i = skipSpaces(inBuf, i + 1); + if (i >= inBuf.length) throw new HttpParseException( + "Invalid challenge, no token after equal sign in " + str); + outStr.append('='); + } else { + // another token, combine all whitespace up to next token + // into single space + outStr.append(' '); + } + outStr.append(inBuf[i]); + inIdx = i; + } + if (inBuf[inIdx] == '\"') inQuotes = !inQuotes; + } + if (inQuotes) throw new HttpParseException( + "Invalid challenge, quoted string not terminated in " + str); + return outStr.toString(); } private static int skipSpaces(char[] buf, int pos) { @@ -146,18 +239,22 @@ return pos; } - private static int findEndOfToken(char[] buf, int pos) { - if (buf[pos] == '\"') { - do { - pos++; - } while (buf[pos] != '\"' && pos < buf.length); + private static int indexOfOutsideQuotedString(String str, int ch, int pos) + throws HttpParseException { + int len = str.length(); + boolean inQuotes = false; + + while (pos < len) { + if (str.charAt(pos) == '\"') { + inQuotes = !inQuotes; + } else if (str.charAt(pos) == ch) { + if (!inQuotes) return pos; + } pos++; - } else { - while (pos < buf.length - && (!Character.isSpaceChar(buf[pos]) && !(buf[pos] == ',') && !(buf[pos] == '='))) - pos++; } - return pos; + if (inQuotes) throw new HttpParseException( + "Invalid callenge, quoted string not terminated in " + str); + return -1; } } |