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.auth; 028 029import java.util.Locale; 030 031import org.apache.http.HttpHost; 032import org.apache.http.annotation.Contract; 033import org.apache.http.annotation.ThreadingBehavior; 034import org.apache.http.util.Args; 035import org.apache.http.util.LangUtils; 036 037/** 038 * {@code AuthScope} represents an authentication scope consisting of a host name, 039 * a port number, a realm name and an authentication scheme name. 040 * <p> 041 * This class can also optionally contain a host of origin, if created in response 042 * to authentication challenge from a specific host. 043 * </p> 044 * @since 4.0 045 */ 046@Contract(threading = ThreadingBehavior.IMMUTABLE) 047public class AuthScope { 048 049 /** 050 * The {@code null} value represents any host. In the future versions of 051 * HttpClient the use of this parameter will be discontinued. 052 */ 053 public static final String ANY_HOST = null; 054 055 /** 056 * The {@code -1} value represents any port. 057 */ 058 public static final int ANY_PORT = -1; 059 060 /** 061 * The {@code null} value represents any realm. 062 */ 063 public static final String ANY_REALM = null; 064 065 /** 066 * The {@code null} value represents any authentication scheme. 067 */ 068 public static final String ANY_SCHEME = null; 069 070 /** 071 * Default scope matching any host, port, realm and authentication scheme. 072 * In the future versions of HttpClient the use of this parameter will be 073 * discontinued. 074 */ 075 public static final AuthScope ANY = new AuthScope(ANY_HOST, ANY_PORT, ANY_REALM, ANY_SCHEME); 076 077 /** The authentication scheme the credentials apply to. */ 078 private final String scheme; 079 080 /** The realm the credentials apply to. */ 081 private final String realm; 082 083 /** The host the credentials apply to. */ 084 private final String host; 085 086 /** The port the credentials apply to. */ 087 private final int port; 088 089 /** The original host, if known */ 090 private final HttpHost origin; 091 092 /** 093 * Defines auth scope with the given {@code host}, {@code port}, {@code realm}, and 094 * {@code schemeName}. 095 * 096 * @param host authentication host. May be {@link #ANY_HOST} if applies 097 * to any host. 098 * @param port authentication port. May be {@link #ANY_PORT} if applies 099 * to any port of the host. 100 * @param realm authentication realm. May be {@link #ANY_REALM} if applies 101 * to any realm on the host. 102 * @param schemeName authentication scheme. May be {@link #ANY_SCHEME} if applies 103 * to any scheme supported by the host. 104 */ 105 public AuthScope( 106 final String host, 107 final int port, 108 final String realm, 109 final String schemeName) { 110 this.host = host == null ? ANY_HOST: host.toLowerCase(Locale.ROOT); 111 this.port = port < 0 ? ANY_PORT : port; 112 this.realm = realm == null ? ANY_REALM : realm; 113 this.scheme = schemeName == null ? ANY_SCHEME : schemeName.toUpperCase(Locale.ROOT); 114 this.origin = null; 115 } 116 117 /** 118 * Defines auth scope for a specific host of origin. 119 * 120 * @param origin host of origin 121 * @param realm authentication realm. May be {@link #ANY_REALM} if applies 122 * to any realm on the host. 123 * @param schemeName authentication scheme. May be {@link #ANY_SCHEME} if applies 124 * to any scheme supported by the host. 125 * 126 * @since 4.2 127 */ 128 public AuthScope( 129 final HttpHost origin, 130 final String realm, 131 final String schemeName) { 132 Args.notNull(origin, "Host"); 133 this.host = origin.getHostName().toLowerCase(Locale.ROOT); 134 this.port = origin.getPort() < 0 ? ANY_PORT : origin.getPort(); 135 this.realm = realm == null ? ANY_REALM : realm; 136 this.scheme = schemeName == null ? ANY_SCHEME : schemeName.toUpperCase(Locale.ROOT); 137 this.origin = origin; 138 } 139 140 /** 141 * Defines auth scope for a specific host of origin. 142 * 143 * @param origin host of origin 144 * 145 * @since 4.2 146 */ 147 public AuthScope(final HttpHost origin) { 148 this(origin, ANY_REALM, ANY_SCHEME); 149 } 150 151 /** 152 * Defines auth scope with the given {@code host}, {@code port} and {@code realm}. 153 * 154 * @param host authentication host. May be {@link #ANY_HOST} if applies 155 * to any host. 156 * @param port authentication port. May be {@link #ANY_PORT} if applies 157 * to any port of the host. 158 * @param realm authentication realm. May be {@link #ANY_REALM} if applies 159 * to any realm on the host. 160 */ 161 public AuthScope(final String host, final int port, final String realm) { 162 this(host, port, realm, ANY_SCHEME); 163 } 164 165 /** 166 * Defines auth scope with the given {@code host} and {@code port}. 167 * 168 * @param host authentication host. May be {@link #ANY_HOST} if applies 169 * to any host. 170 * @param port authentication port. May be {@link #ANY_PORT} if applies 171 * to any port of the host. 172 */ 173 public AuthScope(final String host, final int port) { 174 this(host, port, ANY_REALM, ANY_SCHEME); 175 } 176 177 /** 178 * Creates a copy of the given credentials scope. 179 */ 180 public AuthScope(final AuthScope authscope) { 181 super(); 182 Args.notNull(authscope, "Scope"); 183 this.host = authscope.getHost(); 184 this.port = authscope.getPort(); 185 this.realm = authscope.getRealm(); 186 this.scheme = authscope.getScheme(); 187 this.origin = authscope.getOrigin(); 188 } 189 190 /** 191 * @return host of origin. If unknown returns @null, 192 * 193 * @since 4.4 194 */ 195 public HttpHost getOrigin() { 196 return this.origin; 197 } 198 199 /** 200 * @return the host 201 */ 202 public String getHost() { 203 return this.host; 204 } 205 206 /** 207 * @return the port 208 */ 209 public int getPort() { 210 return this.port; 211 } 212 213 /** 214 * @return the realm name 215 */ 216 public String getRealm() { 217 return this.realm; 218 } 219 220 /** 221 * @return the scheme type 222 */ 223 public String getScheme() { 224 return this.scheme; 225 } 226 227 /** 228 * Tests if the authentication scopes match. 229 * 230 * @return the match factor. Negative value signifies no match. 231 * Non-negative signifies a match. The greater the returned value 232 * the closer the match. 233 */ 234 public int match(final AuthScope that) { 235 int factor = 0; 236 if (LangUtils.equals(this.scheme, that.scheme)) { 237 factor += 1; 238 } else { 239 if (this.scheme != ANY_SCHEME && that.scheme != ANY_SCHEME) { 240 return -1; 241 } 242 } 243 if (LangUtils.equals(this.realm, that.realm)) { 244 factor += 2; 245 } else { 246 if (this.realm != ANY_REALM && that.realm != ANY_REALM) { 247 return -1; 248 } 249 } 250 if (this.port == that.port) { 251 factor += 4; 252 } else { 253 if (this.port != ANY_PORT && that.port != ANY_PORT) { 254 return -1; 255 } 256 } 257 if (LangUtils.equals(this.host, that.host)) { 258 factor += 8; 259 } else { 260 if (this.host != ANY_HOST && that.host != ANY_HOST) { 261 return -1; 262 } 263 } 264 return factor; 265 } 266 267 /** 268 * @see java.lang.Object#equals(Object) 269 */ 270 @Override 271 public boolean equals(final Object o) { 272 if (o == null) { 273 return false; 274 } 275 if (o == this) { 276 return true; 277 } 278 if (!(o instanceof AuthScope)) { 279 return super.equals(o); 280 } 281 final AuthScope that = (AuthScope) o; 282 return 283 LangUtils.equals(this.host, that.host) 284 && this.port == that.port 285 && LangUtils.equals(this.realm, that.realm) 286 && LangUtils.equals(this.scheme, that.scheme); 287 } 288 289 /** 290 * @see java.lang.Object#toString() 291 */ 292 @Override 293 public String toString() { 294 final StringBuilder buffer = new StringBuilder(); 295 if (this.scheme != null) { 296 buffer.append(this.scheme.toUpperCase(Locale.ROOT)); 297 buffer.append(' '); 298 } 299 if (this.realm != null) { 300 buffer.append('\''); 301 buffer.append(this.realm); 302 buffer.append('\''); 303 } else { 304 buffer.append("<any realm>"); 305 } 306 if (this.host != null) { 307 buffer.append('@'); 308 buffer.append(this.host); 309 if (this.port >= 0) { 310 buffer.append(':'); 311 buffer.append(this.port); 312 } 313 } 314 return buffer.toString(); 315 } 316 317 /** 318 * @see java.lang.Object#hashCode() 319 */ 320 @Override 321 public int hashCode() { 322 int hash = LangUtils.HASH_SEED; 323 hash = LangUtils.hashCode(hash, this.host); 324 hash = LangUtils.hashCode(hash, this.port); 325 hash = LangUtils.hashCode(hash, this.realm); 326 hash = LangUtils.hashCode(hash, this.scheme); 327 return hash; 328 } 329}