View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2025 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.jcabi.http.wire;
6   
7   import com.jcabi.http.mock.MkAnswer;
8   import com.jcabi.http.mock.MkContainer;
9   import com.jcabi.http.mock.MkGrizzlyContainer;
10  import com.jcabi.http.mock.MkQueryMatchers;
11  import com.jcabi.http.request.JdkRequest;
12  import com.jcabi.http.response.RestResponse;
13  import jakarta.ws.rs.core.HttpHeaders;
14  import jakarta.ws.rs.core.UriBuilder;
15  import jakarta.xml.bind.DatatypeConverter;
16  import java.net.HttpURLConnection;
17  import java.net.URI;
18  import java.net.URLEncoder;
19  import java.nio.charset.StandardCharsets;
20  import javax.net.ssl.HttpsURLConnection;
21  import org.hamcrest.MatcherAssert;
22  import org.hamcrest.Matchers;
23  import org.junit.jupiter.api.Assertions;
24  import org.junit.jupiter.api.Test;
25  import org.junit.jupiter.params.ParameterizedTest;
26  import org.junit.jupiter.params.provider.CsvSource;
27  
28  /**
29   * Test case for {@link BasicAuthWire}.
30   *
31   * @since 1.17.1
32   */
33  final class BasicAuthWireTest {
34  
35      /**
36       * The format of the credentials as {@code username:password}.
37       */
38      private static final String CRED_FORMAT = "%s:%s";
39  
40      /**
41       * Tests if the wire generates the authorization header correctly.
42       *
43       * @param username The username to user for authentication
44       * @param password The password to user for authentication
45       * @throws Exception If something goes wrong
46       */
47      @ParameterizedTest
48      @CsvSource({
49          "Alice,  secret",
50          "Bob,    s&e+c`ret",
51          "user,  \u20ac\u20ac"
52      })
53      void testHeader(
54          final String username, final String password
55      ) throws Exception {
56          final MkContainer container = new MkGrizzlyContainer().next(
57              new MkAnswer.Simple("")
58          ).start();
59          final URI uri = UriBuilder.fromUri(container.home()).userInfo(
60              String.format(
61                  BasicAuthWireTest.CRED_FORMAT,
62                  URLEncoder.encode(username, StandardCharsets.UTF_8.displayName()),
63                  URLEncoder.encode(password, StandardCharsets.UTF_8.displayName())
64              )
65          ).build();
66          final String expected = BasicAuthWireTest.expectHeader(
67              username,
68              password
69          );
70          new JdkRequest(uri)
71              .through(BasicAuthWire.class)
72              .fetch()
73              .as(RestResponse.class)
74              .assertStatus(HttpURLConnection.HTTP_OK);
75          container.stop();
76          MatcherAssert.assertThat(
77              "should be correct header",
78              container.take().headers().get(HttpHeaders.AUTHORIZATION).get(0),
79              Matchers.equalTo(expected)
80          );
81      }
82  
83      /**
84       * Tests if the wire strips user info from URI, after the header was added.
85       *
86       * @throws Exception If something goes wrong
87       */
88      @Test
89      void shouldStripUserInfo() throws Exception {
90          final MkContainer container = new MkGrizzlyContainer().next(
91              new MkAnswer.Simple(HttpsURLConnection.HTTP_NOT_FOUND),
92              MkQueryMatchers.hasHeader(
93                  "Authorization", Matchers.contains(
94                      BasicAuthWireTest.expectHeader("foo", "bar")
95                  )
96              )
97          ).start();
98          final String userinfo = "foo:bar";
99          final URI uri = UriBuilder.fromUri(container.home()).userInfo(
100             userinfo
101         ).build();
102         MatcherAssert.assertThat(
103             "should not contains user info",
104             Assertions.assertThrows(
105                 AssertionError.class,
106                 () -> new JdkRequest(uri)
107                     .through(BasicAuthWire.class)
108                     .fetch()
109                     .as(RestResponse.class)
110                     .assertStatus(HttpURLConnection.HTTP_OK)
111             ),
112             Matchers.<AssertionError>hasToString(
113                 Matchers.not(
114                     Matchers.containsString(userinfo)
115                 )
116             )
117         );
118         container.stop();
119     }
120 
121     /**
122      * Creates the expected authorization header value for the
123      * given username.
124      *
125      * @param username The username to create the header for
126      * @param password The password to create the header for
127      * @return The header value in the form
128      *  {@code Basic <base64 of username:password>}
129      */
130     private static String expectHeader(
131         final String username,
132         final String password
133     ) {
134         final String credentials = DatatypeConverter.printBase64Binary(
135             String.format(
136                 BasicAuthWireTest.CRED_FORMAT,
137                 username,
138                 password
139             ).getBytes(StandardCharsets.UTF_8)
140         );
141         return String.format("Basic %s", credentials);
142     }
143 }