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