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 <smol...@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>