This is an automated email from the ASF dual-hosted git repository.
lmccay 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 c2c029055 KNOX-3120 - Add a specialized use API for API KEY based on
KNOXTOKEN API (#1019)
c2c029055 is described below
commit c2c029055c5a8253dd766c655b836ca551afa7c2
Author: lmccay <[email protected]>
AuthorDate: Thu Apr 10 09:17:28 2025 -0400
KNOX-3120 - Add a specialized use API for API KEY based on KNOXTOKEN API
(#1019)
---
.../gateway/service/knoxtoken/APIKeyResource.java | 89 ++++++++++++++++++++++
.../knoxtoken/ClientCredentialsResource.java | 71 ++---------------
...esource.java => PasscodeTokenResourceBase.java} | 69 ++---------------
.../deploy/APIKeyServiceDeploymentContributor.java | 45 +++++++++++
...nox.gateway.deploy.ServiceDeploymentContributor | 3 +-
.../knoxtoken/TokenServiceResourceTest.java | 36 +++++++--
.../services/security/token/TokenMetadataType.java | 2 +-
7 files changed, 177 insertions(+), 138 deletions(-)
diff --git
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/APIKeyResource.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/APIKeyResource.java
new file mode 100644
index 000000000..b29750890
--- /dev/null
+++
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/APIKeyResource.java
@@ -0,0 +1,89 @@
+/*
+ * 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.knoxtoken;
+
+import org.apache.knox.gateway.services.security.token.TokenMetadata;
+import org.apache.knox.gateway.services.security.token.TokenMetadataType;
+import org.apache.knox.gateway.util.JsonUtils;
+
+import javax.inject.Singleton;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+
+@Path(APIKeyResource.RESOURCE_PATH)
+@Singleton
+public class APIKeyResource extends PasscodeTokenResourceBase {
+ private static final String TYPE = "type";
+ public static final String RESOURCE_PATH = "apikey/api/v1/auth/key";
+ public static final String API_KEY = "api_key";
+ public static final String KEY_ID = "key_id";
+
+ @Override
+ @GET
+ @Produces({ APPLICATION_JSON, APPLICATION_XML })
+ public Response doGet() {
+ return super.doGet();
+ }
+
+ @Override
+ @POST
+ @Produces({ APPLICATION_JSON, APPLICATION_XML })
+ public Response doPost() {
+ return super.doPost();
+ }
+
+ @Override
+ protected void addArbitraryTokenMetadata(TokenMetadata tokenMetadata) {
+ tokenMetadata.add(TYPE, TokenMetadataType.API_KEY.name());
+ super.addArbitraryTokenMetadata(tokenMetadata);
+ }
+
+ @Override
+ public Response getAuthenticationToken() {
+ UserContext context = buildUserContext(request);
+ Response response = checkForInvalidRequestResponse(context);
+ if (response != null) {
+ return response;
+ }
+
+ TokenResponseContext resp = getTokenResponse (context);
+ if (resp.responseMap != null) {
+ String passcode = (String) resp.responseMap.map.get(PASSCODE);
+ String tokenId = resp.responseMap.tokenId;
+
+ final HashMap<String, Object> map = new HashMap<>();
+ map.put(KEY_ID, tokenId);
+ map.put(API_KEY, passcode);
+ String jsonResponse = JsonUtils.renderAsJsonString(map);
+ return resp.responseBuilder.entity(jsonResponse).build();
+ }
+
+ if (resp.responseStr != null) {
+ return resp.responseBuilder.entity(resp.responseStr).build();
+ } else {
+ return resp.responseBuilder.build();
+ }
+ }
+}
diff --git
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
index 6def33dff..63bfd7f4d 100644
---
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
+++
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
@@ -17,84 +17,29 @@
*/
package org.apache.knox.gateway.service.knoxtoken;
-import com.nimbusds.jose.JOSEException;
-import com.nimbusds.jose.JWSAlgorithm;
-import com.nimbusds.jose.jwk.OctetSequenceKey;
-import com.nimbusds.jose.jwk.gen.OctetSequenceKeyGenerator;
-import org.apache.knox.gateway.config.GatewayConfig;
-import org.apache.knox.gateway.services.GatewayServices;
-import org.apache.knox.gateway.services.ServiceType;
-import org.apache.knox.gateway.services.security.AliasService;
-import org.apache.knox.gateway.services.security.AliasServiceException;
import org.apache.knox.gateway.services.security.token.TokenMetadata;
import org.apache.knox.gateway.services.security.token.TokenMetadataType;
-import org.apache.knox.gateway.services.security.token.TokenStateService;
-import org.apache.knox.gateway.services.security.token.impl.TokenMAC;
import org.apache.knox.gateway.util.JsonUtils;
import javax.inject.Singleton;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.util.HashMap;
-import java.util.UUID;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.APPLICATION_XML;
@Path(ClientCredentialsResource.RESOURCE_PATH)
@Singleton
-public class ClientCredentialsResource extends TokenResource {
+public class ClientCredentialsResource extends PasscodeTokenResourceBase {
private static final String TYPE = "type";
public static final String RESOURCE_PATH =
"clientid/api/v1/oauth/credentials";
public static final String CLIENT_ID = "client_id";
public static final String CLIENT_SECRET = "client_secret";
- private GatewayServices services;
-
- @Override
- protected ServletContext wrapContextForDefaultParams(ServletContext
context) throws ServletException {
- ServletContext wrapperContext = new ServletContextWrapper(context);
-
wrapperContext.setInitParameter(TokenStateService.CONFIG_SERVER_MANAGED,
"true");
- wrapperContext.setInitParameter(TokenResource.TOKEN_TTL_PARAM, "-1");
- services = (GatewayServices)
wrapperContext.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
- tokenStateService =
services.getService(ServiceType.TOKEN_STATE_SERVICE);
- final GatewayConfig gatewayConfig = (GatewayConfig)
wrapperContext.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
- gatewayConfig.getKnoxTokenHashAlgorithm();
- final AliasService aliasService =
services.getService(ServiceType.ALIAS_SERVICE);
- char[] hashkey = new char[0];
- try {
- hashkey =
aliasService.getPasswordFromAliasForGateway(TokenMAC.KNOX_TOKEN_HASH_KEY_ALIAS_NAME);
- } catch (AliasServiceException e) {
- throw new ServletException(e);
- }
- if (hashkey == null) {
- generateAndStoreHMACKeyAlias();
- }
- return wrapperContext;
- }
-
- private void generateAndStoreHMACKeyAlias() {
- final int keyLength =
Integer.parseInt(JWSAlgorithm.HS256.getName().substring(2));
- String jwkAsText = null;
- try {
- final OctetSequenceKey jwk = new
OctetSequenceKeyGenerator(keyLength).keyID(UUID.randomUUID().toString())
- .algorithm(JWSAlgorithm.HS256).generate();
- jwkAsText = jwk.getKeyValue().toJSONString().replace("\"", "");
- getAliasService().addAliasForCluster("__gateway",
TokenMAC.KNOX_TOKEN_HASH_KEY_ALIAS_NAME, jwkAsText);
- } catch (JOSEException | AliasServiceException e) {
- throw new RuntimeException("Error while generating " + keyLength +
" bits JWK secret", e);
- }
- }
-
- protected AliasService getAliasService() {
- return services.getService(ServiceType.ALIAS_SERVICE);
- }
-
@Override
@GET
@Produces({ APPLICATION_JSON, APPLICATION_XML })
@@ -117,17 +62,11 @@ public class ClientCredentialsResource extends
TokenResource {
@Override
public Response getAuthenticationToken() {
- Response response = enforceClientCertIfRequired();
- if (response != null) { return response; }
-
- response = onlyAllowGroupsToBeAddedWhenEnabled();
- if (response != null) { return response; }
-
UserContext context = buildUserContext(request);
-
- response = enforceTokenLimitsAsRequired(context.userName);
- if (response != null) { return response; }
-
+ Response response = checkForInvalidRequestResponse(context);
+ if (response != null) {
+ return response;
+ }
TokenResponseContext resp = getTokenResponse(context);
if (resp.responseMap != null) {
String passcode = (String) resp.responseMap.map.get(PASSCODE);
diff --git
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/PasscodeTokenResourceBase.java
similarity index 63%
copy from
gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
copy to
gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/PasscodeTokenResourceBase.java
index 6def33dff..6804fbf24 100644
---
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
+++
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/PasscodeTokenResourceBase.java
@@ -26,36 +26,16 @@ import org.apache.knox.gateway.services.GatewayServices;
import org.apache.knox.gateway.services.ServiceType;
import org.apache.knox.gateway.services.security.AliasService;
import org.apache.knox.gateway.services.security.AliasServiceException;
-import org.apache.knox.gateway.services.security.token.TokenMetadata;
-import org.apache.knox.gateway.services.security.token.TokenMetadataType;
import org.apache.knox.gateway.services.security.token.TokenStateService;
import org.apache.knox.gateway.services.security.token.impl.TokenMAC;
-import org.apache.knox.gateway.util.JsonUtils;
-import javax.inject.Singleton;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
-import java.util.HashMap;
import java.util.UUID;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static javax.ws.rs.core.MediaType.APPLICATION_XML;
-
-@Path(ClientCredentialsResource.RESOURCE_PATH)
-@Singleton
-public class ClientCredentialsResource extends TokenResource {
- private static final String TYPE = "type";
- public static final String RESOURCE_PATH =
"clientid/api/v1/oauth/credentials";
- public static final String CLIENT_ID = "client_id";
- public static final String CLIENT_SECRET = "client_secret";
-
- private GatewayServices services;
-
+public class PasscodeTokenResourceBase extends TokenResource {
+ protected GatewayServices services;
@Override
protected ServletContext wrapContextForDefaultParams(ServletContext
context) throws ServletException {
ServletContext wrapperContext = new ServletContextWrapper(context);
@@ -66,7 +46,7 @@ public class ClientCredentialsResource extends TokenResource {
final GatewayConfig gatewayConfig = (GatewayConfig)
wrapperContext.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
gatewayConfig.getKnoxTokenHashAlgorithm();
final AliasService aliasService =
services.getService(ServiceType.ALIAS_SERVICE);
- char[] hashkey = new char[0];
+ char[] hashkey;
try {
hashkey =
aliasService.getPasswordFromAliasForGateway(TokenMAC.KNOX_TOKEN_HASH_KEY_ALIAS_NAME);
} catch (AliasServiceException e) {
@@ -95,55 +75,16 @@ public class ClientCredentialsResource extends
TokenResource {
return services.getService(ServiceType.ALIAS_SERVICE);
}
- @Override
- @GET
- @Produces({ APPLICATION_JSON, APPLICATION_XML })
- public Response doGet() {
- return super.doGet();
- }
-
- @Override
- @POST
- @Produces({ APPLICATION_JSON, APPLICATION_XML })
- public Response doPost() {
- return super.doPost();
- }
-
- @Override
- protected void addArbitraryTokenMetadata(TokenMetadata tokenMetadata) {
- tokenMetadata.add(TYPE, TokenMetadataType.CLIENT_ID.name());
- super.addArbitraryTokenMetadata(tokenMetadata);
- }
-
- @Override
- public Response getAuthenticationToken() {
+ protected Response checkForInvalidRequestResponse(UserContext context) {
Response response = enforceClientCertIfRequired();
if (response != null) { return response; }
response = onlyAllowGroupsToBeAddedWhenEnabled();
if (response != null) { return response; }
- UserContext context = buildUserContext(request);
-
response = enforceTokenLimitsAsRequired(context.userName);
if (response != null) { return response; }
- TokenResponseContext resp = getTokenResponse(context);
- if (resp.responseMap != null) {
- String passcode = (String) resp.responseMap.map.get(PASSCODE);
- String tokenId = resp.responseMap.tokenId;
-
- final HashMap<String, Object> map = new HashMap<>();
- map.put(CLIENT_ID, tokenId);
- map.put(CLIENT_SECRET, passcode);
- String jsonResponse = JsonUtils.renderAsJsonString(map);
- return resp.responseBuilder.entity(jsonResponse).build();
- }
-
- if (resp.responseStr != null) {
- return resp.responseBuilder.entity(resp.responseStr).build();
- } else {
- return resp.responseBuilder.build();
- }
+ return response;
}
}
diff --git
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/deploy/APIKeyServiceDeploymentContributor.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/deploy/APIKeyServiceDeploymentContributor.java
new file mode 100644
index 000000000..ebfafa7a3
--- /dev/null
+++
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/deploy/APIKeyServiceDeploymentContributor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.knoxtoken.deploy;
+
+import org.apache.knox.gateway.jersey.JerseyServiceDeploymentContributorBase;
+
+public class APIKeyServiceDeploymentContributor extends
JerseyServiceDeploymentContributorBase {
+
+ public static final String ROLE = "APIKEY";
+
+ @Override
+ public String getRole() {
+ return ROLE;
+ }
+
+ @Override
+ public String getName() {
+ return "APIKeyService";
+ }
+
+ @Override
+ protected String[] getPackages() {
+ return new String[]{ "org.apache.knox.gateway.service.knoxtoken" };
+ }
+
+ @Override
+ protected String[] getPatterns() {
+ return new String[]{ "apikey/api/**?**" };
+ }
+}
diff --git
a/gateway-service-knoxtoken/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor
b/gateway-service-knoxtoken/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor
index 5d15627dd..2151d84f2 100644
---
a/gateway-service-knoxtoken/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor
+++
b/gateway-service-knoxtoken/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor
@@ -17,4 +17,5 @@
##########################################################################
org.apache.knox.gateway.service.knoxtoken.deploy.TokenServiceDeploymentContributor
-org.apache.knox.gateway.service.knoxtoken.deploy.ClientCredentialsServiceDeploymentContributor
\ No newline at end of file
+org.apache.knox.gateway.service.knoxtoken.deploy.ClientCredentialsServiceDeploymentContributor
+org.apache.knox.gateway.service.knoxtoken.deploy.APIKeyServiceDeploymentContributor
\ No newline at end of file
diff --git
a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
index ef35b082f..9613b28b9 100644
---
a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
+++
b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
@@ -1319,6 +1319,30 @@ public class TokenServiceResourceTest {
testPasscodeToken(false, false, false);
}
+ @Test
+ public void testClientCredentialsResponse() throws Exception {
+ Map<String, String> contextExpectations = new HashMap<>();
+ try {
+ tss = new PersistentTestTokenStateService();
+ configureCommonExpectations(contextExpectations, Boolean.TRUE);
+
+ ClientCredentialsResource ccr = new ClientCredentialsResource();
+ ccr.request = request;
+ ccr.context = context;
+ ccr.init();
+
+ Response response = ccr.doPost();
+ assertEquals(200, response.getStatus());
+
+ String clientId = getTagValue(response.getEntity().toString(),
ClientCredentialsResource.CLIENT_ID);
+ assertNotNull(clientId);
+ String clientSecret = getTagValue(response.getEntity().toString(),
ClientCredentialsResource.CLIENT_SECRET);
+ assertNotNull(clientSecret);
+ } finally {
+ tss = new TestTokenStateService();
+ }
+ }
+
@Test
public void
passcodeShouldNotBeInResponseIfTokenStateServiceIsNotPersistent() throws
Exception {
testPasscodeToken(true, false, false);
@@ -1396,13 +1420,13 @@ public class TokenServiceResourceTest {
}
@Test
- public void testClientCredentialsResponse() throws Exception {
+ public void testAPIKeyResponse() throws Exception {
Map<String, String> contextExpectations = new HashMap<>();
try {
tss = new PersistentTestTokenStateService();
configureCommonExpectations(contextExpectations, Boolean.TRUE);
- ClientCredentialsResource ccr = new ClientCredentialsResource();
+ APIKeyResource ccr = new APIKeyResource();
ccr.request = request;
ccr.context = context;
ccr.init();
@@ -1410,10 +1434,10 @@ public class TokenServiceResourceTest {
Response response = ccr.doPost();
assertEquals(200, response.getStatus());
- String clientId = getTagValue(response.getEntity().toString(),
ClientCredentialsResource.CLIENT_ID);
- assertNotNull(clientId);
- String clientSecret = getTagValue(response.getEntity().toString(),
ClientCredentialsResource.CLIENT_SECRET);
- assertNotNull(clientSecret);
+ String keyId = getTagValue(response.getEntity().toString(),
APIKeyResource.KEY_ID);
+ assertNotNull(keyId);
+ String apikey = getTagValue(response.getEntity().toString(),
APIKeyResource.API_KEY);
+ assertNotNull(apikey);
} finally {
tss = new TestTokenStateService();
}
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenMetadataType.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenMetadataType.java
index a4c27140b..17e82e0af 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenMetadataType.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenMetadataType.java
@@ -18,6 +18,6 @@ package org.apache.knox.gateway.services.security.token;
public enum TokenMetadataType {
- JWT, KNOXSSO_COOKIE, CLIENT_ID;
+ JWT, KNOXSSO_COOKIE, CLIENT_ID, API_KEY;
}