Shuyi Chen | d7955ce | 2013-05-22 14:51:55 -0700 | [diff] [blame] | 1 | /* ************************************************************************** |
| 2 | * $OpenLDAP: /com/novell/sasl/client/TokenParser.java,v 1.3 2005/01/17 15:00:54 sunilk Exp $ |
| 3 | * |
| 4 | * Copyright (C) 2002 Novell, Inc. All Rights Reserved. |
| 5 | * |
| 6 | * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND |
| 7 | * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT |
| 8 | * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS |
| 9 | * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" |
| 10 | * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION |
| 11 | * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP |
| 12 | * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT |
| 13 | * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. |
| 14 | ******************************************************************************/ |
| 15 | package com.novell.sasl.client; |
| 16 | |
| 17 | import org.apache.harmony.javax.security.sasl.*; |
| 18 | /** |
| 19 | * The TokenParser class will parse individual tokens from a list of tokens that |
| 20 | * are a directive value for a DigestMD5 authentication.The tokens are separated |
| 21 | * commas. |
| 22 | */ |
| 23 | class TokenParser extends Object |
| 24 | { |
| 25 | private static final int STATE_LOOKING_FOR_FIRST_TOKEN = 1; |
| 26 | private static final int STATE_LOOKING_FOR_TOKEN = 2; |
| 27 | private static final int STATE_SCANNING_TOKEN = 3; |
| 28 | private static final int STATE_LOOKING_FOR_COMMA = 4; |
| 29 | private static final int STATE_PARSING_ERROR = 5; |
| 30 | private static final int STATE_DONE = 6; |
| 31 | |
| 32 | private int m_curPos; |
| 33 | private int m_scanStart; |
| 34 | private int m_state; |
| 35 | private String m_tokens; |
| 36 | |
| 37 | |
| 38 | TokenParser( |
| 39 | String tokens) |
| 40 | { |
| 41 | m_tokens = tokens; |
| 42 | m_curPos = 0; |
| 43 | m_scanStart = 0; |
| 44 | m_state = STATE_LOOKING_FOR_FIRST_TOKEN; |
| 45 | } |
| 46 | |
| 47 | /** |
| 48 | * This function parses the next token from the tokens string and returns |
| 49 | * it as a string. If there are no more tokens a null reference is returned. |
| 50 | * |
| 51 | * @return the parsed token or a null reference if there are no more |
| 52 | * tokens |
| 53 | * |
| 54 | * @exception SASLException if an error occurs while parsing |
| 55 | */ |
| 56 | String parseToken() throws SaslException |
| 57 | { |
| 58 | char currChar; |
| 59 | String token = null; |
| 60 | |
| 61 | |
| 62 | if (m_state == STATE_DONE) |
| 63 | return null; |
| 64 | |
| 65 | while (m_curPos < m_tokens.length() && (token == null)) |
| 66 | { |
| 67 | currChar = m_tokens.charAt(m_curPos); |
| 68 | switch (m_state) |
| 69 | { |
| 70 | case STATE_LOOKING_FOR_FIRST_TOKEN: |
| 71 | case STATE_LOOKING_FOR_TOKEN: |
| 72 | if (isWhiteSpace(currChar)) |
| 73 | { |
| 74 | break; |
| 75 | } |
| 76 | else if (isValidTokenChar(currChar)) |
| 77 | { |
| 78 | m_scanStart = m_curPos; |
| 79 | m_state = STATE_SCANNING_TOKEN; |
| 80 | } |
| 81 | else |
| 82 | { |
| 83 | m_state = STATE_PARSING_ERROR; |
| 84 | throw new SaslException("Invalid token character at position " + m_curPos); |
| 85 | } |
| 86 | break; |
| 87 | |
| 88 | case STATE_SCANNING_TOKEN: |
| 89 | if (isValidTokenChar(currChar)) |
| 90 | { |
| 91 | break; |
| 92 | } |
| 93 | else if (isWhiteSpace(currChar)) |
| 94 | { |
| 95 | token = m_tokens.substring(m_scanStart, m_curPos); |
| 96 | m_state = STATE_LOOKING_FOR_COMMA; |
| 97 | } |
| 98 | else if (',' == currChar) |
| 99 | { |
| 100 | token = m_tokens.substring(m_scanStart, m_curPos); |
| 101 | m_state = STATE_LOOKING_FOR_TOKEN; |
| 102 | } |
| 103 | else |
| 104 | { |
| 105 | m_state = STATE_PARSING_ERROR; |
| 106 | throw new SaslException("Invalid token character at position " + m_curPos); |
| 107 | } |
| 108 | break; |
| 109 | |
| 110 | |
| 111 | case STATE_LOOKING_FOR_COMMA: |
| 112 | if (isWhiteSpace(currChar)) |
| 113 | break; |
| 114 | else if (currChar == ',') |
| 115 | m_state = STATE_LOOKING_FOR_TOKEN; |
| 116 | else |
| 117 | { |
| 118 | m_state = STATE_PARSING_ERROR; |
| 119 | throw new SaslException("Expected a comma, found '" + |
| 120 | currChar + "' at postion " + |
| 121 | m_curPos); |
| 122 | } |
| 123 | break; |
| 124 | } |
| 125 | m_curPos++; |
| 126 | } /* end while loop */ |
| 127 | |
| 128 | if (token == null) |
| 129 | { /* check the ending state */ |
| 130 | switch (m_state) |
| 131 | { |
| 132 | case STATE_SCANNING_TOKEN: |
| 133 | token = m_tokens.substring(m_scanStart); |
| 134 | m_state = STATE_DONE; |
| 135 | break; |
| 136 | |
| 137 | case STATE_LOOKING_FOR_FIRST_TOKEN: |
| 138 | case STATE_LOOKING_FOR_COMMA: |
| 139 | break; |
| 140 | |
| 141 | case STATE_LOOKING_FOR_TOKEN: |
| 142 | throw new SaslException("Trialing comma"); |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | return token; |
| 147 | } |
| 148 | |
| 149 | /** |
| 150 | * This function returns TRUE if the character is a valid token character. |
| 151 | * |
| 152 | * token = 1*<any CHAR except CTLs or separators> |
| 153 | * |
| 154 | * separators = "(" | ")" | "<" | ">" | "@" |
| 155 | * | "," | ";" | ":" | "\" | <"> |
| 156 | * | "/" | "[" | "]" | "?" | "=" |
| 157 | * | "{" | "}" | SP | HT |
| 158 | * |
| 159 | * CTL = <any US-ASCII control character |
| 160 | * (octets 0 - 31) and DEL (127)> |
| 161 | * |
| 162 | * CHAR = <any US-ASCII character (octets 0 - 127)> |
| 163 | * |
| 164 | * @param c character to be validated |
| 165 | * |
| 166 | * @return True if character is valid Token character else it returns |
| 167 | * false |
| 168 | */ |
| 169 | boolean isValidTokenChar( |
| 170 | char c) |
| 171 | { |
| 172 | if ( ( (c >= '\u0000') && (c <='\u0020') ) || |
| 173 | ( (c >= '\u003a') && (c <= '\u0040') ) || |
| 174 | ( (c >= '\u005b') && (c <= '\u005d') ) || |
| 175 | ('\u002c' == c) || |
| 176 | ('\u0025' == c) || |
| 177 | ('\u0028' == c) || |
| 178 | ('\u0029' == c) || |
| 179 | ('\u007b' == c) || |
| 180 | ('\u007d' == c) || |
| 181 | ('\u007f' == c) ) |
| 182 | return false; |
| 183 | |
| 184 | return true; |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * This function returns TRUE if the character is linear white space (LWS). |
| 189 | * LWS = [CRLF] 1*( SP | HT ) |
| 190 | * |
| 191 | * @param c character to be validated |
| 192 | * |
| 193 | * @return True if character is liner whitespace else it returns false |
| 194 | */ |
| 195 | boolean isWhiteSpace( |
| 196 | char c) |
| 197 | { |
| 198 | if ( ('\t' == c) || // HORIZONTAL TABULATION. |
| 199 | ('\n' == c) || // LINE FEED. |
| 200 | ('\r' == c) || // CARRIAGE RETURN. |
| 201 | ('\u0020' == c) ) |
| 202 | return true; |
| 203 | |
| 204 | return false; |
| 205 | } |
| 206 | |
| 207 | } |
| 208 | |