View Javadoc

1   package com.atlassian.sal.core.net;
2   
3   import com.atlassian.sal.api.net.Request;
4   import com.atlassian.sal.api.net.ResponseException;
5   import com.atlassian.sal.api.user.UserManager;
6   import com.atlassian.sal.core.trusted.CertificateFactory;
7   import com.atlassian.security.auth.trustedapps.EncryptedCertificate;
8   import com.atlassian.security.auth.trustedapps.TrustedApplicationUtils;
9   import org.apache.http.Header;
10  import org.apache.http.HttpClientConnection;
11  import org.apache.http.HttpException;
12  import org.apache.http.HttpRequest;
13  import org.apache.http.HttpResponse;
14  import org.apache.http.HttpStatus;
15  import org.apache.http.ProtocolVersion;
16  import org.apache.http.conn.ConnectionRequest;
17  import org.apache.http.conn.HttpClientConnectionManager;
18  import org.apache.http.conn.routing.HttpRoute;
19  import org.apache.http.entity.StringEntity;
20  import org.apache.http.message.BasicHttpResponse;
21  import org.apache.http.protocol.HttpContext;
22  import org.apache.http.protocol.HttpRequestExecutor;
23  import org.hamcrest.FeatureMatcher;
24  import org.hamcrest.Matcher;
25  import org.junit.Before;
26  import org.junit.Rule;
27  import org.junit.Test;
28  import org.junit.rules.ExpectedException;
29  import org.junit.runner.RunWith;
30  import org.mockito.ArgumentCaptor;
31  import org.mockito.Captor;
32  import org.mockito.Mock;
33  import org.mockito.runners.MockitoJUnitRunner;
34  
35  import java.io.IOException;
36  import java.nio.charset.StandardCharsets;
37  import java.text.MessageFormat;
38  import java.util.concurrent.ExecutionException;
39  import java.util.concurrent.TimeUnit;
40  
41  import static org.hamcrest.MatcherAssert.assertThat;
42  import static org.hamcrest.Matchers.arrayContaining;
43  import static org.hamcrest.Matchers.equalTo;
44  import static org.mockito.Matchers.any;
45  import static org.mockito.Matchers.anyInt;
46  import static org.mockito.Matchers.anyObject;
47  import static org.mockito.Matchers.eq;
48  import static org.mockito.Mockito.mock;
49  import static org.mockito.Mockito.verify;
50  import static org.mockito.Mockito.when;
51  
52  @RunWith(MockitoJUnitRunner.class)
53  public class TestHttpClientTrustedRequest {
54  
55      private static final String DUMMY_HOST = "dummy.atlassian.test";
56      private static final String DUMMY_HTTP_URL = MessageFormat.format("http://{0}/", DUMMY_HOST);
57  
58      private static final String DUMMY_USERNAME = "dummy";
59      private static final String DUMMY_TRUSTED_TOKEN_ID = "dummy-id";
60  
61      @Rule
62      public ExpectedException thrown = ExpectedException.none();
63  
64      @Mock
65      private HttpRequestExecutor mockRequestExecutor;
66  
67      @Mock
68      private HttpClientConnectionManager mockConnectionManager;
69  
70      @Mock
71      private CertificateFactory certificateFactory;
72  
73      @Mock
74      private EncryptedCertificate encryptedCertificate;
75  
76      @Mock
77      private UserManager userManager;
78  
79      private HttpClientTrustedRequestFactory requestFactory;
80  
81      @Captor
82      private ArgumentCaptor<HttpRequest> requestCaptor;
83  
84      @Before
85      public void setup() throws InterruptedException, ExecutionException, IOException, HttpException {
86          requestFactory = new HttpClientWithMockConnectionTrustedRequestFactory(userManager, certificateFactory, mockConnectionManager, mockRequestExecutor);
87  
88          // Always respond with a 200/OK message
89          when(mockRequestExecutor.execute(any(HttpRequest.class), any(HttpClientConnection.class),
90                  any(HttpContext.class))).thenReturn(createOkResponse());
91  
92          // This allows us to hook in to the connection details that HttpClient would have made
93          final HttpClientConnection conn = mock(HttpClientConnection.class);
94          final ConnectionRequest connRequest = mock(ConnectionRequest.class);
95          when(connRequest.get(anyInt(), any(TimeUnit.class))).thenReturn(conn);
96          when(mockConnectionManager.requestConnection(any(HttpRoute.class), anyObject())).thenReturn(connRequest);
97  
98          // Setup trusted apps mocks
99          when(userManager.getRemoteUsername()).thenReturn(DUMMY_USERNAME);
100         when(encryptedCertificate.getID()).thenReturn(DUMMY_TRUSTED_TOKEN_ID);
101         when(certificateFactory.createCertificate(eq(DUMMY_USERNAME), eq(DUMMY_HTTP_URL))).thenReturn(encryptedCertificate);
102     }
103 
104     private static HttpResponse createOkResponse() {
105         final BasicHttpResponse response = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), HttpStatus.SC_OK, "OK");
106         response.setEntity(new StringEntity("test body", StandardCharsets.UTF_8));
107         return response;
108     }
109 
110     // TODO @alex fix TrustedTokenScheme#authenticate
111     @Test
112     public void assertThatTrustedTokenHeadersAdded() throws ResponseException, IOException, HttpException {
113         final HttpClientTrustedRequest request = requestFactory.createTrustedRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
114 
115         request.addTrustedTokenAuthentication(DUMMY_HOST);
116         request.execute();
117 
118         verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
119         final HttpRequest lastRequest = requestCaptor.getValue();
120         final Header[] headers = lastRequest.getHeaders(TrustedApplicationUtils.Header.Request.ID);
121 
122         //noinspection unchecked
123         assertThat(headers, arrayContaining(headerWithValue(equalTo(DUMMY_TRUSTED_TOKEN_ID))));
124 
125     }
126 
127     private static Matcher<Header> headerWithValue(final Matcher<String> valueMatcher) {
128         return new FeatureMatcher<Header, String>(valueMatcher, "header with value", "header value") {
129             @Override
130             protected String featureValueOf(final Header header) {
131                 return header.getValue();
132             }
133         };
134     }
135 }