KNOX-2770 - KnoxToken doAs support depends on token state service and a service-level configuration (#609)
diff --git a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
index 42fc815..ee8d100 100644
--- a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
+++ b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
@@ -145,7 +145,7 @@
private static final String TARGET_ENDPOINT_PULIC_CERT_PEM = TOKEN_PARAM_PREFIX + "target.endpoint.cert.pem";
static final String QUERY_PARAMETER_DOAS = "doAs";
static final String PROXYUSER_PREFIX = TOKEN_PARAM_PREFIX + "proxyuser";
- private static final String IMPERSONATION_ENABLED_PARAM = TOKEN_PARAM_PREFIX + "impersonation.enabled";
+ static final String IMPERSONATION_ENABLED_PARAM = TOKEN_PARAM_PREFIX + "impersonation.enabled";
private static final String IMPERSONATION_ENABLED_TEXT = "impersonationEnabled";
public static final String KNOX_TOKEN_INCLUDE_GROUPS = TOKEN_PARAM_PREFIX + "include.groups";
public static final String KNOX_TOKEN_ISSUER = TOKEN_PARAM_PREFIX + "issuer";
@@ -173,6 +173,7 @@
private int tokenLimitPerUser;
private boolean includeGroupsInTokenAllowed;
private String tokenIssuer;
+ private boolean impersonationEnabled;
enum UserLimitExceededAction {REMOVE_OLDEST, RETURN_ERROR};
private UserLimitExceededAction userLimitExceededAction = UserLimitExceededAction.RETURN_ERROR;
@@ -269,6 +270,12 @@
endpointPublicCert = targetEndpointPublicCert;
}
+ // KnoxToken impersonation should be configurable regardless of the token state
+ // management status (i.e. even if token state management is enabled users
+ // should be able to opt-out token impersonation
+ final String impersonationEnabledValue = context.getInitParameter(IMPERSONATION_ENABLED_PARAM);
+ impersonationEnabled = impersonationEnabledValue == null ? Boolean.TRUE : Boolean.parseBoolean(impersonationEnabledValue);
+
// If server-managed token expiration is configured, set the token state service
if (isServerManagedTokenStateEnabled()) {
String topologyName = getTopologyName();
@@ -314,11 +321,15 @@
} else {
log.noRenewersConfigured(topologyName);
}
+
+ // refreshing Hadoop ProxyUser groups config only makes sense if token state management is turned on
+ // and impersonation is enabled
+ if (impersonationEnabled) {
+ final Configuration conf = AuthFilterUtils.getProxyUserConfiguration(context, PROXYUSER_PREFIX);
+ ProxyUsers.refreshSuperUserGroupsConfiguration(conf, PROXYUSER_PREFIX);
+ }
}
setTokenStateServiceStatusMap();
-
- final Configuration conf = AuthFilterUtils.getProxyUserConfiguration(context, PROXYUSER_PREFIX);
- ProxyUsers.refreshSuperUserGroupsConfiguration(conf, PROXYUSER_PREFIX);
}
private String getTokenTTLAsText() {
@@ -368,9 +379,7 @@
final Boolean lifespanInputEnabled = lifespanInputEnabledValue == null ? Boolean.TRUE : Boolean.parseBoolean(lifespanInputEnabledValue);
tokenStateServiceStatusMap.put(LIFESPAN_INPUT_ENABLED_TEXT, lifespanInputEnabled.toString());
- final String impersonationEnabledValue = context.getInitParameter(IMPERSONATION_ENABLED_PARAM);
- final Boolean impersonationEnabled = impersonationEnabledValue == null ? Boolean.TRUE : Boolean.parseBoolean(impersonationEnabledValue);
- tokenStateServiceStatusMap.put(IMPERSONATION_ENABLED_TEXT, impersonationEnabled.toString());
+ tokenStateServiceStatusMap.put(IMPERSONATION_ENABLED_TEXT, Boolean.toString(impersonationEnabled));
}
private void populateAllowedTokenStateBackendForTokenGenApp(final String actualTokenServiceName) {
@@ -711,7 +720,8 @@
String userName = request.getUserPrincipal().getName();
String createdBy = null;
// checking the doAs user only makes sense if tokens are managed (this is where we store the userName information)
- if (tokenStateService != null) {
+ // and if impersonation is enabled
+ if (impersonationEnabled && tokenStateService != null) {
final String doAsUser = request.getParameter(QUERY_PARAMETER_DOAS);
if (doAsUser != null && !doAsUser.equals(userName)) {
try {
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 6812b19..bf06269 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
@@ -170,6 +170,9 @@
if (contextExpectations.containsKey(TokenResource.QUERY_PARAMETER_DOAS)) {
EasyMock.expect(request.getParameter(TokenResource.QUERY_PARAMETER_DOAS)).andReturn(contextExpectations.get(TokenResource.QUERY_PARAMETER_DOAS)).anyTimes();
}
+ if (contextExpectations.containsKey(TokenResource.IMPERSONATION_ENABLED_PARAM)) {
+ EasyMock.expect(request.getParameter(TokenResource.IMPERSONATION_ENABLED_PARAM)).andReturn(contextExpectations.get(TokenResource.IMPERSONATION_ENABLED_PARAM)).anyTimes();
+ }
EasyMock.expect(request.getParameterNames()).andReturn(Collections.emptyEnumeration()).anyTimes();
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
@@ -1102,11 +1105,21 @@
@Test
public void testCreateImpersonatedToken() throws Exception {
+ testCreateImpersonatedToken(true);
+ }
+
+ @Test
+ public void testImpersonationDisabled() throws Exception {
+ testCreateImpersonatedToken(false);
+ }
+
+ private void testCreateImpersonatedToken(boolean enableImpersonation) throws Exception {
final String impersonatedUser = "testUser";
final Map<String, String> contextExpectations = new HashMap<>();
contextExpectations.put(TokenResource.QUERY_PARAMETER_DOAS, impersonatedUser);
contextExpectations.put(TokenResource.PROXYUSER_PREFIX + "." + USER_NAME + ".users", impersonatedUser);
contextExpectations.put(TokenResource.PROXYUSER_PREFIX + "." + USER_NAME + ".hosts", "*");
+ contextExpectations.put(TokenResource.IMPERSONATION_ENABLED_PARAM, Boolean.toString(enableImpersonation));
configureCommonExpectations(contextExpectations, Boolean.TRUE);
final TokenResource tr = new TokenResource();
@@ -1116,13 +1129,18 @@
tr.doGet();
- final Response getKnoxTokensResponse = getUserTokensResponse(tr, true);
+ final Response getKnoxTokensResponse = getUserTokensResponse(tr, enableImpersonation);
final Collection<LinkedHashMap<String, Object>> tokens = ((Map<String, Collection<LinkedHashMap<String, Object>>>) JsonUtils
.getObjectFromJsonString(getKnoxTokensResponse.getEntity().toString())).get("tokens");
final LinkedHashMap<String, Object> knoxToken = tokens.iterator().next();
final Map<String, String> metadata = (Map<String, String>) knoxToken.get("metadata");
- assertEquals(metadata.get("createdBy"), USER_NAME);
- assertEquals(metadata.get("userName"), impersonatedUser);
+ if (enableImpersonation) {
+ assertEquals(metadata.get("createdBy"), USER_NAME);
+ assertEquals(metadata.get("userName"), impersonatedUser);
+ } else {
+ assertNull(metadata.get("createdBy"));
+ assertEquals(USER_NAME, metadata.get("userName"));
+ }
}
@Test