/* Copyright (c) 2008 Google Inc.
*
* Licensed 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.
*/
package com.google.gdata.util;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* The AuthenticationException class is used to represent a GData service
* failure due to authentication.
*
*
*/
public class AuthenticationException extends ServiceException {
private String authHeader;
private String scheme;
private Map<String,String> parameters = new HashMap<String,String>();
/**
* Constructs a new AuthenticationException instance based upon
* the contents of a WWW-Authenticate header as described by
* RFC2617.
*/
public AuthenticationException(String message, String authHeader) {
super(message);
initFromAuthHeader(authHeader);
}
/**
* Creates a new AuthenticationException without any authentication
* header information. The WWW-Authenticate header will have
* to be set separately to build a valid HTTP 401 error response.
*/
public AuthenticationException(String message) {
super(message);
}
/**
* Constructs a new AuthenticationException using header and error
* stream information from an HTTP connection.
*/
public AuthenticationException(HttpURLConnection httpConn)
throws IOException {
super(httpConn);
initFromAuthHeader(httpConn.getHeaderField("WWW-Authenticate"));
}
// Used to extract scheme info from the WWW-Authenticate header.
private static final Pattern SCHEME_PATTERN =
Pattern.compile("([^\\s$]*)\\s*(.*)?");
private static String TOKEN =
"[\\p{ASCII}&&[^\\p{Cntrl} \t;/=\\[\\]\\(\\)\\<\\>\\@\\,\\:\\\"\\?\\=]]+";
// Used to extract auth params from the WWW-Authenticate header.
private static final Pattern PARAM_PATTERN =
Pattern.compile(
"(" + TOKEN + ")" + // param name (G1)
"\\s*=\\s*" +
"(?:" +
"\"([^\"]*)\"" + // value as quoted string (G2)
"|" +
"(" + TOKEN + ")?" + // value as token (G3)
")");
/**
* Initializes internal state from the contents of a WWW-Authenticate
* header.
*/
private void initFromAuthHeader(String authHeader) {
this.authHeader = authHeader;
if (authHeader == null)
throw new NullPointerException("No authentication header information");
Matcher authMatcher = SCHEME_PATTERN.matcher(authHeader);
if (!authMatcher.matches()) {
throw new IllegalStateException("Unable to parse auth header: " +
authHeader);
}
scheme = authMatcher.group(1);
if (authMatcher.groupCount() > 1) {
Matcher paramMatcher = PARAM_PATTERN.matcher(authMatcher.group(2));
while (paramMatcher.find()) {
String value = paramMatcher.group(2);
if (value == null) {
value = paramMatcher.group(3);
}
parameters.put(paramMatcher.group(1), value);
}
}
}
public String getScheme() {
return scheme;
}
public String getRealm() {
return parameters.get("realm");
}
public Map<String,String> getParameters() {
return Collections.unmodifiableMap(parameters);
}
public String getAuthHeader() {
return authHeader;
}
}