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 ******************************************************************************/ 15package com.novell.sasl.client; 16 17import 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 */ 23class 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 209