Skip to content

Commit

Permalink
Support Url Encode in Athenz auth params (#1073)
Browse files Browse the repository at this point in the history
  • Loading branch information
hrsakai authored and merlimat committed Jan 18, 2018
1 parent de8d09c commit a5c123e
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 25 deletions.
Expand Up @@ -52,6 +52,9 @@

public class AuthenticationAthenz implements Authentication, EncodedAuthenticationParameterSupport {

private static final String APPLICATION_X_PEM_FILE = "application/x-pem-file";
private static final String APPLICATION_X_PEM_FILE_BASE64 = "application/x-pem-file;base64";

private transient ZTSClient ztsClient = null;
private String tenantDomain;
private String tenantService;
Expand Down Expand Up @@ -107,7 +110,9 @@ public void configure(String encodedAuthParamString) {
// Convert JSON to Map
try {
ObjectMapper jsonMapper = ObjectMapperFactory.create();
Map<String, String> authParamsMap = jsonMapper.readValue(encodedAuthParamString, new TypeReference<HashMap<String, String>>() {});
Map<String, String> authParamsMap = jsonMapper.readValue(encodedAuthParamString,
new TypeReference<HashMap<String, String>>() {
});
setAuthParams(authParamsMap);
} catch (IOException e) {
throw new IllegalArgumentException("Failed to parse authParams");
Expand All @@ -119,7 +124,7 @@ public void configure(Map<String, String> authParams) {
setAuthParams(authParams);
}

private void setAuthParams(Map<String, String> authParams){
private void setAuthParams(Map<String, String> authParams) {
this.tenantDomain = authParams.get("tenantDomain");
this.tenantService = authParams.get("tenantService");
this.providerDomain = authParams.get("providerDomain");
Expand All @@ -129,11 +134,11 @@ private void setAuthParams(Map<String, String> authParams){
} else {
this.privateKey = loadPrivateKey(authParams.get("privateKey"));
}
if(this.privateKey == null) {

if (this.privateKey == null) {
throw new IllegalArgumentException("Failed to load private key from privateKey or privateKeyPath field");
}

this.keyId = authParams.getOrDefault("keyId", "0");
if (authParams.containsKey("athenzConfPath")) {
System.setProperty("athenz.athenz_conf", authParams.get("athenzConfPath"));
Expand Down Expand Up @@ -172,15 +177,20 @@ private PrivateKey loadPrivateKey(String privateKeyURL) {
privateKey = Crypto.loadPrivateKey(new File(privateKeyURL));
} else if (uri.getScheme().equals("file")) {
privateKey = Crypto.loadPrivateKey(new File(uri.getPath()));
} else if(uri.getScheme().equals("data")) {
} else if (uri.getScheme().equals("data")) {
List<String> dataParts = Splitter.on(",").splitToList(uri.getSchemeSpecificPart());
if (dataParts.get(0).equals("application/x-pem-file;base64")) {
// Support Urlencode but not decode here because already decoded by URI class.
if (dataParts.get(0).equals(APPLICATION_X_PEM_FILE)) {
privateKey = Crypto.loadPrivateKey(dataParts.get(1));
// Support base64
} else if (dataParts.get(0).equals(APPLICATION_X_PEM_FILE_BASE64)) {
privateKey = Crypto.loadPrivateKey(new String(Base64.getDecoder().decode(dataParts.get(1))));
} else {
throw new IllegalArgumentException("Unsupported media type or encoding format: " + dataParts.get(0));
throw new IllegalArgumentException(
"Unsupported media type or encoding format: " + dataParts.get(0));
}
}
} catch(URISyntaxException e) {
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Invalid privateKey format");
}
return privateKey;
Expand Down
Expand Up @@ -19,20 +19,29 @@
package org.apache.pulsar.client.impl.auth;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import org.testng.annotations.Test;
import org.apache.pulsar.client.api.AuthenticationDataProvider;
import org.apache.pulsar.client.impl.auth.AuthenticationAthenz;
import org.apache.pulsar.common.util.ObjectMapperFactory;
import static org.apache.pulsar.common.util.Codec.encode;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yahoo.athenz.auth.util.Crypto;
import com.yahoo.athenz.zts.RoleToken;
import com.yahoo.athenz.zts.ZTSClient;

Expand All @@ -41,24 +50,12 @@ public class AuthenticationAthenzTest {
private AuthenticationAthenz auth;
private static final String TENANT_DOMAIN = "test_tenant";
private static final String TENANT_SERVICE = "test_service";
private static final String PROVIDER_DOMAIN = "test_provider";
private static final String PRIVATE_KEY_PATH = "./src/test/resources/tenant_private.pem";

@BeforeClass
public void setup() throws Exception {

// Configure parameters
Map<String, String> params = new HashMap<String, String>() {
{
put("tenantDomain", TENANT_DOMAIN);
put("tenantService", TENANT_SERVICE);
put("providerDomain", PROVIDER_DOMAIN);
put("privateKeyPath", PRIVATE_KEY_PATH);
}
};
String paramsStr = new String(Files.readAllBytes(Paths.get("./src/test/resources/authParams.json")));
auth = new AuthenticationAthenz();
auth.configure(params);

auth.configure(paramsStr);
// Set mock ztsClient which returns fixed token instead of fetching from ZTS server
Field field = auth.getClass().getDeclaredField("ztsClient");
field.setAccessible(true);
Expand Down Expand Up @@ -112,4 +109,58 @@ public void testGetAuthData() throws Exception {
}
assertEquals(count, 1);
}
}

@Test
public void testLoadPrivateKeyBase64() throws Exception {
try {
String paramsStr = new String(Files.readAllBytes(Paths.get("./src/test/resources/authParams.json")));

// load privatekey and encode it using base64
ObjectMapper jsonMapper = ObjectMapperFactory.create();
Map<String, String> authParamsMap = jsonMapper.readValue(paramsStr,
new TypeReference<HashMap<String, String>>() {
});
String privateKeyContents = new String(Files.readAllBytes(Paths.get(authParamsMap.get("privateKey"))));
authParamsMap.put("privateKey", "data:application/x-pem-file;base64,"
+ new String(Base64.getEncoder().encode(privateKeyContents.getBytes())));

AuthenticationAthenz authBase64 = new AuthenticationAthenz();
authBase64.configure(jsonMapper.writeValueAsString(authParamsMap));

PrivateKey privateKey = Crypto.loadPrivateKey(new File("./src/test/resources/tenant_private.pem"));
Field field = authBase64.getClass().getDeclaredField("privateKey");
field.setAccessible(true);
PrivateKey key = (PrivateKey) field.get(authBase64);
assertTrue(privateKey.equals(key));
} catch (Exception e) {
Assert.fail();
}
}

@Test
public void testLoadPrivateKeyUrlEncode() throws Exception {
try {
String paramsStr = new String(Files.readAllBytes(Paths.get("./src/test/resources/authParams.json")));

// load privatekey and encode it using url encoding
ObjectMapper jsonMapper = ObjectMapperFactory.create();
Map<String, String> authParamsMap = jsonMapper.readValue(paramsStr,
new TypeReference<HashMap<String, String>>() {
});
String privateKeyContents = new String(Files.readAllBytes(Paths.get(authParamsMap.get("privateKey"))));
authParamsMap.put("privateKey",
"data:application/x-pem-file," + new String(encode(privateKeyContents).replace("+", "%20")));

AuthenticationAthenz authEncode = new AuthenticationAthenz();
authEncode.configure(jsonMapper.writeValueAsString(authParamsMap));

PrivateKey privateKey = Crypto.loadPrivateKey(new File("./src/test/resources/tenant_private.pem"));
Field field = authEncode.getClass().getDeclaredField("privateKey");
field.setAccessible(true);
PrivateKey key = (PrivateKey) field.get(authEncode);
assertTrue(privateKey.equals(key));
} catch (Exception e) {
Assert.fail();
}
}
}
6 changes: 6 additions & 0 deletions pulsar-client-auth-athenz/src/test/resources/authParams.json
@@ -0,0 +1,6 @@
{
"tenantService": "test_service",
"privateKey": "./src/test/resources/tenant_private.pem",
"providerDomain": "test_provider",
"tenantDomain": "test_tenant"
}

0 comments on commit a5c123e

Please sign in to comment.