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.auth;
28  
29  import java.util.Locale;
30  
31  import org.apache.hc.core5.annotation.Contract;
32  import org.apache.hc.core5.annotation.ThreadingBehavior;
33  import org.apache.hc.core5.http.HttpHost;
34  import org.apache.hc.core5.util.Args;
35  import org.apache.hc.core5.util.LangUtils;
36  
37  /**
38   * {@code AuthScope} represents an authentication scope consisting of
39   * an application protocol, a host name, a port number, a realm name
40   * and an authentication scheme name.
41   *
42   * @since 4.0
43   */
44  @Contract(threading = ThreadingBehavior.IMMUTABLE)
45  public class AuthScope {
46  
47      private final String protocol;
48      private final String host;
49      private final int port;
50      private final String realm;
51      private final String schemeName;
52  
53      /**
54       * Defines auth scope with the given {@code protocol}, {@code host}, {@code port},
55       * {@code realm}, and {@code schemeName}.
56       *
57       * @param protocol application protocol. May be {@code null} if applies
58       *   to any protocol.
59       * @param host authentication host. May be {@code null} if applies
60       *   to any host.
61       * @param port authentication port. May be {@code -1} if applies
62       *   to any port of the host.
63       * @param realm authentication realm. May be {@code null} if applies
64       *   to any realm on the host.
65       * @param schemeName authentication scheme name. May be {@code null} if applies
66       *   to any auth scheme supported by the host.
67       */
68      public AuthScope(
69              final String protocol,
70              final String host,
71              final int port,
72              final String realm,
73              final String schemeName) {
74          this.protocol = protocol != null ? protocol.toLowerCase(Locale.ROOT) : null;
75          this.host = host != null ? host.toLowerCase(Locale.ROOT) : null;
76          this.port = port >= 0 ? port: -1;
77          this.realm = realm;
78          this.schemeName = schemeName;
79      }
80  
81      /**
82       * Defines auth scope for a specific host of origin.
83       *
84       * @param origin host of origin
85       * @param realm authentication realm. May be {@code null} if applies
86       *   to any realm on the host.
87       * @param schemeName authentication scheme name. May be {@code null} if applies
88       *   to any auth scheme supported by the host.
89       *
90       * @since 4.2
91       */
92      public AuthScope(
93              final HttpHost origin,
94              final String realm,
95              final String schemeName) {
96          Args.notNull(origin, "Host");
97          this.protocol = origin.getSchemeName().toLowerCase(Locale.ROOT);
98          this.host = origin.getHostName().toLowerCase(Locale.ROOT);
99          this.port = origin.getPort() >= 0 ? origin.getPort() : -1;
100         this.realm = realm;
101         this.schemeName = schemeName;
102     }
103 
104     /**
105      * Defines auth scope for a specific host of origin.
106      *
107      * @param origin host of origin
108      *
109      * @since 4.2
110      */
111     public AuthScope(final HttpHost origin) {
112         this(origin, null, null);
113     }
114 
115     /**
116      * Defines auth scope with the given {@code host} and {@code port}.
117      *
118      * @param host authentication host. May be {@code null} if applies
119      *   to any host.
120      * @param port authentication port. May be {@code -1} if applies
121      *   to any port of the host.
122      */
123     public AuthScope(final String host, final int port) {
124         this(null, host, port, null, null);
125     }
126 
127     /**
128      * Creates a copy of the given credentials scope.
129      */
130     public AuthScopent5/http/auth/AuthScope.html#AuthScope">AuthScope(final AuthScope authScope) {
131         super();
132         Args.notNull(authScope, "Scope");
133         this.protocol = authScope.getProtocol();
134         this.host = authScope.getHost();
135         this.port = authScope.getPort();
136         this.realm = authScope.getRealm();
137         this.schemeName = authScope.getSchemeName();
138     }
139 
140     public String getProtocol() {
141         return protocol;
142     }
143 
144     public String getHost() {
145         return this.host;
146     }
147 
148     public int getPort() {
149         return this.port;
150     }
151 
152     public String getRealm() {
153         return this.realm;
154     }
155 
156     public String getSchemeName() {
157         return this.schemeName;
158     }
159 
160     /**
161      * Tests if the authentication scopes match.
162      *
163      * @return the match factor. Negative value signifies no match.
164      *    Non-negative signifies a match. The greater the returned value
165      *    the closer the match.
166      */
167     public int match(final AuthScope that) {
168         int factor = 0;
169         if (LangUtils.equals(toNullSafeLowerCase(this.schemeName),
170                              toNullSafeLowerCase(that.schemeName))) {
171             factor += 1;
172         } else {
173             if (this.schemeName != null && that.schemeName != null) {
174                 return -1;
175             }
176         }
177         if (LangUtils.equals(this.realm, that.realm)) {
178             factor += 2;
179         } else {
180             if (this.realm != null && that.realm != null) {
181                 return -1;
182             }
183         }
184         if (this.port == that.port) {
185             factor += 4;
186         } else {
187             if (this.port != -1 && that.port != -1) {
188                 return -1;
189             }
190         }
191         if (LangUtils.equals(this.protocol, that.protocol)) {
192             factor += 8;
193         } else {
194             if (this.protocol != null && that.protocol != null) {
195                 return -1;
196             }
197         }
198         if (LangUtils.equals(this.host, that.host)) {
199             factor += 16;
200         } else {
201             if (this.host != null && that.host != null) {
202                 return -1;
203             }
204         }
205         return factor;
206     }
207 
208     @Override
209     public boolean equals(final Object obj) {
210         if (this == obj) {
211             return true;
212         }
213         if (obj instanceof AuthScope) {
214             final AuthScope./../../../../../org/apache/hc/client5/http/auth/AuthScope.html#AuthScope">AuthScope that = (AuthScope) obj;
215             return LangUtils.equals(this.protocol, that.protocol)
216                     && LangUtils.equals(this.host, that.host)
217                     && this.port == that.port
218                     && LangUtils.equals(this.realm, that.realm)
219                     && LangUtils.equals(toNullSafeLowerCase(this.schemeName),
220                                         toNullSafeLowerCase(that.schemeName));
221         }
222         return false;
223     }
224 
225     @Override
226     public int hashCode() {
227         int hash = LangUtils.HASH_SEED;
228         hash = LangUtils.hashCode(hash, this.protocol);
229         hash = LangUtils.hashCode(hash, this.host);
230         hash = LangUtils.hashCode(hash, this.port);
231         hash = LangUtils.hashCode(hash, this.realm);
232         hash = LangUtils.hashCode(hash, toNullSafeLowerCase(this.schemeName));
233         return hash;
234     }
235 
236     private String toNullSafeLowerCase(final String str) {
237         return str != null ? str.toLowerCase(Locale.ROOT) : null;
238     }
239 
240     @Override
241     public String toString() {
242         final StringBuilder buffer = new StringBuilder();
243         if (this.schemeName != null) {
244             buffer.append(this.schemeName);
245         } else {
246             buffer.append("<any auth scheme>");
247         }
248         buffer.append(' ');
249         if (this.realm != null) {
250             buffer.append('\'');
251             buffer.append(this.realm);
252             buffer.append('\'');
253         } else {
254             buffer.append("<any realm>");
255         }
256         buffer.append(' ');
257         if (this.protocol != null) {
258             buffer.append(this.protocol);
259         } else {
260             buffer.append("<any protocol>");
261         }
262         buffer.append("://");
263         if (this.host != null) {
264             buffer.append(this.host);
265         } else {
266             buffer.append("<any host>");
267         }
268         buffer.append(':');
269         if (this.port >= 0) {
270             buffer.append(this.port);
271         } else {
272             buffer.append("<any port>");
273         }
274         return buffer.toString();
275     }
276 
277 }