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