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.security.Principal;
30
31 import org.apache.hc.core5.http.HttpHost;
32 import org.apache.hc.core5.http.HttpRequest;
33 import org.apache.hc.core5.http.protocol.HttpContext;
34
35 /**
36 * This interface represents an abstract challenge-response oriented authentication scheme.
37 * <p>
38 * Authentication schemes can be either request or connection based. The former are
39 * expected to provide an authorization response with each request message while the latter
40 * is executed only once and applies to the underlying connection for its entire life span.
41 * Care must be taken when re-using connections authorized through a connection based
42 * authentication scheme and they may carry a particular security context and be authorized
43 * for a particular user identity. It is important that such schemes always provide
44 * the user identity they represent through the {@link #getPrincipal()} method.
45 * </p>
46 * <p>
47 * Authentication scheme are expected to transition through a series of standard phases or
48 * states.
49 * </p>
50 * <p>
51 * Authentication scheme starts off its life cycle with no context and no specific state.
52 * </p>
53 * <p>
54 * The {@link #processChallenge(AuthChallenge, HttpContext)} method is called to
55 * process an authentication challenge received either from the target server or a proxy.
56 * The authentication scheme transitions to CHALLENGED state and is expected to validate
57 * the token passed to it as a parameter and initialize its internal state based on
58 * challenge details. Standard authentication schemes are expected to provide a realm
59 * attribute in the challenge. {@link #getRealm()} can be called to obtain an identifier
60 * of the realm that requires authorization.
61 * </p>
62 * <p>
63 * Once the challenge has been fully processed the {@link #isResponseReady(HttpHost,
64 * CredentialsProvider, HttpContext)} method to determine whether the scheme is capable of
65 * generating a authorization response based on its current state and it holds user credentials
66 * required to do so. If this method returns {@code false} the authentication is considered
67 * to be in FAILED state and no authorization response. Otherwise the scheme is considered
68 * to be in RESPONSE_READY state.
69 * </p>
70 * <p>
71 * Once the scheme is ready to respond to the challenge the {@link #generateAuthResponse(
72 * HttpHost, HttpRequest, HttpContext)} method to generate a response token, which will
73 * be sent to the opposite endpoint in the subsequent request message.
74 * </p>
75 * <p>
76 * Certain non-standard schemes may involve multiple challenge / response exchanges to
77 * fully establish a shared context and complete the authentication process. Authentication
78 * schemes are required to return {@code true} {@link #isChallengeComplete()} once the
79 * handshake is considered complete.
80 * </p>
81 * <p>
82 * The authentication scheme is considered successfully completed and in SUCCESS state
83 * if the opposite endpoint accepts the request message containing the authorization
84 * response and responds with a message indicating no authentication failure .
85 * If the opposite endpoint sends status code 401 or 407 in response to a request message
86 * containing the terminal authorization response, the scheme is considered unsuccessful
87 * and in FAILED state.
88 * </p>
89 *
90 * @since 4.0
91 */
92 public interface AuthScheme {
93
94 /**
95 * Returns textual designation of the given authentication scheme.
96 *
97 * @return the name of the given authentication scheme
98 */
99 String getName();
100
101 /**
102 * Determines if the authentication scheme is expected to provide an authorization response
103 * on a per connection basis instead of the standard per request basis
104 *
105 * @return {@code true} if the scheme is connection based, {@code false}
106 * if the scheme is request based.
107 */
108 boolean isConnectionBased();
109
110 /**
111 * Processes the given auth challenge. Some authentication schemes may involve multiple
112 * challenge-response exchanges. Such schemes must be able to maintain internal state
113 * when dealing with sequential challenges
114 * <p>
115 * Please note auth schemes that perform mutual authentication must implement
116 * {@link #processChallenge(HttpHost, boolean, AuthChallenge, HttpContext)} and
117 * {@link #isChallengeExpected()} instead.
118 *
119 * @param authChallenge the auth challenge
120 * @param context HTTP context
121 * @throws MalformedChallengeException in case the auth challenge is incomplete,
122 * malformed or otherwise invalid.
123 *
124 * @see #processChallenge(HttpHost, boolean, AuthChallenge, HttpContext)
125 *
126 * @since 5.0
127 */
128 void processChallenge(
129 AuthChallenge authChallenge,
130 HttpContext context) throws MalformedChallengeException;
131
132 /**
133 * Indicates that the even authorized (i.e. not 401 or 407) responses must be processed
134 * by this scheme.
135 *
136 * @return true if responses with non 401/407 response codes must be processed by the scheme.
137 *
138 * @since 5.5
139 */
140 default boolean isChallengeExpected() {
141 return false;
142 }
143
144 /**
145 * Processes the given auth challenge. Some authentication schemes may involve multiple
146 * challenge-response exchanges. Such schemes must be able to maintain internal state
147 * when dealing with sequential challenges.
148 * <p>
149 * When {@link #isChallengeExpected()} returns true, but no challenge was sent, this method
150 * must be called with a null {@link AuthChallenge} so that the scheme can handle this situation.
151 *
152 * @param host HTTP host
153 * @param challenged true if the response was unauthorised (401/407)
154 * @param authChallenge the auth challenge or null if no challenge was received
155 * @param context HTTP context
156 *
157 * @throws MalformedChallengeException in case the auth challenge is incomplete,
158 * @throws AuthenticationException in case the authentication process is unsuccessful.
159 *
160 * @since 5.5
161 */
162 default void processChallenge(
163 HttpHost host,
164 boolean challenged,
165 AuthChallenge authChallenge,
166 HttpContext context) throws MalformedChallengeException, AuthenticationException {
167 processChallenge(authChallenge, context);
168 }
169
170 /**
171 * Authentication process may involve a series of challenge-response exchanges.
172 * This method tests if the authorization process has been fully completed (either
173 * successfully or unsuccessfully), that is, all the required authorization
174 * challenges have been processed in their entirety.
175 * <p>
176 * Please note if the scheme returns {@code true} from this method in response
177 * to a challenge, it effectively implies a failure to respond to this challenge
178 * and termination of the authentication process.
179 *
180 * @return {@code true} if the authentication process has been completed,
181 * {@code false} otherwise.
182 *
183 * @since 5.0
184 */
185 boolean isChallengeComplete();
186
187 /**
188 * Returns authentication realm. If the concept of an authentication
189 * realm is not applicable to the given authentication scheme, returns
190 * {@code null}.
191 *
192 * @return the authentication realm
193 */
194 String getRealm();
195
196 /**
197 * Determines whether or not an authorization response can be generated based on
198 * the actual authentication state. Generally the outcome of this method will depend
199 * upon availability of user credentials necessary to produce an authorization
200 * response.
201 *
202 * @param credentialsProvider The credentials to be used for authentication
203 * @param context HTTP context
204 * @throws AuthenticationException if authorization string cannot
205 * be generated due to an authentication failure
206 *
207 * @return {@code true} if an authorization response can be generated and
208 * the authentication handshake can proceed, {@code false} otherwise.
209 *
210 * @since 5.0
211 */
212 boolean isResponseReady(
213 HttpHost host,
214 CredentialsProvider credentialsProvider,
215 HttpContext context) throws AuthenticationException;
216
217 /**
218 * Returns {@link Principal} whose credentials are used to generate
219 * an authentication response. Connection based schemes are required
220 * to return a user {@link Principal} if authorization applies to
221 * for the entire life span of connection.
222 * @return user principal
223 *
224 * @see #isConnectionBased()
225 *
226 * @since 5.0
227 */
228 Principal getPrincipal();
229
230 /**
231 * Generates an authorization response based on the current state. Some authentication
232 * schemes may need to load user credentials required to generate an authorization
233 * response from a {@link CredentialsProvider} prior to this method call.
234 *
235 * @param request The request being authenticated
236 * @param context HTTP context
237 * @throws AuthenticationException if authorization string cannot
238 * be generated due to an authentication failure
239 *
240 * @return authorization header
241 *
242 * @see #isResponseReady(HttpHost, CredentialsProvider, HttpContext)
243 *
244 * @since 5.0
245 */
246 String generateAuthResponse(
247 HttpHost host,
248 HttpRequest request,
249 HttpContext context) throws AuthenticationException;
250
251 }