Browse Source

AMBARI-9609 - Views: Impersonator doesn't expose any way to POST a body or headers. (tbeerbower)

tbeerbower 10 years ago
parent
commit
4bdc4ad744

+ 6 - 11
ambari-server/src/main/java/org/apache/ambari/server/view/HttpImpersonatorImpl.java

@@ -24,7 +24,6 @@ import org.apache.ambari.server.proxy.ProxyService;
 import org.apache.ambari.view.ImpersonatorSetting;
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.HttpImpersonator;
-import org.apache.ambari.server.controller.internal.AppCookieManager;
 
 import java.io.BufferedReader;
 import java.io.IOException;
@@ -45,7 +44,6 @@ import java.util.ArrayList;
  */
 public class HttpImpersonatorImpl implements HttpImpersonator {
   private ViewContext context;
-  private AppCookieManager appCookieManager;
   private FactoryHelper helper;
 
   /**
@@ -57,15 +55,13 @@ public class HttpImpersonatorImpl implements HttpImpersonator {
     }
   }
 
-  public HttpImpersonatorImpl(ViewContext c, AppCookieManager appCookieManager) {
+  public HttpImpersonatorImpl(ViewContext c) {
     this.context = c;
-    this.appCookieManager = appCookieManager;
     this.helper = new FactoryHelper();
   }
 
-  public HttpImpersonatorImpl(ViewContext c, AppCookieManager appCookieManager, FactoryHelper h) {
+  public HttpImpersonatorImpl(ViewContext c, FactoryHelper h) {
     this.context = c;
-    this.appCookieManager = appCookieManager;
     this.helper = h;
   }
 
@@ -115,18 +111,17 @@ public class HttpImpersonatorImpl implements HttpImpersonator {
   /**
    * Returns the result of the HTTP request by setting the "doAs" impersonation for the query param and username
    * in @param impersonatorSetting.
-   * @param urlToRead URL to request
+   * @param url URL to request
    * @param requestType HTTP Request type: GET, PUT, POST, DELETE, etc.
    * @param impersonatorSetting Setting class with default values for username and doAs param name.
    *                           To use different values, call the setters of the object.
    * @return Return a response as a String
    */
   @Override
-  public String requestURL(String urlToRead, String requestType, final ImpersonatorSetting impersonatorSetting) {
+  public String requestURL(String url, String requestType, final ImpersonatorSetting impersonatorSetting) {
     String result = "";
     BufferedReader rd;
-    String line = null;
-    String url = urlToRead;
+    String line;
 
     if (url.toLowerCase().contains(impersonatorSetting.getDoAsParamName().toLowerCase())) {
       throw new IllegalArgumentException("URL cannot contain \"" + impersonatorSetting.getDoAsParamName() + "\" parameter");
@@ -145,7 +140,7 @@ public class HttpImpersonatorImpl implements HttpImpersonator {
       HttpURLConnection connection = urlStreamProvider.processURL(url, requestType, null, headers);
 
       int responseCode = connection.getResponseCode();
-      InputStream resultInputStream = null;
+      InputStream resultInputStream;
       if (responseCode >= ProxyService.HTTP_ERROR_RANGE_START) {
         resultInputStream = connection.getErrorStream();
       } else {

+ 2 - 2
ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java

@@ -331,7 +331,7 @@ public class ViewContextImpl implements ViewContext, ViewController {
   @Override
   public HttpImpersonatorImpl getHttpImpersonator() {
     ensureURLStreamProvider();
-    return new HttpImpersonatorImpl(this, streamProvider.getAppCookieManager());
+    return new HttpImpersonatorImpl(this);
   }
 
   @Override
@@ -376,7 +376,7 @@ public class ViewContextImpl implements ViewContext, ViewController {
   // ensure that the URL stream provider has been created
   private synchronized void ensureURLStreamProvider() {
     if (streamProvider == null) {
-      streamProvider = viewRegistry.createURLStreamProvider();
+      streamProvider = viewRegistry.createURLStreamProvider(this);
     }
   }
 

+ 12 - 10
ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java

@@ -1528,18 +1528,20 @@ public class ViewRegistry {
   /**
    * Factory method to create a view URL stream provider.
    *
+   * @param viewContext  the view context
+   *
    * @return a new view URL stream provider
    */
-  protected ViewURLStreamProvider createURLStreamProvider() {
-    ComponentSSLConfiguration configuration1 = ComponentSSLConfiguration.instance();
+  protected ViewURLStreamProvider createURLStreamProvider(ViewContext viewContext) {
+    ComponentSSLConfiguration sslConfiguration = ComponentSSLConfiguration.instance();
     org.apache.ambari.server.controller.internal.URLStreamProvider streamProvider =
         new org.apache.ambari.server.controller.internal.URLStreamProvider(
             configuration.getRequestConnectTimeout(),
             configuration.getRequestReadTimeout(),
-            configuration1.getTruststorePath(),
-            configuration1.getTruststorePassword(),
-            configuration1.getTruststoreType());
-    return new ViewURLStreamProvider(streamProvider);
+            sslConfiguration.getTruststorePath(),
+            sslConfiguration.getTruststorePassword(),
+            sslConfiguration.getTruststoreType());
+    return new ViewURLStreamProvider(viewContext, streamProvider);
   }
 
   /**
@@ -1548,14 +1550,14 @@ public class ViewRegistry {
    * @return a new view Ambari stream provider
    */
   protected ViewAmbariStreamProvider createAmbariStreamProvider() {
-    ComponentSSLConfiguration configuration1 = ComponentSSLConfiguration.instance();
+    ComponentSSLConfiguration sslConfiguration = ComponentSSLConfiguration.instance();
     org.apache.ambari.server.controller.internal.URLStreamProvider streamProvider =
         new org.apache.ambari.server.controller.internal.URLStreamProvider(
             DEFAULT_REQUEST_CONNECT_TIMEOUT,
             DEFAULT_REQUEST_READ_TIMEOUT,
-            configuration1.getTruststorePath(),
-            configuration1.getTruststorePassword(),
-            configuration1.getTruststoreType());
+            sslConfiguration.getTruststorePath(),
+            sslConfiguration.getTruststorePassword(),
+            sslConfiguration.getTruststoreType());
     return new ViewAmbariStreamProvider(streamProvider, ambariSessionManager, AmbariServer.getController());
   }
 }

+ 48 - 12
ambari-server/src/main/java/org/apache/ambari/server/view/ViewURLStreamProvider.java

@@ -18,11 +18,13 @@
 
 package org.apache.ambari.server.view;
 
-import org.apache.ambari.server.controller.internal.AppCookieManager;
 import org.apache.ambari.server.controller.internal.URLStreamProvider;
+import org.apache.ambari.server.proxy.ProxyService;
+import org.apache.ambari.view.ViewContext;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.HttpURLConnection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -32,6 +34,17 @@ import java.util.Map;
  * Wrapper around an internal URL stream provider.
  */
 public class ViewURLStreamProvider implements org.apache.ambari.view.URLStreamProvider {
+
+  /**
+   * The key for the "doAs" header.
+   */
+  private static final String DO_AS_PARAM = "doAs";
+
+  /**
+   * The view context.
+   */
+  private final ViewContext viewContext;
+
   /**
    * Internal stream provider.
    */
@@ -43,9 +56,11 @@ public class ViewURLStreamProvider implements org.apache.ambari.view.URLStreamPr
   /**
    * Construct a view URL stream provider.
    *
+   * @param viewContext     the associated view context
    * @param streamProvider  the underlying stream provider
    */
-  protected ViewURLStreamProvider(URLStreamProvider streamProvider) {
+  protected ViewURLStreamProvider(ViewContext viewContext, URLStreamProvider streamProvider) {
+    this.viewContext    = viewContext;
     this.streamProvider = streamProvider;
   }
 
@@ -53,26 +68,47 @@ public class ViewURLStreamProvider implements org.apache.ambari.view.URLStreamPr
   // ----- URLStreamProvider -----------------------------------------------
 
   @Override
-  public InputStream readFrom(String spec, String requestMethod, String params, Map<String, String> headers)
+  public InputStream readFrom(String spec, String requestMethod, String body, Map<String, String> headers)
       throws IOException {
     // adapt the headers to the internal URLStreamProvider processURL signature
     Map<String, List<String>> headerMap = new HashMap<String, List<String>>();
     for (Map.Entry<String, String> entry : headers.entrySet()) {
       headerMap.put(entry.getKey(), Collections.singletonList(entry.getValue()));
     }
-    return streamProvider.processURL(spec, requestMethod, params, headerMap).getInputStream();
+
+    HttpURLConnection connection = streamProvider.processURL(spec, requestMethod, body, headerMap);
+
+    int responseCode = connection.getResponseCode();
+
+    return responseCode >= ProxyService.HTTP_ERROR_RANGE_START ?
+        connection.getErrorStream() : connection.getInputStream();
   }
 
+  @Override
+  public InputStream readAs(String spec, String requestMethod, String body, Map<String, String> headers,
+                            String userName)
+      throws IOException {
+
+    if (spec.toLowerCase().contains(DO_AS_PARAM)) {
+      throw new IllegalArgumentException("URL cannot contain \"" + DO_AS_PARAM + "\" parameter.");
+    }
 
-  // ----- helper methods --------------------------------------------------
+    if (headers == null) {
+      headers = new HashMap<String, String>();
+    } else {
+      headers = new HashMap<String, String>(headers);
+    }
 
-  /**
-   * Get the associated app cookie manager
-   *
-   * @return get the app cookie manager
-   */
-  protected AppCookieManager getAppCookieManager() {
-    return streamProvider.getAppCookieManager();
+    headers.put(DO_AS_PARAM, userName);
+
+    return readFrom(spec, requestMethod, body, headers);
+  }
+
+  @Override
+  public InputStream readAsCurrent(String spec, String requestMethod, String body, Map<String, String> headers)
+      throws IOException {
+
+    return readAs(spec, requestMethod, body, headers, viewContext.getUsername());
   }
 }
 

+ 16 - 14
ambari-server/src/test/java/org/apache/ambari/server/view/HttpImpersonatorImplTest.java

@@ -18,11 +18,12 @@
 
 package org.apache.ambari.server.view;
 
-import junit.framework.TestCase;
 import org.apache.ambari.view.ImpersonatorSetting;
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.server.controller.internal.AppCookieManager;
 import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
 import org.mockito.Mockito;
 
 import java.io.BufferedReader;
@@ -35,7 +36,7 @@ import static org.mockito.Matchers.*;
 import static org.mockito.Mockito.when;
 
 
-public class HttpImpersonatorImplTest extends TestCase {
+public class HttpImpersonatorImplTest {
 
   String cookie;
   String username;
@@ -43,6 +44,7 @@ public class HttpImpersonatorImplTest extends TestCase {
   HttpImpersonatorImpl impersonator;
   String expectedResult;
 
+  @Before
   public void setUp() throws Exception {
     String uuid = UUID.randomUUID().toString().replace("-", "");
     this.cookie = uuid;
@@ -61,11 +63,11 @@ public class HttpImpersonatorImplTest extends TestCase {
     this.viewContext = Mockito.mock(ViewContext.class);
     when(this.viewContext.getUsername()).thenReturn(username);
 
-    this.impersonator = new HttpImpersonatorImpl(this.viewContext, mockAppCookieManager, mockFactory);
+    this.impersonator = new HttpImpersonatorImpl(this.viewContext, mockFactory);
     when(this.viewContext.getHttpImpersonator()).thenReturn(this.impersonator);
   }
 
-  @org.junit.Test
+  @Test
   public void testBasic() throws Exception {
     String urlToRead = "http://foo.com";
     String requestMethod = "GET";
@@ -80,12 +82,12 @@ public class HttpImpersonatorImplTest extends TestCase {
 
     // Test specific params
     HttpURLConnection conn2 = (HttpURLConnection) url.openConnection();
-    conn2 = this.viewContext.getHttpImpersonator().doAs(conn1, requestMethod, "admin", "username");
-    Assert.assertEquals(requestMethod, conn1.getRequestMethod());
-    Assert.assertEquals("admin", conn1.getRequestProperty("username"));
+    conn2 = this.viewContext.getHttpImpersonator().doAs(conn2, requestMethod, "admin", "username");
+    Assert.assertEquals(requestMethod, conn2.getRequestMethod());
+    Assert.assertEquals("admin", conn2.getRequestProperty("username"));
   }
 
-  @org.junit.Test
+  @Test
   public void testRequestURL() throws Exception {
     String urlToRead = "http://foo.com";
     String requestMethod = "GET";
@@ -97,7 +99,7 @@ public class HttpImpersonatorImplTest extends TestCase {
     Assert.assertEquals(this.expectedResult, actualResult);
   }
 
-  @org.junit.Test
+  @Test
   public void testRequestURLWithCustom() throws Exception {
     String urlToRead = "http://foo.com";
     String requestMethod = "GET";
@@ -109,7 +111,7 @@ public class HttpImpersonatorImplTest extends TestCase {
     Assert.assertEquals(this.expectedResult, actualResult);
   }
 
-  @org.junit.Test
+  @Test
   public void testInvalidURL() throws Exception {
     String urlToRead = "http://foo.com?" + "doAs" + "=hive";
     String requestMethod = "GET";
@@ -117,10 +119,10 @@ public class HttpImpersonatorImplTest extends TestCase {
 
     HttpURLConnection conn = (HttpURLConnection) url.openConnection();
     try {
-      conn = this.viewContext.getHttpImpersonator().doAs(conn, requestMethod);
-      fail("Expected an exception to be thrown." );
-    } catch(Exception e) {
-      ;
+      this.viewContext.getHttpImpersonator().doAs(conn, requestMethod);
+      Assert.fail("Expected an exception to be thrown.");
+    } catch(IllegalArgumentException e) {
+      //expected
     }
   }
 }

+ 3 - 3
ambari-server/src/test/java/org/apache/ambari/server/view/ViewContextImplTest.java

@@ -178,11 +178,11 @@ public class ViewContextImplTest {
 
     viewInstanceDefinition.addResourceProvider(type, provider);
 
-    expect(viewRegistry.createURLStreamProvider()).andReturn(urlStreamProvider);
+    ViewContextImpl viewContext = new ViewContextImpl(viewInstanceDefinition, viewRegistry);
 
-    replay(viewRegistry);
+    expect(viewRegistry.createURLStreamProvider(viewContext)).andReturn(urlStreamProvider);
 
-    ViewContextImpl viewContext = new ViewContextImpl(viewInstanceDefinition, viewRegistry);
+    replay(viewRegistry);
 
     Assert.assertEquals(urlStreamProvider, viewContext.getURLStreamProvider());
 

+ 51 - 9
ambari-server/src/test/java/org/apache/ambari/server/view/ViewURLStreamProviderTest.java

@@ -18,8 +18,8 @@
 
 package org.apache.ambari.server.view;
 
-import org.apache.ambari.server.controller.internal.AppCookieManager;
 import org.apache.ambari.server.controller.internal.URLStreamProvider;
+import org.apache.ambari.view.ViewContext;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -43,6 +43,7 @@ public class ViewURLStreamProviderTest {
     URLStreamProvider streamProvider = createNiceMock(URLStreamProvider.class);
     HttpURLConnection urlConnection = createNiceMock(HttpURLConnection.class);
     InputStream inputStream = createNiceMock(InputStream.class);
+    ViewContext viewContext = createNiceMock(ViewContext.class);
 
     Map<String, String> headers = new HashMap<String, String>();
     headers.put("header", "headerValue");
@@ -55,7 +56,7 @@ public class ViewURLStreamProviderTest {
 
     replay(streamProvider, urlConnection, inputStream);
 
-    ViewURLStreamProvider viewURLStreamProvider = new ViewURLStreamProvider(streamProvider);
+    ViewURLStreamProvider viewURLStreamProvider = new ViewURLStreamProvider(viewContext, streamProvider);
 
     Assert.assertEquals(inputStream, viewURLStreamProvider.readFrom("spec", "requestMethod", "params", headers));
 
@@ -63,18 +64,59 @@ public class ViewURLStreamProviderTest {
   }
 
   @Test
-  public void testGetAppCookieManager() throws Exception {
+  public void testReadAs() throws Exception {
+
     URLStreamProvider streamProvider = createNiceMock(URLStreamProvider.class);
-    AppCookieManager appCookieManager = createNiceMock(AppCookieManager.class);
+    HttpURLConnection urlConnection = createNiceMock(HttpURLConnection.class);
+    InputStream inputStream = createNiceMock(InputStream.class);
+    ViewContext viewContext = createNiceMock(ViewContext.class);
+
+    Map<String, String> headers = new HashMap<String, String>();
+    headers.put("header", "headerValue");
+    headers.put("doAs", "joe");
+
+    Map<String, List<String>> headerMap = new HashMap<String, List<String>>();
+    headerMap.put("header", Collections.singletonList("headerValue"));
+    headerMap.put("doAs", Collections.singletonList("joe"));
 
-    expect(streamProvider.getAppCookieManager()).andReturn(appCookieManager);
+    expect(streamProvider.processURL("spec", "requestMethod", "params", headerMap)).andReturn(urlConnection);
+    expect(urlConnection.getInputStream()).andReturn(inputStream);
+
+    replay(streamProvider, urlConnection, inputStream);
+
+    ViewURLStreamProvider viewURLStreamProvider = new ViewURLStreamProvider(viewContext, streamProvider);
+
+    Assert.assertEquals(inputStream, viewURLStreamProvider.readAs("spec", "requestMethod", "params", headers, "joe"));
+
+    verify(streamProvider, urlConnection, inputStream);
+  }
+
+  @Test
+  public void testReadAsCurrent() throws Exception {
+
+    URLStreamProvider streamProvider = createNiceMock(URLStreamProvider.class);
+    HttpURLConnection urlConnection = createNiceMock(HttpURLConnection.class);
+    InputStream inputStream = createNiceMock(InputStream.class);
+    ViewContext viewContext = createNiceMock(ViewContext.class);
+
+    Map<String, String> headers = new HashMap<String, String>();
+    headers.put("header", "headerValue");
+    headers.put("doAs", "joe");
+
+    Map<String, List<String>> headerMap = new HashMap<String, List<String>>();
+    headerMap.put("header", Collections.singletonList("headerValue"));
+    headerMap.put("doAs", Collections.singletonList("joe"));
+
+    expect(streamProvider.processURL("spec", "requestMethod", "params", headerMap)).andReturn(urlConnection);
+    expect(urlConnection.getInputStream()).andReturn(inputStream);
+    expect(viewContext.getUsername()).andReturn("joe").anyTimes();
 
-    replay(streamProvider, appCookieManager);
+    replay(streamProvider, urlConnection, inputStream, viewContext);
 
-    ViewURLStreamProvider viewURLStreamProvider = new ViewURLStreamProvider(streamProvider);
+    ViewURLStreamProvider viewURLStreamProvider = new ViewURLStreamProvider(viewContext, streamProvider);
 
-    Assert.assertEquals(appCookieManager, viewURLStreamProvider.getAppCookieManager());
+    Assert.assertEquals(inputStream, viewURLStreamProvider.readAsCurrent("spec", "requestMethod", "params", headers));
 
-    verify(streamProvider, appCookieManager);
+    verify(streamProvider, urlConnection, inputStream, viewContext);
   }
 }

+ 4 - 0
ambari-views/src/main/java/org/apache/ambari/view/HttpImpersonator.java

@@ -21,7 +21,11 @@ import java.net.HttpURLConnection;
 
 /**
  * Interface for views to impersonate users over HTTP request.
+ *
+ * @deprecated  As of release 2.0, replaced by
+ *              {@link URLStreamProvider#readAs(String, String, String, java.util.Map, String)}
  */
+@Deprecated
 public interface HttpImpersonator {
 
   /**

+ 4 - 0
ambari-views/src/main/java/org/apache/ambari/view/ImpersonatorSetting.java

@@ -19,7 +19,11 @@ package org.apache.ambari.view;
 
 /**
  * Interface that provides default values for impersonating, such as the username and doAs parameter name.
+ *
+ * @deprecated  As of release 2.0, replaced by
+ *              {@link URLStreamProvider#readAs(String, String, String, java.util.Map, String)}
  */
+@Deprecated
 public interface ImpersonatorSetting {
 
   /**

+ 37 - 2
ambari-views/src/main/java/org/apache/ambari/view/URLStreamProvider.java

@@ -31,13 +31,48 @@ public interface URLStreamProvider {
    *
    * @param spec           the String to parse as a URL
    * @param requestMethod  the HTTP method (GET,POST,PUT,etc.).
-   * @param params         the body of the request; may be null
+   * @param body           the body of the request; may be null
    * @param headers        the headers of the request; may be null
    *
    * @return the input stream
    *
    * @throws IOException if an error occurred connecting to the server
    */
-  public InputStream readFrom(String spec, String requestMethod, String params, Map<String, String> headers)
+  public InputStream readFrom(String spec, String requestMethod, String body, Map<String, String> headers)
       throws IOException;
+
+  /**
+   * Read from the input stream specified by the given URL spec as the given user.  This method sets the
+   * "doAs" user header to impersonate the user over the request.
+   *
+   * @param spec           the String to parse as a URL
+   * @param requestMethod  the HTTP method (GET,POST,PUT,etc.).
+   * @param body           the body of the request; may be null
+   * @param headers        the headers of the request; may be null
+   * @param userName       the "doAs" user name
+   *
+   * @return the input stream
+   *
+   * @throws IOException if an error occurred connecting to the server
+   */
+  public InputStream readAs(String spec, String requestMethod, String body, Map<String, String> headers,
+                            String userName)
+      throws IOException;
+
+  /**
+   * Read from the input stream specified by the given URL spec as the current user.  This method sets the
+   * "doAs" user header to impersonate the user over the request.
+   *
+   * @param spec           the String to parse as a URL
+   * @param requestMethod  the HTTP method (GET,POST,PUT,etc.).
+   * @param body           the body of the request; may be null
+   * @param headers        the headers of the request; may be null
+   *
+   * @return the input stream
+   *
+   * @throws IOException if an error occurred connecting to the server
+   */
+  public InputStream readAsCurrent(String spec, String requestMethod, String body, Map<String, String> headers)
+      throws IOException;
+
 }