You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by sm...@apache.org on 2022/08/26 16:09:37 UTC

[knox] branch master updated: KNOX-2792 - new REST API endpoint to set Authorization/Bearer header in the response using an environment variable (#627)

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

smolnar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new b7f9f2149 KNOX-2792 - new REST API endpoint to set Authorization/Bearer header in the response using an environment variable (#627)
b7f9f2149 is described below

commit b7f9f2149333460f4e870ccc1ed23717d4ef0ad5
Author: Sandor Molnar <sm...@apache.org>
AuthorDate: Fri Aug 26 18:09:32 2022 +0200

    KNOX-2792 - new REST API endpoint to set Authorization/Bearer header in the response using an environment variable (#627)
---
 gateway-service-auth/pom.xml                       |   5 +
 .../gateway/service/auth/AuthBearerResource.java   |  76 +++++++++++++++
 .../service/auth/AuthBearerResourceTest.java       | 102 +++++++++++++++++++++
 pom.xml                                            |   7 ++
 4 files changed, 190 insertions(+)

diff --git a/gateway-service-auth/pom.xml b/gateway-service-auth/pom.xml
index 0a4615d4d..b68757175 100644
--- a/gateway-service-auth/pom.xml
+++ b/gateway-service-auth/pom.xml
@@ -55,6 +55,11 @@
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>uk.org.webcompere</groupId>
+            <artifactId>system-stubs-junit4</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/AuthBearerResource.java b/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/AuthBearerResource.java
new file mode 100644
index 000000000..4b3d1fcda
--- /dev/null
+++ b/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/AuthBearerResource.java
@@ -0,0 +1,76 @@
+/*
+ * 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.knox.gateway.service.auth;
+
+import static javax.ws.rs.core.Response.ok;
+
+import java.util.Locale;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+/**
+ * The service populates HTTP "Authorization" header with the Bearer Token,
+ * obtained from an environment variable.
+ * <p>
+ * This implementation assumes that the token is not rotated as it never gets
+ * exposed to the end-user. Consider alternative ways of obtaining tokens(e.g.
+ * from files) and implement caching/refreshing mechanism if token rotation is
+ * required.
+ */
+@Path(AuthBearerResource.RESOURCE_PATH)
+public class AuthBearerResource {
+  static final String RESOURCE_PATH = "auth/api/v1/bearer";
+  static final String BEARER_AUTH_TOKEN_ENV_CONFIG = "auth.bearer.token.env";
+  static final String DEFAULT_BEARER_AUTH_TOKEN_ENV = "BEARER_AUTH_TOKEN";
+  static final String HEADER_FORMAT = "Bearer %s";
+
+  private String token;
+
+  @Context
+  HttpServletResponse response;
+
+  @Context
+  ServletContext context;
+
+  @PostConstruct
+  public void init() throws ServletException {
+    String bearerTokenEnvVariableName = context.getInitParameter(BEARER_AUTH_TOKEN_ENV_CONFIG);
+    if (bearerTokenEnvVariableName == null) {
+      bearerTokenEnvVariableName = DEFAULT_BEARER_AUTH_TOKEN_ENV;
+    }
+
+    token = System.getenv(bearerTokenEnvVariableName);
+    if (token == null) {
+      throw new ServletException(String.format(Locale.ROOT, "Token environment variable '%s' is not set", bearerTokenEnvVariableName));
+    }
+  }
+
+  @GET
+  public Response doGet() {
+    response.addHeader(HttpHeaders.AUTHORIZATION, String.format(Locale.ROOT, HEADER_FORMAT, token));
+    return ok().build();
+  }
+}
diff --git a/gateway-service-auth/src/test/java/org/apache/knox/gateway/service/auth/AuthBearerResourceTest.java b/gateway-service-auth/src/test/java/org/apache/knox/gateway/service/auth/AuthBearerResourceTest.java
new file mode 100644
index 000000000..5ffa311b0
--- /dev/null
+++ b/gateway-service-auth/src/test/java/org/apache/knox/gateway/service/auth/AuthBearerResourceTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.knox.gateway.service.auth;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
+
+import org.easymock.EasyMock;
+import org.junit.Rule;
+import org.junit.Test;
+
+import uk.org.webcompere.systemstubs.rules.EnvironmentVariablesRule;
+
+public class AuthBearerResourceTest {
+
+  @Rule
+  public EnvironmentVariablesRule environmentVariablesRule = new EnvironmentVariablesRule();
+
+  private static final String CUSTOM_TOKEN_ENV_VARIABLE = "MY_BEARER_TOKEN_ENV";
+  private static final String TOKEN = "TestBearerToken";
+
+  private ServletContext context;
+  private HttpServletResponse response;
+
+  private void configureCommonExpectations(String bearerTokenEnvVariableName, boolean expectHeader) {
+    context = EasyMock.createNiceMock(ServletContext.class);
+    EasyMock.expect(context.getInitParameter(AuthBearerResource.BEARER_AUTH_TOKEN_ENV_CONFIG)).andReturn(bearerTokenEnvVariableName).anyTimes();
+    response = EasyMock.createNiceMock(HttpServletResponse.class);
+    if (expectHeader) {
+      response.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + TOKEN);
+      EasyMock.expectLastCall();
+    }
+    EasyMock.replay(context, response);
+  }
+
+  @Test
+  public void testBearerTokenWithDefaultEnvVariableName() throws Exception {
+    testAuthBearerResource(null, true);
+  }
+
+  @Test
+  public void testBearerTokenWithCustomEnvVariableName() throws Exception {
+    testAuthBearerResource(CUSTOM_TOKEN_ENV_VARIABLE, true);
+  }
+
+  @Test
+  public void testNoBearerTokenWithDefaultEnvVariableName() throws Exception {
+    testAuthBearerResource(null, false);
+  }
+
+  @Test
+  public void testNoBearerTokenWithCustomEnvVariableName() throws Exception {
+    testAuthBearerResource(CUSTOM_TOKEN_ENV_VARIABLE, false);
+  }
+
+  private void testAuthBearerResource(String envVariableName, boolean setEnv) {
+    final String expectedEnvVariableName = envVariableName == null ? AuthBearerResource.DEFAULT_BEARER_AUTH_TOKEN_ENV : envVariableName;
+    boolean exceptionThrown = false;
+    try {
+      if (setEnv) {
+        environmentVariablesRule.set(expectedEnvVariableName, TOKEN);
+      }
+      configureCommonExpectations(envVariableName, setEnv);
+      final AuthBearerResource authBearerResource = new AuthBearerResource();
+      authBearerResource.context = context;
+      authBearerResource.response = response;
+      authBearerResource.init();
+      authBearerResource.doGet();
+      EasyMock.verify(response);
+    } catch (ServletException e) {
+      exceptionThrown = true;
+      assertEquals("Token environment variable '" + expectedEnvVariableName + "' is not set", e.getMessage());
+    }
+    if (setEnv) {
+      assertFalse(exceptionThrown);
+    } else {
+      assertTrue(exceptionThrown);
+    }
+  }
+
+}
diff --git a/pom.xml b/pom.xml
index a8eaa4c57..fe6e4f85a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -266,6 +266,7 @@
         <spring-vault.version>2.3.2</spring-vault.version>
         <stax-ex.version>1.8.3</stax-ex.version>
         <stax2-api.version>4.2.1</stax2-api.version>
+        <system-stubs-junit4.version>1.1.0</system-stubs-junit4.version>
         <swagger-annotations.version>1.6.2</swagger-annotations.version>
         <swagger-maven-plugin.version>3.1.7</swagger-maven-plugin.version>
         <taglibs-standard.version>1.2.5</taglibs-standard.version>
@@ -2521,6 +2522,12 @@
                 <artifactId>hsqldb</artifactId>
                 <version>${hsql.db.version}</version>
             </dependency>
+            <dependency>
+                <groupId>uk.org.webcompere</groupId>
+                <artifactId>system-stubs-junit4</artifactId>
+                <version>${system-stubs-junit4.version}</version>
+                <scope>test</scope>
+            </dependency>
         </dependencies>
     </dependencyManagement>