001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027package org.apache.http.impl.auth; 028 029import java.util.Locale; 030 031import org.apache.http.FormattedHeader; 032import org.apache.http.Header; 033import org.apache.http.HttpRequest; 034import org.apache.http.auth.AUTH; 035import org.apache.http.auth.AuthenticationException; 036import org.apache.http.auth.ChallengeState; 037import org.apache.http.auth.ContextAwareAuthScheme; 038import org.apache.http.auth.Credentials; 039import org.apache.http.auth.MalformedChallengeException; 040import org.apache.http.protocol.HTTP; 041import org.apache.http.protocol.HttpContext; 042import org.apache.http.util.Args; 043import org.apache.http.util.CharArrayBuffer; 044 045/** 046 * Abstract authentication scheme class that serves as a basis 047 * for all authentication schemes supported by HttpClient. This class 048 * defines the generic way of parsing an authentication challenge. It 049 * does not make any assumptions regarding the format of the challenge 050 * nor does it impose any specific way of responding to that challenge. 051 * 052 * 053 * @since 4.0 054 */ 055public abstract class AuthSchemeBase implements ContextAwareAuthScheme { 056 057 protected ChallengeState challengeState; 058 059 /** 060 * Creates an instance of {@code AuthSchemeBase} with the given challenge 061 * state. 062 * 063 * @since 4.2 064 * 065 * @deprecated (4.3) do not use. 066 */ 067 @Deprecated 068 public AuthSchemeBase(final ChallengeState challengeState) { 069 super(); 070 this.challengeState = challengeState; 071 } 072 073 public AuthSchemeBase() { 074 super(); 075 } 076 077 /** 078 * Processes the given challenge token. Some authentication schemes 079 * may involve multiple challenge-response exchanges. Such schemes must be able 080 * to maintain the state information when dealing with sequential challenges 081 * 082 * @param header the challenge header 083 * 084 * @throws MalformedChallengeException is thrown if the authentication challenge 085 * is malformed 086 */ 087 @Override 088 public void processChallenge(final Header header) throws MalformedChallengeException { 089 Args.notNull(header, "Header"); 090 final String authheader = header.getName(); 091 if (authheader.equalsIgnoreCase(AUTH.WWW_AUTH)) { 092 this.challengeState = ChallengeState.TARGET; 093 } else if (authheader.equalsIgnoreCase(AUTH.PROXY_AUTH)) { 094 this.challengeState = ChallengeState.PROXY; 095 } else { 096 throw new MalformedChallengeException("Unexpected header name: " + authheader); 097 } 098 099 final CharArrayBuffer buffer; 100 int pos; 101 if (header instanceof FormattedHeader) { 102 buffer = ((FormattedHeader) header).getBuffer(); 103 pos = ((FormattedHeader) header).getValuePos(); 104 } else { 105 final String s = header.getValue(); 106 if (s == null) { 107 throw new MalformedChallengeException("Header value is null"); 108 } 109 buffer = new CharArrayBuffer(s.length()); 110 buffer.append(s); 111 pos = 0; 112 } 113 while (pos < buffer.length() && HTTP.isWhitespace(buffer.charAt(pos))) { 114 pos++; 115 } 116 final int beginIndex = pos; 117 while (pos < buffer.length() && !HTTP.isWhitespace(buffer.charAt(pos))) { 118 pos++; 119 } 120 final int endIndex = pos; 121 final String s = buffer.substring(beginIndex, endIndex); 122 if (!s.equalsIgnoreCase(getSchemeName())) { 123 throw new MalformedChallengeException("Invalid scheme identifier: " + s); 124 } 125 126 parseChallenge(buffer, pos, buffer.length()); 127 } 128 129 130 @Override 131 @SuppressWarnings("deprecation") 132 public Header authenticate( 133 final Credentials credentials, 134 final HttpRequest request, 135 final HttpContext context) throws AuthenticationException { 136 return authenticate(credentials, request); 137 } 138 139 protected abstract void parseChallenge( 140 CharArrayBuffer buffer, int beginIndex, int endIndex) throws MalformedChallengeException; 141 142 /** 143 * Returns {@code true} if authenticating against a proxy, {@code false} 144 * otherwise. 145 */ 146 public boolean isProxy() { 147 return this.challengeState != null && this.challengeState == ChallengeState.PROXY; 148 } 149 150 /** 151 * Returns {@link ChallengeState} value or {@code null} if unchallenged. 152 * 153 * @since 4.2 154 */ 155 public ChallengeState getChallengeState() { 156 return this.challengeState; 157 } 158 159 @Override 160 public String toString() { 161 final String name = getSchemeName(); 162 if (name != null) { 163 return name.toUpperCase(Locale.ROOT); 164 } else { 165 return super.toString(); 166 } 167 } 168 169}