You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ra...@apache.org on 2019/12/11 10:24:32 UTC

[sling-org-apache-sling-committer-cli] branch master updated: SLING-8864 - Report authentication errors immediately without looking at the response's body

This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-committer-cli.git


The following commit(s) were added to refs/heads/master by this push:
     new 75b5594  SLING-8864 - Report authentication errors immediately without looking at the response's body
75b5594 is described below

commit 75b55946d861058d4358cd18db883a9a9613720f
Author: Radu Cotescu <17...@users.noreply.github.com>
AuthorDate: Wed Dec 11 11:24:26 2019 +0100

    SLING-8864 - Report authentication errors immediately without looking at the response's body
    
    * added a response interceptor which throws an ISE when a server returns a 401 status code
---
 .../sling/cli/impl/http/HttpClientFactory.java     |  15 ++-
 .../sling/cli/impl/http/HttpClientFactoryTest.java | 103 +++++++++++++++++++++
 2 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/sling/cli/impl/http/HttpClientFactory.java b/src/main/java/org/apache/sling/cli/impl/http/HttpClientFactory.java
index adc8d8e..4fbc065 100644
--- a/src/main/java/org/apache/sling/cli/impl/http/HttpClientFactory.java
+++ b/src/main/java/org/apache/sling/cli/impl/http/HttpClientFactory.java
@@ -17,9 +17,13 @@
 package org.apache.sling.cli.impl.http;
 
 import org.apache.http.HttpHost;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.HttpStatus;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.AuthCache;
+import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.impl.auth.BasicScheme;
 import org.apache.http.impl.client.BasicAuthCache;
@@ -61,9 +65,18 @@ public class HttpClientFactory {
     }
 
     public CloseableHttpClient newClient() {
-        
+        final String[] urlHolder = new String[1];
         return HttpClients.custom()
                 .setDefaultCredentialsProvider(newCredentialsProvider())
+                .addInterceptorFirst(
+                        (HttpRequestInterceptor) (request, context) ->
+                        urlHolder[0] = ((HttpRequestWrapper) request).getOriginal().getRequestLine().getUri()
+                )
+                .addInterceptorFirst((HttpResponseInterceptor) (response, context) -> {
+                    if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
+                        throw new IllegalStateException("Server returned a 401 status; please check your authentication details for " + urlHolder[0]);
+                    }
+                })
                 .build();
     }
 
diff --git a/src/test/java/org/apache/sling/cli/impl/http/HttpClientFactoryTest.java b/src/test/java/org/apache/sling/cli/impl/http/HttpClientFactoryTest.java
new file mode 100644
index 0000000..e468314
--- /dev/null
+++ b/src/test/java/org/apache/sling/cli/impl/http/HttpClientFactoryTest.java
@@ -0,0 +1,103 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.cli.impl.http;
+
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.sling.cli.impl.CredentialsService;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpServer;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class HttpClientFactoryTest {
+
+    private HttpServer server;
+    private Map<String, String> replacedProperties;
+    private Map<String, String> testProperties;
+
+    @Rule
+    public OsgiContext osgiContext = new OsgiContext();
+
+    @Before
+    public void before() throws Throwable {
+        replacedProperties = new HashMap<>();
+        testProperties = new HashMap<>();
+        testProperties.put("asf.username", "asf.username");
+        testProperties.put("asf.password", "asf.password");
+        testProperties.put("jira.username", "jira.username");
+        testProperties.put("jira.password", "jira.password");
+        for (Map.Entry<String, String> testProperty : testProperties.entrySet()) {
+            String originalValue = System.getProperty(testProperty.getKey());
+            if (originalValue != null) {
+                replacedProperties.put(testProperty.getKey(), originalValue);
+            }
+            System.setProperty(testProperty.getKey(), testProperty.getValue());
+        }
+        server = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
+        HttpContext rootContext = server.createContext("/");
+        rootContext.setHandler(ex -> {
+            ex.sendResponseHeaders(401, -1);
+            ex.close();
+        });
+        server.start();
+        osgiContext.registerInjectActivateService(new CredentialsService());
+        osgiContext.registerInjectActivateService(new HttpClientFactory());
+    }
+
+    @Test
+    public void test401() {
+        HttpClientFactory factory = osgiContext.getService(HttpClientFactory.class);
+        if (factory == null) {
+            throw new IllegalStateException("Unable to retrieve an HttpClientFactory.");
+        }
+        CloseableHttpClient client = factory.newClient();
+        HttpGet httpGet = new HttpGet("http://" + server.getAddress().getHostString() + ":" + server.getAddress().getPort());
+        Throwable t = null;
+        try {
+            client.execute(httpGet);
+        } catch (Exception e) {
+            t = e;
+        }
+        assertNotNull(t);
+        assertTrue(t.getMessage().contains("Server returned a 401 status; please check your authentication details"));
+    }
+
+    @After
+    public void after() {
+        server.stop(0);
+        for (String testProperty : testProperties.keySet()) {
+            System.clearProperty(testProperty);
+        }
+        for (Map.Entry<String, String> replacedProperty : replacedProperties.entrySet()) {
+            System.setProperty(replacedProperty.getKey(), replacedProperty.getValue());
+        }
+    }
+}