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