Skip to content

Commit

Permalink
RFC 7231: parse capable of parsing multiple auth challenges
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1687909 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
ok2c committed Jun 27, 2015
1 parent fb56b49 commit 11612ab
Show file tree
Hide file tree
Showing 4 changed files with 560 additions and 0 deletions.
83 changes: 83 additions & 0 deletions httpclient/src/main/java/org/apache/http/auth/AuthChallenge.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.auth;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.annotation.Immutable;
import org.apache.http.util.Args;

/**
* This class represents an authentication challenge consisting of a auth scheme
* and either a single parameter or a list of name / value pairs.
*
* @since 5.0
*/
@Immutable
public final class AuthChallenge {

private final String scheme;
private final String value;
private final List<NameValuePair> params;

public AuthChallenge(final String scheme, final String value, final List<? extends NameValuePair> params) {
super();
Args.notNull(scheme, "Auth scheme");
this.scheme = scheme;
this.value = value;
this.params = params != null ? Collections.unmodifiableList(new ArrayList<>(params)) : null;
}

public String getScheme() {
return scheme;
}

public String getValue() {
return value;
}

public List<NameValuePair> getParams() {
return params;
}

@Override
public String toString() {
final StringBuilder buffer = new StringBuilder();
buffer.append(scheme).append(" ");
if (value != null) {
buffer.append(value);
} else if (params != null) {
buffer.append(params);
}
return buffer.toString();
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/

package org.apache.http.impl.auth;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.message.ParserCursor;
import org.apache.http.message.TokenParser;
import org.apache.http.util.CharArrayBuffer;

public class AuthChallengeParser {

private final TokenParser tokenParser = TokenParser.INSTANCE;

private final static char BLANK = ' ';
private final static char COMMA_CHAR = ',';
private final static char EQUAL_CHAR = '=';

// IMPORTANT!
// These private static variables must be treated as immutable and never exposed outside this class
private static final BitSet TERMINATORS = TokenParser.INIT_BITSET(BLANK, EQUAL_CHAR, COMMA_CHAR);
private static final BitSet DELIMITER = TokenParser.INIT_BITSET(COMMA_CHAR);

NameValuePair parseTokenOrParameter(final CharArrayBuffer buffer, final ParserCursor cursor) throws ParseException {

tokenParser.skipWhiteSpace(buffer, cursor);
final String token = tokenParser.parseToken(buffer, cursor, TERMINATORS);
if (!cursor.atEnd()) {
if (buffer.charAt(cursor.getPos()) == BLANK) {
tokenParser.skipWhiteSpace(buffer, cursor);
}
if (buffer.charAt(cursor.getPos()) == EQUAL_CHAR) {
cursor.updatePos(cursor.getPos() + 1);
final String value = tokenParser.parseValue(buffer, cursor, DELIMITER);
return new BasicNameValuePair(token, value);
}
}
return new BasicNameValuePair(token, null);
}

public List<AuthChallenge> parse(final CharArrayBuffer buffer, final ParserCursor cursor) throws ParseException {

final List<AuthChallenge> list = new ArrayList<>();
String scheme = null;
final List<NameValuePair> params = new ArrayList<>();
while (!cursor.atEnd()) {
final NameValuePair tokenOrParameter = parseTokenOrParameter(buffer, cursor);
if (tokenOrParameter.getValue() == null && !cursor.atEnd() && buffer.charAt(cursor.getPos()) != COMMA_CHAR) {
if (scheme != null) {
if (params.isEmpty()) {
throw new ParseException("Malformed auth challenge");
}
list.add(createAuthChallenge(scheme, params));
params.clear();
}
scheme = tokenOrParameter.getName();
} else {
params.add(tokenOrParameter);
if (!cursor.atEnd() && buffer.charAt(cursor.getPos()) != COMMA_CHAR) {
scheme = null;
}
}
if (!cursor.atEnd() && buffer.charAt(cursor.getPos()) == COMMA_CHAR) {
cursor.updatePos(cursor.getPos() + 1);
}
}
list.add(createAuthChallenge(scheme, params));
return list;
}

private static AuthChallenge createAuthChallenge(final String scheme, final List<NameValuePair> params) {
if (scheme != null) {
if (params.size() == 1) {
final NameValuePair nvp = params.get(0);
if (nvp.getValue() == null) {
return new AuthChallenge(scheme, nvp.getName(), null);
}
}
return new AuthChallenge(scheme, null, params.size() > 0 ? params : null);
} else {
if (params.size() == 1) {
final NameValuePair nvp = params.get(0);
if (nvp.getValue() == null) {
return new AuthChallenge(nvp.getName(), null, null);
}
}
throw new ParseException("Malformed auth challenge");
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/

package org.apache.http.auth;

import java.util.Arrays;

import org.apache.http.message.BasicNameValuePair;
import org.junit.Assert;
import org.junit.Test;

public class TestAuthChallenge {

@Test
public void testAuthChallengeWithValue() {
final AuthChallenge authChallenge = new AuthChallenge("Basic", "blah", null);
Assert.assertEquals("Basic", authChallenge.getScheme());
Assert.assertEquals("blah", authChallenge.getValue());
Assert.assertEquals(null, authChallenge.getParams());
Assert.assertEquals("Basic blah", authChallenge.toString());
}

@Test
public void testAuthChallengeWithParams() {
final AuthChallenge authChallenge = new AuthChallenge("Basic", null,
Arrays.asList(new BasicNameValuePair("blah", "this"), new BasicNameValuePair("blah", "that")));
Assert.assertEquals("Basic", authChallenge.getScheme());
Assert.assertEquals(null, authChallenge.getValue());
Assert.assertNotNull(authChallenge.getParams());
Assert.assertEquals("Basic [blah=this, blah=that]", authChallenge.toString());
}

}
Loading

0 comments on commit 11612ab

Please sign in to comment.