View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.client5.http.impl.auth;
28  
29  import static org.hamcrest.MatcherAssert.assertThat;
30  
31  import java.util.List;
32  
33  import org.apache.hc.client5.http.NameValuePairMatcher;
34  import org.apache.hc.client5.http.auth.AuthChallenge;
35  import org.apache.hc.client5.http.auth.ChallengeType;
36  import org.apache.hc.client5.http.auth.StandardAuthScheme;
37  import org.apache.hc.core5.http.NameValuePair;
38  import org.apache.hc.core5.http.ParseException;
39  import org.apache.hc.core5.http.message.ParserCursor;
40  import org.apache.hc.core5.util.CharArrayBuffer;
41  import org.hamcrest.CoreMatchers;
42  import org.junit.jupiter.api.Assertions;
43  import org.junit.jupiter.api.BeforeEach;
44  import org.junit.jupiter.api.Test;
45  
46  public class TestAuthChallengeParser {
47  
48      private AuthChallengeParser parser;
49  
50      @BeforeEach
51      public void setUp() throws Exception {
52          this.parser = new AuthChallengeParser();
53      }
54  
55      @Test
56      public void testParseTokenTerminatedByBlank() throws Exception {
57          final CharArrayBuffer buffer = new CharArrayBuffer(64);
58          buffer.append("aaabbbbccc ");
59          final ParserCursor cursor = new ParserCursor(0, buffer.length());
60          assertThat(parser.parseToken(buffer, cursor), CoreMatchers.equalTo("aaabbbbccc"));
61      }
62  
63      @Test
64      public void testParseTokenTerminatedByComma() throws Exception {
65          final CharArrayBuffer buffer = new CharArrayBuffer(64);
66          buffer.append("aaabbbbccc, ");
67          final ParserCursor cursor = new ParserCursor(0, buffer.length());
68          assertThat(parser.parseToken(buffer, cursor), CoreMatchers.equalTo("aaabbbbccc"));
69      }
70  
71      @Test
72      public void testParseTokenTerminatedByEndOfStream() throws Exception {
73          final CharArrayBuffer buffer = new CharArrayBuffer(64);
74          buffer.append("aaabbbbccc");
75          final ParserCursor cursor = new ParserCursor(0, buffer.length());
76          assertThat(parser.parseToken(buffer, cursor), CoreMatchers.equalTo("aaabbbbccc"));
77      }
78  
79      @Test
80      public void testParsePaddedToken68() throws Exception {
81          final CharArrayBuffer buffer = new CharArrayBuffer(64);
82          buffer.append("aaabbbbccc==== ");
83          final ParserCursor cursor = new ParserCursor(0, buffer.length());
84          assertThat(parser.parseToken(buffer, cursor), CoreMatchers.equalTo("aaabbbbccc===="));
85          assertThat(cursor.atEnd(), CoreMatchers.equalTo(false));
86          assertThat(buffer.charAt(cursor.getPos()), CoreMatchers.equalTo(' '));
87      }
88  
89      @Test
90      public void testParsePaddedToken68SingleEqual() throws Exception {
91          final CharArrayBuffer buffer = new CharArrayBuffer(64);
92          buffer.append("aaabbbbccc=");
93          final ParserCursor cursor = new ParserCursor(0, buffer.length());
94          assertThat(parser.parseToken(buffer, cursor), CoreMatchers.equalTo("aaabbbbccc="));
95          assertThat(cursor.atEnd(), CoreMatchers.equalTo(true));
96      }
97  
98      @Test
99      public void testParsePaddedToken68MultipleEquals() throws Exception {
100         final CharArrayBuffer buffer = new CharArrayBuffer(16);
101         buffer.append("aaabbbbccc======");
102         final ParserCursor cursor = new ParserCursor(0, buffer.length());
103         assertThat(parser.parseToken(buffer, cursor), CoreMatchers.equalTo("aaabbbbccc======"));
104         assertThat(cursor.atEnd(), CoreMatchers.equalTo(true));
105     }
106 
107     @Test
108     public void testParsePaddedToken68TerminatedByComma() throws Exception {
109         final CharArrayBuffer buffer = new CharArrayBuffer(64);
110         buffer.append("aaabbbbccc====,");
111         final ParserCursor cursor = new ParserCursor(0, buffer.length());
112         assertThat(parser.parseToken(buffer, cursor), CoreMatchers.equalTo("aaabbbbccc===="));
113         assertThat(cursor.atEnd(), CoreMatchers.equalTo(false));
114         assertThat(buffer.charAt(cursor.getPos()), CoreMatchers.equalTo(','));
115     }
116 
117     @Test
118     public void testParseTokenTerminatedByParameter() throws Exception {
119         final CharArrayBuffer buffer = new CharArrayBuffer(64);
120         buffer.append("aaabbbbccc=blah");
121         final ParserCursor cursor = new ParserCursor(0, buffer.length());
122         assertThat(parser.parseToken(buffer, cursor), CoreMatchers.equalTo("aaabbbbccc"));
123         assertThat(cursor.atEnd(), CoreMatchers.equalTo(false));
124         assertThat(buffer.charAt(cursor.getPos()), CoreMatchers.equalTo('='));
125     }
126 
127     @Test
128     public void testParseBasicAuthChallenge() throws Exception {
129         final CharArrayBuffer buffer = new CharArrayBuffer(64);
130         buffer.append(StandardAuthScheme.BASIC + " realm=blah");
131         final ParserCursor cursor = new ParserCursor(0, buffer.length());
132         final List<AuthChallenge> challenges = parser.parse(ChallengeType.TARGET, buffer, cursor);
133         Assertions.assertNotNull(challenges);
134         Assertions.assertEquals(1, challenges.size());
135         final AuthChallenge challenge1 = challenges.get(0);
136         Assertions.assertEquals(StandardAuthScheme.BASIC, challenge1.getSchemeName());
137         Assertions.assertNull(challenge1.getValue());
138         final List<NameValuePair> params = challenge1.getParams();
139         Assertions.assertNotNull(params);
140         Assertions.assertEquals(1, params.size());
141         assertThat(params.get(0), NameValuePairMatcher.equals("realm", "blah"));
142     }
143 
144     @Test
145     public void testParseAuthChallengeWithBlanks() throws Exception {
146         final CharArrayBuffer buffer = new CharArrayBuffer(64);
147         buffer.append("   " + StandardAuthScheme.BASIC + "  realm = blah   ");
148         final ParserCursor cursor = new ParserCursor(0, buffer.length());
149         final List<AuthChallenge> challenges = parser.parse(ChallengeType.TARGET, buffer, cursor);
150         Assertions.assertNotNull(challenges);
151         Assertions.assertEquals(1, challenges.size());
152         final AuthChallenge challenge1 = challenges.get(0);
153         Assertions.assertEquals(StandardAuthScheme.BASIC, challenge1.getSchemeName());
154         Assertions.assertNull(challenge1.getValue());
155         final List<NameValuePair> params = challenge1.getParams();
156         Assertions.assertNotNull(params);
157         Assertions.assertEquals(1, params.size());
158         assertThat(params.get(0), NameValuePairMatcher.equals("realm", "blah"));
159     }
160 
161     @Test
162     public void testParseMultipleAuthChallenge() throws Exception {
163         final CharArrayBuffer buffer = new CharArrayBuffer(64);
164         buffer.append("This  xxxxxxxxxxxxxxxxxxxxxx, " +
165                 "That yyyyyyyyyyyyyyyyyyyyyy  ");
166         final ParserCursor cursor = new ParserCursor(0, buffer.length());
167         final List<AuthChallenge> challenges = parser.parse(ChallengeType.TARGET, buffer, cursor);
168         Assertions.assertNotNull(challenges);
169         Assertions.assertEquals(2, challenges.size());
170 
171         final AuthChallenge challenge1 = challenges.get(0);
172         Assertions.assertEquals("This", challenge1.getSchemeName());
173         Assertions.assertEquals("xxxxxxxxxxxxxxxxxxxxxx", challenge1.getValue());
174         Assertions.assertNull(challenge1.getParams());
175 
176         final AuthChallenge challenge2 = challenges.get(1);
177         Assertions.assertEquals("That", challenge2.getSchemeName());
178         Assertions.assertEquals("yyyyyyyyyyyyyyyyyyyyyy", challenge2.getValue());
179         Assertions.assertNull(challenge2.getParams());
180     }
181 
182     @Test
183     public void testParseMultipleAuthChallengeWithParams() throws Exception {
184         final CharArrayBuffer buffer = new CharArrayBuffer(64);
185         buffer.append(StandardAuthScheme.BASIC + " realm=blah, param1 = this, param2=that, " +
186                 StandardAuthScheme.BASIC + " realm=\"\\\"yada\\\"\", this, that=,this-and-that  ");
187         final ParserCursor cursor = new ParserCursor(0, buffer.length());
188         final List<AuthChallenge> challenges = parser.parse(ChallengeType.TARGET, buffer, cursor);
189         Assertions.assertNotNull(challenges);
190         Assertions.assertEquals(2, challenges.size());
191 
192         final AuthChallenge challenge1 = challenges.get(0);
193         Assertions.assertEquals(StandardAuthScheme.BASIC, challenge1.getSchemeName());
194         Assertions.assertNull(challenge1.getValue());
195         final List<NameValuePair> params1 = challenge1.getParams();
196         Assertions.assertNotNull(params1);
197         Assertions.assertEquals(3, params1.size());
198         assertThat(params1.get(0), NameValuePairMatcher.equals("realm", "blah"));
199         assertThat(params1.get(1), NameValuePairMatcher.equals("param1", "this"));
200         assertThat(params1.get(2), NameValuePairMatcher.equals("param2", "that"));
201 
202         final AuthChallenge challenge2 = challenges.get(1);
203         Assertions.assertEquals(StandardAuthScheme.BASIC, challenge2.getSchemeName());
204         Assertions.assertNull(challenge2.getValue());
205         final List<NameValuePair> params2 = challenge2.getParams();
206         Assertions.assertNotNull(params2);
207         Assertions.assertEquals(4, params2.size());
208         assertThat(params2.get(0), NameValuePairMatcher.equals("realm", "\"yada\""));
209         assertThat(params2.get(1), NameValuePairMatcher.equals("this", null));
210         assertThat(params2.get(2), NameValuePairMatcher.equals("that", ""));
211         assertThat(params2.get(3), NameValuePairMatcher.equals("this-and-that", null));
212     }
213 
214     @Test
215     public void testParseMultipleAuthChallengeWithParamsContainingComma() throws Exception {
216         final CharArrayBuffer buffer = new CharArrayBuffer(64);
217         buffer.append(StandardAuthScheme.BASIC + " realm=blah, param1 = \"this, param2=that\", " +
218                 StandardAuthScheme.BASIC + " realm=\"\\\"yada,,,,\\\"\"");
219         final ParserCursor cursor = new ParserCursor(0, buffer.length());
220         final List<AuthChallenge> challenges = parser.parse(ChallengeType.TARGET, buffer, cursor);
221         Assertions.assertNotNull(challenges);
222         Assertions.assertEquals(2, challenges.size());
223 
224         final AuthChallenge challenge1 = challenges.get(0);
225         Assertions.assertEquals(StandardAuthScheme.BASIC, challenge1.getSchemeName());
226         Assertions.assertNull(challenge1.getValue());
227         final List<NameValuePair> params1 = challenge1.getParams();
228         Assertions.assertNotNull(params1);
229         Assertions.assertEquals(2, params1.size());
230         assertThat(params1.get(0), NameValuePairMatcher.equals("realm", "blah"));
231         assertThat(params1.get(1), NameValuePairMatcher.equals("param1", "this, param2=that"));
232 
233         final AuthChallenge challenge2 = challenges.get(1);
234         Assertions.assertEquals(StandardAuthScheme.BASIC, challenge2.getSchemeName());
235         Assertions.assertNull(challenge2.getValue());
236         final List<NameValuePair> params2 = challenge2.getParams();
237         Assertions.assertNotNull(params2);
238         Assertions.assertEquals(1, params2.size());
239         assertThat(params2.get(0), NameValuePairMatcher.equals("realm", "\"yada,,,,\""));
240     }
241 
242     @Test
243     public void testParseEmptyAuthChallenge1() throws Exception {
244         final CharArrayBuffer buffer = new CharArrayBuffer(64);
245         buffer.append("This");
246         final ParserCursor cursor = new ParserCursor(0, buffer.length());
247         final List<AuthChallenge> challenges = parser.parse(ChallengeType.TARGET, buffer, cursor);
248         Assertions.assertNotNull(challenges);
249         Assertions.assertEquals(1, challenges.size());
250 
251         final AuthChallenge challenge1 = challenges.get(0);
252         Assertions.assertEquals("This", challenge1.getSchemeName());
253         Assertions.assertNull(challenge1.getValue());
254         Assertions.assertNull(challenge1.getParams());
255     }
256 
257     @Test
258     public void testParseMalformedAuthChallenge1() throws Exception {
259         final CharArrayBuffer buffer = new CharArrayBuffer(64);
260         buffer.append("This , ");
261         final ParserCursor cursor = new ParserCursor(0, buffer.length());
262         Assertions.assertThrows(ParseException.class, () ->
263                 parser.parse(ChallengeType.TARGET, buffer, cursor));
264     }
265 
266     @Test
267     public void testParseMalformedAuthChallenge2() throws Exception {
268         final CharArrayBuffer buffer = new CharArrayBuffer(64);
269         buffer.append("This = that");
270         final ParserCursor cursor = new ParserCursor(0, buffer.length());
271         Assertions.assertThrows(ParseException.class, () ->
272                 parser.parse(ChallengeType.TARGET, buffer, cursor));
273     }
274 
275     @Test
276     public void testParseMalformedAuthChallenge3() throws Exception {
277         final CharArrayBuffer buffer = new CharArrayBuffer(64);
278         buffer.append("blah blah blah");
279         final ParserCursor cursor = new ParserCursor(0, buffer.length());
280         Assertions.assertThrows(ParseException.class, () ->
281                 parser.parse(ChallengeType.TARGET, buffer, cursor));
282     }
283 
284     @Test
285     public void testParseValidAuthChallenge1() throws Exception {
286         final CharArrayBuffer buffer = new CharArrayBuffer(64);
287         buffer.append("blah blah");
288         final ParserCursor cursor = new ParserCursor(0, buffer.length());
289         final List<AuthChallenge> challenges = parser.parse(ChallengeType.TARGET, buffer, cursor);
290         Assertions.assertNotNull(challenges);
291         Assertions.assertEquals(1, challenges.size());
292 
293         final AuthChallenge challenge1 = challenges.get(0);
294         Assertions.assertEquals("blah", challenge1.getSchemeName());
295         Assertions.assertEquals("blah", challenge1.getValue());
296         Assertions.assertNull(challenge1.getParams());
297     }
298 
299     @Test
300     public void testParseValidAuthChallenge2() throws Exception {
301         final CharArrayBuffer buffer = new CharArrayBuffer(64);
302         buffer.append("blah blah, blah");
303         final ParserCursor cursor = new ParserCursor(0, buffer.length());
304         final List<AuthChallenge> challenges = parser.parse(ChallengeType.TARGET, buffer, cursor);
305         Assertions.assertNotNull(challenges);
306         Assertions.assertEquals(1, challenges.size());
307 
308         final AuthChallenge challenge1 = challenges.get(0);
309         Assertions.assertEquals("blah", challenge1.getSchemeName());
310         Assertions.assertNull(challenge1.getValue());
311         final List<NameValuePair> params1 = challenge1.getParams();
312         Assertions.assertNotNull(params1);
313         Assertions.assertEquals(2, params1.size());
314         assertThat(params1.get(0), NameValuePairMatcher.equals("blah", null));
315         assertThat(params1.get(1), NameValuePairMatcher.equals("blah", null));
316     }
317 
318     @Test
319     public void testParseEmptyNTLMAuthChallenge() throws Exception {
320         final CharArrayBuffer buffer = new CharArrayBuffer(64);
321         buffer.append(StandardAuthScheme.NTLM);
322         final ParserCursor cursor = new ParserCursor(0, buffer.length());
323         final List<AuthChallenge> challenges = parser.parse(ChallengeType.TARGET, buffer, cursor);
324         Assertions.assertNotNull(challenges);
325         Assertions.assertEquals(1, challenges.size());
326         final AuthChallenge challenge1 = challenges.get(0);
327         Assertions.assertEquals(StandardAuthScheme.NTLM, challenge1.getSchemeName());
328         Assertions.assertNull(challenge1.getValue());
329     }
330 
331     @Test
332     public void testParseParameterAndToken68AuthChallengeMix() throws Exception {
333         final CharArrayBuffer buffer = new CharArrayBuffer(64);
334         buffer.append("scheme1 aaaa  , scheme2 aaaa==,  scheme3 aaaa=aaaa, scheme4 aaaa=");
335         final ParserCursor cursor = new ParserCursor(0, buffer.length());
336         final List<AuthChallenge> challenges = parser.parse(ChallengeType.TARGET, buffer, cursor);
337         Assertions.assertNotNull(challenges);
338         Assertions.assertEquals(4, challenges.size());
339         final AuthChallenge challenge1 = challenges.get(0);
340         assertThat(challenge1.getSchemeName(), CoreMatchers.equalTo("scheme1"));
341         assertThat(challenge1.getValue(), CoreMatchers.equalTo("aaaa"));
342         assertThat(challenge1.getParams(), CoreMatchers.nullValue());
343         final AuthChallenge challenge2 = challenges.get(1);
344         assertThat(challenge2.getSchemeName(), CoreMatchers.equalTo("scheme2"));
345         assertThat(challenge2.getValue(), CoreMatchers.equalTo("aaaa=="));
346         assertThat(challenge2.getParams(), CoreMatchers.nullValue());
347         final AuthChallenge challenge3 = challenges.get(2);
348         assertThat(challenge3.getSchemeName(), CoreMatchers.equalTo("scheme3"));
349         assertThat(challenge3.getValue(), CoreMatchers.nullValue());
350         assertThat(challenge3.getParams(), CoreMatchers.notNullValue());
351         assertThat(challenge3.getParams().size(), CoreMatchers.equalTo(1));
352         assertThat(challenge3.getParams().get(0), NameValuePairMatcher.equals("aaaa", "aaaa"));
353         final AuthChallenge challenge4 = challenges.get(3);
354         assertThat(challenge4.getSchemeName(), CoreMatchers.equalTo("scheme4"));
355         assertThat(challenge4.getValue(), CoreMatchers.equalTo("aaaa="));
356         assertThat(challenge4.getParams(), CoreMatchers.nullValue());
357     }
358 
359 }