2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright (c) 2013-2015 Oracle and/or its affiliates. All rights reserved.
6 * The contents of this file are subject to the terms of either the GNU
7 * General Public License Version 2 only ("GPL") or the Common Development
8 * and Distribution License("CDDL") (collectively, the "License"). You
9 * may not use this file except in compliance with the License. You can
10 * obtain a copy of the License at
11 * http://glassfish.java.net/public/CDDL+GPL_1_1.html
12 * or packager/legal/LICENSE.txt. See the License for the specific
13 * language governing permissions and limitations under the License.
15 * When distributing the software, include this License Header Notice in each
16 * file and include the License file at packager/legal/LICENSE.txt.
18 * GPL Classpath Exception:
19 * Oracle designates this particular file as subject to the "Classpath"
20 * exception as provided by Oracle in the GPL Version 2 section of the License
21 * file that accompanied this code.
24 * If applicable, add the following below the License Header, with the fields
25 * enclosed by brackets [] replaced by your own identifying information:
26 * "Portions Copyright [year] [name of copyright owner]"
29 * If you wish your version of this file to be governed by only the CDDL or
30 * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 * elects to include this software in this distribution under the [CDDL or GPL
32 * Version 2] license." If you don't indicate a single choice of license, a
33 * recipient has the option to distribute your version of this file under
34 * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 * its licensees as provided above. However, if you add GPL Version 2 code
36 * and therefore, elected the GPL Version 2 license, then the option applies
37 * only if the new code is made subject to such option by the copyright
40 package org.openhab.binding.lametrictime.internal.api.authentication;
42 import javax.ws.rs.core.Feature;
43 import javax.ws.rs.core.FeatureContext;
46 * Features that provides Http Basic and Digest client authentication (based on RFC 2617).
48 * The feature can work in following modes:
50 * <li><b>BASIC:</b> Basic preemptive authentication. In preemptive mode the authentication information
51 * is send always with each HTTP request. This mode is more usual than the following non-preemptive mode
52 * (if you require BASIC authentication you will probably use this preemptive mode). This mode must
53 * be combined with usage of SSL/TLS as the password is send only BASE64 encoded.</li>
54 * <li><i>BASIC NON-PREEMPTIVE:</i> Basic non-preemptive authentication. In non-preemptive mode the
55 * authentication information is added only when server refuses the request with {@code 401} status code and
56 * then the request is repeated with authentication information. This mode has negative impact on the performance.
57 * The advantage is that it does not send credentials when they are not needed. This mode must
58 * be combined with usage of SSL/TLS as the password is send only BASE64 encoded.
60 * <li><b>DIGEST:</b> Http digest authentication. Does not require usage of SSL/TLS.</li>
61 * <li><b>UNIVERSAL:</b> Combination of basic and digest authentication. The feature works in non-preemptive
62 * mode which means that it sends requests without authentication information. If {@code 401} status
63 * code is returned, the request is repeated and an appropriate authentication is used based on the
64 * authentication requested in the response (defined in {@code WWW-Authenticate} HTTP header. The feature
65 * remembers which authentication requests were successful for given URI and next time tries to preemptively
66 * authenticate against this URI with latest successful authentication method.
71 * To initialize the feature use static method of this feature.
74 * Example of building the feature in
75 * Basic authentication mode:
78 * HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic("user", "superSecretPassword");
82 * Example of building the feature in basic non-preemptive mode:
85 * HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder().nonPreemptive()
86 * .credentials("user", "superSecretPassword").build();
90 * Example of building the feature in universal mode:
93 * HttpAuthenticationFeature feature = HttpAuthenticationFeature.universal("user", "superSecretPassword");
97 * Example of building the feature in universal mode with different credentials for basic and digest:
100 * HttpAuthenticationFeature feature = HttpAuthenticationFeature.universalBuilder()
101 * .credentialsForBasic("user", "123456").credentials("adminuser", "hello").build();
104 * Example of building the feature in basic preemptive mode with no default credentials. Credentials will have
105 * to be supplied with each request using request properties (see below):
108 * HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder().build();
112 * Once the feature is built it needs to be registered into the {@link javax.ws.rs.client.Client},
113 * {@link javax.ws.rs.client.WebTarget} or other client configurable object. Example:
116 * final Client client = ClientBuilder.newClient();
117 * client.register(feature);
121 * Then you invoke requests as usual and authentication will be handled by the feature.
122 * You can change the credentials for each request using properties
125 * final Response response = client.target("http://localhost:8080/rest/homer/contact").request()
126 * .property(HTTP_AUTHENTICATION_BASIC_USERNAME, "homer")
127 * .property(HTTP_AUTHENTICATION_BASIC_PASSWORD, "p1swd745").get();
130 * This class also contains property key definitions for overriding only specific basic or digest credentials:
133 * @author Miroslav Fuksa
137 public class HttpAuthenticationFeature implements Feature {
140 * Feature authentication mode.
148 * Basic non preemptive
150 BASIC_NON_PREEMPTIVE,
162 * Builder that creates instances of {@link HttpAuthenticationFeature}.
164 public static interface Builder {
169 * @param username Username.
170 * @param password Password as byte array.
171 * @return This builder.
173 public Builder credentials(String username, byte[] password);
178 * @param username Username.
179 * @param password Password as {@link String}.
180 * @return This builder.
182 public Builder credentials(String username, String password);
187 * @return Http authentication feature configured from this builder.
189 public HttpAuthenticationFeature build();
193 * Extension of {@link org.glassfish.jersey.client.authentication.HttpAuthenticationFeature.Builder}
194 * that builds the http authentication feature configured for basic authentication.
196 public static interface BasicBuilder extends Builder {
199 * Configure the builder to create features in non-preemptive basic authentication mode.
201 * @return This builder.
203 public BasicBuilder nonPreemptive();
207 * that builds the http authentication feature configured in universal mode that supports
208 * basic and digest authentication.
210 public static interface UniversalBuilder extends Builder {
213 * Set credentials that will be used for basic authentication only.
215 * @param username Username.
216 * @param password Password as {@link String}.
217 * @return This builder.
219 public UniversalBuilder credentialsForBasic(String username, String password);
222 * Set credentials that will be used for basic authentication only.
224 * @param username Username.
225 * @param password Password as {@code byte array}.
226 * @return This builder.
228 public UniversalBuilder credentialsForBasic(String username, byte[] password);
231 * Set credentials that will be used for digest authentication only.
233 * @param username Username.
234 * @param password Password as {@link String}.
235 * @return This builder.
237 public UniversalBuilder credentialsForDigest(String username, String password);
240 * Set credentials that will be used for digest authentication only.
242 * @param username Username.
243 * @param password Password as {@code byte array}.
244 * @return This builder.
246 public UniversalBuilder credentialsForDigest(String username, byte[] password);
250 * Implementation of all authentication builders.
252 static class BuilderImpl implements UniversalBuilder, BasicBuilder {
254 private String usernameBasic;
255 private byte[] passwordBasic;
256 private String usernameDigest;
257 private byte[] passwordDigest;
261 * Create a new builder.
263 * @param mode Mode in which the final authentication feature should work.
265 public BuilderImpl(Mode mode) {
270 public Builder credentials(String username, String password) {
271 return credentials(username,
272 password == null ? null : password.getBytes(HttpAuthenticationFilter.CHARACTER_SET));
276 public Builder credentials(String username, byte[] password) {
277 credentialsForBasic(username, password);
278 credentialsForDigest(username, password);
283 public UniversalBuilder credentialsForBasic(String username, String password) {
284 return credentialsForBasic(username,
285 password == null ? null : password.getBytes(HttpAuthenticationFilter.CHARACTER_SET));
289 public UniversalBuilder credentialsForBasic(String username, byte[] password) {
290 this.usernameBasic = username;
291 this.passwordBasic = password;
296 public UniversalBuilder credentialsForDigest(String username, String password) {
297 return credentialsForDigest(username,
298 password == null ? null : password.getBytes(HttpAuthenticationFilter.CHARACTER_SET));
302 public UniversalBuilder credentialsForDigest(String username, byte[] password) {
303 this.usernameDigest = username;
304 this.passwordDigest = password;
309 public HttpAuthenticationFeature build() {
310 return new HttpAuthenticationFeature(mode,
311 usernameBasic == null ? null
312 : new HttpAuthenticationFilter.Credentials(usernameBasic, passwordBasic),
313 usernameDigest == null ? null
314 : new HttpAuthenticationFilter.Credentials(usernameDigest, passwordDigest));
318 public BasicBuilder nonPreemptive() {
319 if (mode == Mode.BASIC_PREEMPTIVE) {
320 this.mode = Mode.BASIC_NON_PREEMPTIVE;
327 * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
328 * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
329 * the username for http authentication feature for the request.
334 * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
335 * .property(HTTP_AUTHENTICATION_USERNAME, "joe").property(HTTP_AUTHENTICATION_PASSWORD, "p1swd745").get();
338 * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_PASSWORD} property
339 * (as shown in the example). This property pair overrides all password settings of the authentication
340 * feature for the current request.
342 * The default value must be instance of {@link String}.
345 * The name of the configuration property is <tt>{@value}</tt>.
348 public static final String HTTP_AUTHENTICATION_USERNAME = "jersey.config.client.http.auth.username";
350 * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
351 * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
352 * the password for http authentication feature for the request.
357 * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
358 * .property(HTTP_AUTHENTICATION_USERNAME, "joe").property(HTTP_AUTHENTICATION_PASSWORD, "p1swd745").get();
361 * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_USERNAME} property
362 * (as shown in the example). This property pair overrides all password settings of the authentication
363 * feature for the current request.
365 * The value must be instance of {@link String} or {@code byte} array ({@code byte[]}).
368 * The name of the configuration property is <tt>{@value}</tt>.
371 public static final String HTTP_AUTHENTICATION_PASSWORD = "jersey.config.client.http.auth.password";
374 * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
375 * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
376 * the username for http basic authentication feature for the request.
381 * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
382 * .property(HTTP_AUTHENTICATION_BASIC_USERNAME, "joe").property(HTTP_AUTHENTICATION_BASIC_PASSWORD, "p1swd745")
386 * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_PASSWORD} property
387 * (as shown in the example). The property pair influence only credentials used during basic authentication.
390 * The value must be instance of {@link String}.
393 * The name of the configuration property is <tt>{@value}</tt>.
397 public static final String HTTP_AUTHENTICATION_BASIC_USERNAME = "jersey.config.client.http.auth.basic.username";
400 * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
401 * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
402 * the password for http basic authentication feature for the request.
407 * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
408 * .property(HTTP_AUTHENTICATION_BASIC_USERNAME, "joe").property(HTTP_AUTHENTICATION_BASIC_PASSWORD, "p1swd745")
412 * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_USERNAME} property
413 * (as shown in the example). The property pair influence only credentials used during basic authentication.
415 * The value must be instance of {@link String} or {@code byte} array ({@code byte[]}).
418 * The name of the configuration property is <tt>{@value}</tt>.
421 public static final String HTTP_AUTHENTICATION_BASIC_PASSWORD = "jersey.config.client.http.auth.basic.password";
424 * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
425 * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
426 * the username for http digest authentication feature for the request.
431 * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
432 * .property(HTTP_AUTHENTICATION_DIGEST_USERNAME, "joe")
433 * .property(HTTP_AUTHENTICATION_DIGEST_PASSWORD, "p1swd745").get();
436 * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_PASSWORD} property
437 * (as shown in the example). The property pair influence only credentials used during digest authentication.
439 * The value must be instance of {@link String}.
442 * The name of the configuration property is <tt>{@value}</tt>.
445 public static final String HTTP_AUTHENTICATION_DIGEST_USERNAME = "jersey.config.client.http.auth.digest.username";
448 * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
449 * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
450 * the password for http digest authentication feature for the request.
455 * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
456 * .property(HTTP_AUTHENTICATION_DIGEST_USERNAME, "joe")
457 * .property(HTTP_AUTHENTICATION_DIGEST_PASSWORD, "p1swd745").get();
460 * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_PASSWORD} property
461 * (as shown in the example). The property pair influence only credentials used during digest authentication.
463 * The value must be instance of {@link String} or {@code byte} array ({@code byte[]}).
466 * The name of the configuration property is <tt>{@value}</tt>.
469 public static final String HTTP_AUTHENTICATION_DIGEST_PASSWORD = "jersey.config.client.http.auth.digest.password";
472 * Create the builder of the http authentication feature working in basic authentication mode. The builder
473 * can build preemptive and non-preemptive basic authentication features.
475 * @return Basic http authentication builder.
477 public static BasicBuilder basicBuilder() {
478 return new BuilderImpl(Mode.BASIC_PREEMPTIVE);
482 * Create the http authentication feature in basic preemptive authentication mode initialized with credentials.
484 * @param username Username.
485 * @param password Password as {@code byte array}.
486 * @return Http authentication feature configured in basic mode.
488 public static HttpAuthenticationFeature basic(String username, byte[] password) {
489 return build(Mode.BASIC_PREEMPTIVE, username, password);
493 * Create the http authentication feature in basic preemptive authentication mode initialized with credentials.
495 * @param username Username.
496 * @param password Password as {@link String}.
497 * @return Http authentication feature configured in basic mode.
499 public static HttpAuthenticationFeature basic(String username, String password) {
500 return build(Mode.BASIC_PREEMPTIVE, username, password);
504 * Create the http authentication feature in digest authentication mode initialized without default
505 * credentials. Credentials will have to be supplied using request properties for each request.
507 * @return Http authentication feature configured in digest mode.
509 public static HttpAuthenticationFeature digest() {
510 return build(Mode.DIGEST);
514 * Create the http authentication feature in digest authentication mode initialized with credentials.
516 * @param username Username.
517 * @param password Password as {@code byte array}.
518 * @return Http authentication feature configured in digest mode.
520 public static HttpAuthenticationFeature digest(String username, byte[] password) {
521 return build(Mode.DIGEST, username, password);
525 * Create the http authentication feature in digest authentication mode initialized with credentials.
527 * @param username Username.
528 * @param password Password as {@link String}.
529 * @return Http authentication feature configured in digest mode.
531 public static HttpAuthenticationFeature digest(String username, String password) {
532 return build(Mode.DIGEST, username, password);
536 * Create the builder that builds http authentication feature in combined mode supporting both,
537 * basic and digest authentication.
539 * @return Universal builder.
541 public static UniversalBuilder universalBuilder() {
542 return new BuilderImpl(Mode.UNIVERSAL);
546 * Create the http authentication feature in combined mode supporting both,
547 * basic and digest authentication.
549 * @param username Username.
550 * @param password Password as {@code byte array}.
551 * @return Http authentication feature configured in digest mode.
553 public static HttpAuthenticationFeature universal(String username, byte[] password) {
554 return build(Mode.UNIVERSAL, username, password);
558 * Create the http authentication feature in combined mode supporting both,
559 * basic and digest authentication.
561 * @param username Username.
562 * @param password Password as {@link String}.
563 * @return Http authentication feature configured in digest mode.
565 public static HttpAuthenticationFeature universal(String username, String password) {
566 return build(Mode.UNIVERSAL, username, password);
569 private static HttpAuthenticationFeature build(Mode mode) {
570 return new BuilderImpl(mode).build();
573 private static HttpAuthenticationFeature build(Mode mode, String username, byte[] password) {
574 return new BuilderImpl(mode).credentials(username, password).build();
577 private static HttpAuthenticationFeature build(Mode mode, String username, String password) {
578 return new BuilderImpl(mode).credentials(username, password).build();
581 private final Mode mode;
582 private final HttpAuthenticationFilter.Credentials basicCredentials;
584 private HttpAuthenticationFeature(Mode mode, HttpAuthenticationFilter.Credentials basicCredentials,
585 HttpAuthenticationFilter.Credentials digestCredentials) {
587 this.basicCredentials = basicCredentials;
591 public boolean configure(FeatureContext context) {
592 context.register(new HttpAuthenticationFilter(mode, basicCredentials, context.getConfiguration()));