PageRenderTime 18ms CodeModel.GetById 2ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/core-client/src/main/java/org/glassfish/jersey/client/authentication/HttpAuthenticationFeature.java

https://bitbucket.org/Akshay-bitbucket/devops-app
Java | 602 lines | 138 code | 47 blank | 417 comment | 7 complexity | 463ee62785f7d9e4d8651471ed9da905 MD5 | raw file
  1/*
  2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3 *
  4 * Copyright (c) 2013-2015 Oracle and/or its affiliates. All rights reserved.
  5 *
  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.
 14 *
 15 * When distributing the software, include this License Header Notice in each
 16 * file and include the License file at packager/legal/LICENSE.txt.
 17 *
 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.
 22 *
 23 * Modifications:
 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]"
 27 *
 28 * Contributor(s):
 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
 38 * holder.
 39 */
 40
 41package org.glassfish.jersey.client.authentication;
 42
 43import javax.ws.rs.core.Feature;
 44import javax.ws.rs.core.FeatureContext;
 45
 46/**
 47 * Features that provides Http Basic and Digest client authentication (based on RFC 2617).
 48 * <p>
 49 * The feature can work in following modes:
 50 * <ul>
 51 *  <li><b>BASIC:</b> Basic preemptive authentication. In preemptive mode the authentication information
 52 *  is send always with each HTTP request. This mode is more usual than the following non-preemptive mode
 53 *  (if you require BASIC authentication you will probably use this preemptive mode). This mode must
 54 *  be combined with usage of SSL/TLS as the password is send only BASE64 encoded.</li>
 55 *  <li><i>BASIC NON-PREEMPTIVE:</i> Basic non-preemptive authentication. In non-preemptive mode the
 56 *  authentication information is added only when server refuses the request with {@code 401} status code and
 57 *  then the request is repeated with authentication information. This mode has negative impact on the performance.
 58 *  The advantage is that it does not send credentials when they are not needed. This mode must
 59 *  be combined with usage of SSL/TLS as the password is send only BASE64 encoded.
 60 *  </li>
 61 *  <li><b>DIGEST:</b> Http digest authentication. Does not require usage of SSL/TLS.</li>
 62 *  <li><b>UNIVERSAL:</b> Combination of basic and digest authentication. The feature works in non-preemptive
 63 *  mode which means that it sends requests without authentication information. If {@code 401} status
 64 *  code is returned, the request is repeated and an appropriate authentication is used based on the
 65 *  authentication requested in the response (defined in {@code WWW-Authenticate} HTTP header. The feature
 66 *  remembers which authentication requests were successful for given URI and next time tries to preemptively
 67 *  authenticate against this URI with latest successful authentication method.
 68 *  </li>
 69 * </ul>
 70 * </p>
 71 * <p>
 72 * To initialize the feature use static method of this feature.
 73 * </p>
 74 * <p>
 75 * Example of building the feature in
 76 * Basic authentication mode:
 77 * <pre>
 78 * HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic("user", "superSecretPassword");
 79 * </pre>
 80 * </p>
 81 * <p>
 82 * Example of building the feature in basic non-preemptive mode:
 83 * <pre>
 84 * HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder()
 85 *     .nonPreemptive().credentials("user", "superSecretPassword").build();
 86 * </pre>
 87 * </p>
 88 * <p>
 89 * Example of building the feature in universal mode:
 90 * <pre>
 91 * HttpAuthenticationFeature feature = HttpAuthenticationFeature.universal("user", "superSecretPassword");
 92 * </pre>
 93 * </p>
 94 * <p>
 95 * Example of building the feature in universal mode with different credentials for basic and digest:
 96 * <pre>
 97 * HttpAuthenticationFeature feature = HttpAuthenticationFeature.universalBuilder()
 98 *      .credentialsForBasic("user", "123456")
 99 *      .credentials("adminuser", "hello")
100 *      .build();
101 * </pre>
102 * </p>
103 * Example of building the feature in basic preemptive mode with no default credentials. Credentials will have
104 * to be supplied with each request using request properties (see below):
105 * <pre>
106 * HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder().build();
107 * </pre>
108 * </p>
109 * <p>
110 * Once the feature is built it needs to be registered into the {@link javax.ws.rs.client.Client},
111 * {@link javax.ws.rs.client.WebTarget} or other client configurable object. Example:
112 * <pre>
113 * final Client client = ClientBuilder.newClient();
114 * client.register(feature);
115 * </pre>
116 * </p>
117 *
118 * Then you invoke requests as usual and authentication will be handled by the feature.
119 * You can change the credentials for each request using properties
120 * {@link org.glassfish.jersey.client.authentication.HttpAuthenticationFeature#HTTP_AUTHENTICATION_USERNAME} and
121 * {@link org.glassfish.jersey.client.authentication.HttpAuthenticationFeature#HTTP_AUTHENTICATION_PASSWORD}. Example:
122 * <pre>
123 * final Response response = client.target("http://localhost:8080/rest/homer/contact").request()
124 *    .property(HTTP_AUTHENTICATION_BASIC_USERNAME, "homer")
125 *    .property(HTTP_AUTHENTICATION_BASIC_PASSWORD, "p1swd745").get();
126 * </pre>
127 * <p>
128 * This class also contains property key definitions for overriding only specific basic or digest credentials:
129 * <ul>
130 *     <li>
131 *      {@link org.glassfish.jersey.client.authentication.HttpAuthenticationFeature#HTTP_AUTHENTICATION_BASIC_USERNAME} and
132 *      {@link org.glassfish.jersey.client.authentication.HttpAuthenticationFeature#HTTP_AUTHENTICATION_BASIC_PASSWORD}
133 *      </li>
134 *     <li>
135 *      {@link org.glassfish.jersey.client.authentication.HttpAuthenticationFeature#HTTP_AUTHENTICATION_DIGEST_USERNAME} and
136 *      {@link org.glassfish.jersey.client.authentication.HttpAuthenticationFeature#HTTP_AUTHENTICATION_DIGEST_PASSWORD}.
137 *      </li>
138 * </ul>
139 * </p>
140 *
141 * @author Miroslav Fuksa
142 *
143 * @since 2.5
144 */
145public class HttpAuthenticationFeature implements Feature {
146
147    /**
148     * Feature authentication mode.
149     */
150    static enum Mode {
151        /**
152         * Basic preemptive.
153         **/
154        BASIC_PREEMPTIVE,
155        /**
156         * Basic non preemptive
157         */
158        BASIC_NON_PREEMPTIVE,
159        /**
160         * Digest.
161         */
162        DIGEST,
163        /**
164         * Universal.
165         */
166        UNIVERSAL
167    }
168
169    /**
170     * Builder that creates instances of {@link HttpAuthenticationFeature}.
171     */
172    public static interface Builder {
173
174        /**
175         * Set credentials.
176         *
177         * @param username Username.
178         * @param password Password as byte array.
179         * @return This builder.
180         */
181        public Builder credentials(String username, byte[] password);
182
183        /**
184         * Set credentials.
185         *
186         * @param username Username.
187         * @param password Password as {@link String}.
188         * @return This builder.
189         */
190        public Builder credentials(String username, String password);
191
192        /**
193         * Build the feature.
194         *
195         * @return Http authentication feature configured from this builder.
196         */
197        public HttpAuthenticationFeature build();
198    }
199
200    /**
201     * Extension of {@link org.glassfish.jersey.client.authentication.HttpAuthenticationFeature.Builder}
202     * that builds the http authentication feature configured for basic authentication.
203     */
204    public static interface BasicBuilder extends Builder {
205
206        /**
207         * Configure the builder to create features in non-preemptive basic authentication mode.
208         *
209         * @return This builder.
210         */
211        public BasicBuilder nonPreemptive();
212    }
213
214    /**
215     * Extension of {@link org.glassfish.jersey.client.authentication.HttpAuthenticationFeature.Builder}
216     * that builds the http authentication feature configured in universal mode that supports
217     * basic and digest authentication.
218     */
219    public static interface UniversalBuilder extends Builder {
220
221        /**
222         * Set credentials that will be used for basic authentication only.
223         *
224         * @param username Username.
225         * @param password Password as {@link String}.
226         * @return This builder.
227         */
228        public UniversalBuilder credentialsForBasic(String username, String password);
229
230        /**
231         * Set credentials that will be used for basic authentication only.
232         *
233         * @param username Username.
234         * @param password Password as {@code byte array}.
235         * @return This builder.
236         */
237        public UniversalBuilder credentialsForBasic(String username, byte[] password);
238
239        /**
240         * Set credentials that will be used for digest authentication only.
241         *
242         * @param username Username.
243         * @param password Password as {@link String}.
244         * @return This builder.
245         */
246        public UniversalBuilder credentialsForDigest(String username, String password);
247
248        /**
249         * Set credentials that will be used for digest authentication only.
250         *
251         * @param username Username.
252         * @param password Password as {@code byte array}.
253         * @return This builder.
254         */
255        public UniversalBuilder credentialsForDigest(String username, byte[] password);
256    }
257
258    /**
259     * Implementation of all authentication builders.
260     */
261    static class BuilderImpl implements UniversalBuilder, BasicBuilder {
262
263        private String usernameBasic;
264        private byte[] passwordBasic;
265        private String usernameDigest;
266        private byte[] passwordDigest;
267        private Mode mode;
268
269        /**
270         * Create a new builder.
271         *
272         * @param mode Mode in which the final authentication feature should work.
273         */
274        public BuilderImpl(Mode mode) {
275            this.mode = mode;
276        }
277
278        @Override
279        public Builder credentials(String username, String password) {
280            return credentials(username, password == null ? null : password.getBytes(HttpAuthenticationFilter.CHARACTER_SET));
281        }
282
283        @Override
284        public Builder credentials(String username, byte[] password) {
285            credentialsForBasic(username, password);
286            credentialsForDigest(username, password);
287            return this;
288        }
289
290        @Override
291        public UniversalBuilder credentialsForBasic(String username, String password) {
292            return credentialsForBasic(username,
293                    password == null ? null : password.getBytes(HttpAuthenticationFilter.CHARACTER_SET));
294        }
295
296        @Override
297        public UniversalBuilder credentialsForBasic(String username, byte[] password) {
298            this.usernameBasic = username;
299            this.passwordBasic = password;
300            return this;
301        }
302
303        @Override
304        public UniversalBuilder credentialsForDigest(String username, String password) {
305            return credentialsForDigest(username,
306                    password == null ? null : password.getBytes(HttpAuthenticationFilter.CHARACTER_SET));
307        }
308
309        @Override
310        public UniversalBuilder credentialsForDigest(String username, byte[] password) {
311            this.usernameDigest = username;
312            this.passwordDigest = password;
313            return this;
314        }
315
316        @Override
317        public HttpAuthenticationFeature build() {
318            return new HttpAuthenticationFeature(mode,
319                    usernameBasic == null ? null
320                            : new HttpAuthenticationFilter.Credentials(usernameBasic, passwordBasic),
321                    usernameDigest == null ? null
322                            : new HttpAuthenticationFilter.Credentials(usernameDigest, passwordDigest));
323        }
324
325        @Override
326        public BasicBuilder nonPreemptive() {
327            if (mode == Mode.BASIC_PREEMPTIVE) {
328                this.mode = Mode.BASIC_NON_PREEMPTIVE;
329            }
330            return this;
331        }
332    }
333
334    /**
335     * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
336     * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
337     * the username for http authentication feature for the request.
338     * <p>
339     * Example:
340     * <pre>
341     * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
342     *      .property(HTTP_AUTHENTICATION_USERNAME, "joe")
343     *      .property(HTTP_AUTHENTICATION_PASSWORD, "p1swd745").get();
344     * </pre>
345     * </p>
346     * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_PASSWORD} property
347     * (as shown in the example). This property pair overrides all password settings of the authentication
348     * feature for the current request.
349     * <p>
350     * The default value must be instance of {@link String}.
351     * </p>
352     * <p>
353     * The name of the configuration property is <tt>{@value}</tt>.
354     * </p>
355     */
356    public static final String HTTP_AUTHENTICATION_USERNAME = "jersey.config.client.http.auth.username";
357    /**
358     * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
359     * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
360     * the password for http authentication feature for the request.
361     * <p>
362     * Example:
363     * <pre>
364     * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
365     *      .property(HTTP_AUTHENTICATION_USERNAME, "joe")
366     *      .property(HTTP_AUTHENTICATION_PASSWORD, "p1swd745").get();
367     * </pre>
368     * </p>
369     * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_USERNAME} property
370     * (as shown in the example). This property pair overrides all password settings of the authentication
371     * feature for the current request.
372     * <p>
373     * The value must be instance of {@link String} or {@code byte} array ({@code byte[]}).
374     * </p>
375     * <p>
376     * The name of the configuration property is <tt>{@value}</tt>.
377     * </p>
378     */
379    public static final String HTTP_AUTHENTICATION_PASSWORD = "jersey.config.client.http.auth.password";
380
381    /**
382     * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
383     * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
384     * the username for http basic authentication feature for the request.
385     * <p>
386     * Example:
387     * <pre>
388     * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
389     *      .property(HTTP_AUTHENTICATION_BASIC_USERNAME, "joe")
390     *      .property(HTTP_AUTHENTICATION_BASIC_PASSWORD, "p1swd745").get();
391     * </pre>
392     * </p>
393     * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_PASSWORD} property
394     * (as shown in the example). The property pair influence only credentials used during basic authentication.
395     *
396     * <p>
397     * The value must be instance of {@link String}.
398     * </p>
399     * <p>
400     * The name of the configuration property is <tt>{@value}</tt>.
401     * </p>
402
403     */
404    public static final String HTTP_AUTHENTICATION_BASIC_USERNAME = "jersey.config.client.http.auth.basic.username";
405
406    /**
407     * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
408     * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
409     * the password for http basic authentication feature for the request.
410     * <p>
411     * Example:
412     * <pre>
413     * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
414     *      .property(HTTP_AUTHENTICATION_BASIC_USERNAME, "joe")
415     *      .property(HTTP_AUTHENTICATION_BASIC_PASSWORD, "p1swd745").get();
416     * </pre>
417     * </p>
418     * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_USERNAME} property
419     * (as shown in the example). The property pair influence only credentials used during basic authentication.
420     * <p>
421     * The value must be instance of {@link String} or {@code byte} array ({@code byte[]}).
422     * </p>
423     * <p>
424     * The name of the configuration property is <tt>{@value}</tt>.
425     * </p>
426     */
427    public static final String HTTP_AUTHENTICATION_BASIC_PASSWORD = "jersey.config.client.http.auth.basic.password";
428
429    /**
430     * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
431     * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
432     * the username for http digest authentication feature for the request.
433     * <p>
434     * Example:
435     * <pre>
436     * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
437     *      .property(HTTP_AUTHENTICATION_DIGEST_USERNAME, "joe")
438     *      .property(HTTP_AUTHENTICATION_DIGEST_PASSWORD, "p1swd745").get();
439     * </pre>
440     * </p>
441     * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_PASSWORD} property
442     * (as shown in the example). The property pair influence only credentials used during digest authentication.
443     * <p>
444     * The value must be instance of {@link String}.
445     * </p>
446     * <p>
447     * The name of the configuration property is <tt>{@value}</tt>.
448     * </p>
449     */
450    public static final String HTTP_AUTHENTICATION_DIGEST_USERNAME = "jersey.config.client.http.auth.digest.username";
451
452    /**
453     * Key of the property that can be set into the {@link javax.ws.rs.client.ClientRequestContext client request}
454     * using {@link javax.ws.rs.client.ClientRequestContext#setProperty(String, Object)} in order to override
455     * the password for http digest authentication feature for the request.
456     * <p>
457     * Example:
458     * <pre>
459     * Response response = client.target("http://localhost:8080/rest/joe/orders").request()
460     *      .property(HTTP_AUTHENTICATION_DIGEST_USERNAME, "joe")
461     *      .property(HTTP_AUTHENTICATION_DIGEST_PASSWORD, "p1swd745").get();
462     * </pre>
463     * </p>
464     * The property must be always combined with configuration of {@link #HTTP_AUTHENTICATION_PASSWORD} property
465     * (as shown in the example). The property pair influence only credentials used during digest authentication.
466     * <p>
467     * The value must be instance of {@link String} or {@code byte} array ({@code byte[]}).
468     * </p>
469     * <p>
470     * The name of the configuration property is <tt>{@value}</tt>.
471     * </p>
472     */
473    public static final String HTTP_AUTHENTICATION_DIGEST_PASSWORD = "jersey.config.client.http.auth.digest.password";
474
475    /**
476     * Create the builder of the http authentication feature working in basic authentication mode. The builder
477     * can build preemptive and non-preemptive basic authentication features.
478     *
479     * @return Basic http authentication builder.
480     */
481    public static BasicBuilder basicBuilder() {
482        return new BuilderImpl(Mode.BASIC_PREEMPTIVE);
483    }
484
485    /**
486     * Create the http authentication feature in basic preemptive authentication mode initialized with credentials.
487     *
488     * @param username Username.
489     * @param password Password as {@code byte array}.
490     * @return Http authentication feature configured in basic mode.
491     */
492    public static HttpAuthenticationFeature basic(String username, byte[] password) {
493        return build(Mode.BASIC_PREEMPTIVE, username, password);
494    }
495
496    /**
497     * Create the http authentication feature in basic preemptive authentication mode initialized with credentials.
498     *
499     * @param username Username.
500     * @param password Password as {@link String}.
501     * @return Http authentication feature configured in basic mode.
502     */
503    public static HttpAuthenticationFeature basic(String username, String password) {
504        return build(Mode.BASIC_PREEMPTIVE, username, password);
505    }
506
507    /**
508     * Create the http authentication feature in digest authentication mode initialized without default
509     * credentials. Credentials will have to be supplied using request properties for each request.
510     *
511     * @return Http authentication feature configured in digest mode.
512     */
513    public static HttpAuthenticationFeature digest() {
514        return build(Mode.DIGEST);
515    }
516
517    /**
518     * Create the http authentication feature in digest authentication mode initialized with credentials.
519     *
520     * @param username Username.
521     * @param password Password as {@code byte array}.
522     * @return Http authentication feature configured in digest mode.
523     */
524    public static HttpAuthenticationFeature digest(String username, byte[] password) {
525        return build(Mode.DIGEST, username, password);
526    }
527
528    /**
529     * Create the http authentication feature in digest authentication mode initialized with credentials.
530     *
531     * @param username Username.
532     * @param password Password as {@link String}.
533     * @return Http authentication feature configured in digest mode.
534     */
535    public static HttpAuthenticationFeature digest(String username, String password) {
536        return build(Mode.DIGEST, username, password);
537    }
538
539    /**
540     * Create the builder that builds http authentication feature in combined mode supporting both,
541     * basic and digest authentication.
542     *
543     * @return Universal builder.
544     */
545    public static UniversalBuilder universalBuilder() {
546        return new BuilderImpl(Mode.UNIVERSAL);
547    }
548
549    /**
550     * Create the http authentication feature in combined mode supporting both,
551     * basic and digest authentication.
552     *
553     * @param username Username.
554     * @param password Password as {@code byte array}.
555     * @return Http authentication feature configured in digest mode.
556     */
557    public static HttpAuthenticationFeature universal(String username, byte[] password) {
558        return build(Mode.UNIVERSAL, username, password);
559    }
560
561    /**
562     * Create the http authentication feature in combined mode supporting both,
563     * basic and digest authentication.
564     *
565     * @param username Username.
566     * @param password Password as {@link String}.
567     * @return Http authentication feature configured in digest mode.
568     */
569    public static HttpAuthenticationFeature universal(String username, String password) {
570        return build(Mode.UNIVERSAL, username, password);
571    }
572
573    private static HttpAuthenticationFeature build(Mode mode) {
574        return new BuilderImpl(mode).build();
575    }
576
577    private static HttpAuthenticationFeature build(Mode mode, String username, byte[] password) {
578        return new BuilderImpl(mode).credentials(username, password).build();
579    }
580
581    private static HttpAuthenticationFeature build(Mode mode, String username, String password) {
582        return new BuilderImpl(mode).credentials(username, password).build();
583    }
584
585    private final Mode mode;
586    private final HttpAuthenticationFilter.Credentials basicCredentials;
587    private final HttpAuthenticationFilter.Credentials digestCredentials;
588
589    private HttpAuthenticationFeature(Mode mode, HttpAuthenticationFilter.Credentials basicCredentials,
590                                      HttpAuthenticationFilter.Credentials digestCredentials) {
591        this.mode = mode;
592        this.basicCredentials = basicCredentials;
593
594        this.digestCredentials = digestCredentials;
595    }
596
597    @Override
598    public boolean configure(FeatureContext context) {
599        context.register(new HttpAuthenticationFilter(mode, basicCredentials, digestCredentials, context.getConfiguration()));
600        return true;
601    }
602}