Skip to content

Commit

Permalink
Added privateKey field to cpp Athenz client plugin's authParams (apac…
Browse files Browse the repository at this point in the history
  • Loading branch information
hrsakai authored and merlimat committed Oct 7, 2017
1 parent d360b07 commit c65207e
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 19 deletions.
83 changes: 68 additions & 15 deletions pulsar-client-cpp/lib/auth/athenz/ZTSClient.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <json/value.h>
#include <json/reader.h>

#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/xpressive/xpressive.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
Expand All @@ -50,7 +51,7 @@ namespace pulsar {
const static int MIN_TOKEN_EXPIRATION_TIME_SEC = 900;
const static int MAX_HTTP_REDIRECTS = 20;
const static long long FETCH_EPSILON = 60; // if cache expires in 60 seconds, get it from ZTS
const static std::string requiredParams[] = {"tenantDomain", "tenantService", "providerDomain", "privateKeyPath", "ztsUrl"};
const static std::string requiredParams[] = {"tenantDomain", "tenantService", "providerDomain", "privateKey", "ztsUrl"};

std::map<std::string, RoleToken> ZTSClient::roleTokenCache_;

Expand All @@ -63,17 +64,18 @@ namespace pulsar {
LOG_ERROR(requiredParams[i] << " parameter is required");
}
}

if (!valid) {
LOG_ERROR("Some parameters are missing")
return;
}

// set required value
tenantDomain_ = params[requiredParams[0]];
tenantService_ = params[requiredParams[1]];
tenantDomain_ = params[requiredParams[0]];
tenantService_ = params[requiredParams[1]];
providerDomain_ = params[requiredParams[2]];
privateKeyPath_ = params[requiredParams[3]];
ztsUrl_ = params[requiredParams[4]];
privateKeyUri_ = parseUri(params[requiredParams[3]].c_str());
ztsUrl_ = params[requiredParams[4]];

// set optional value
keyId_ = params.find("keyId") == params.end() ? "0" : params["keyId"];
Expand Down Expand Up @@ -136,6 +138,22 @@ namespace pulsar {
return ret;
}

char* ZTSClient::base64Decode(const char* input) {
BIO *bio, *b64;
size_t length = strlen(input);
char *result = (char*)malloc(length);

bio = BIO_new_mem_buf(input, -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);

BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
BIO_read(bio, result, length);
BIO_free_all(bio);

return result;
}

const std::string ZTSClient::getPrincipalToken() const {
// construct unsigned principal token
std::string unsignedTokenString = "v=S1";
Expand All @@ -162,21 +180,43 @@ namespace pulsar {
FILE *fp;
RSA *privateKey;

fp = fopen(privateKeyPath_.c_str(), "r");
if (fp == NULL) {
LOG_ERROR("Failed to open athenz private key file: " << privateKeyPath_);
return "";
}
if (privateKeyUri_.scheme == "data") {
if(privateKeyUri_.mediaTypeAndEncodingType != "application/x-pem-file;base64") {
LOG_ERROR("Unsupported mediaType or encodingType: " << privateKeyUri_.mediaTypeAndEncodingType);
return "";
}
char* decodeStr = base64Decode(privateKeyUri_.data.c_str());

privateKey = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
if (privateKey == NULL) {
LOG_ERROR("Failed to read private key: " << privateKeyPath_);
BIO *bio = BIO_new_mem_buf( (void*)decodeStr, -1 );
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
if (bio == NULL) {
LOG_ERROR("Failed to create key BIO");
return "";
}
privateKey = PEM_read_bio_RSAPrivateKey( bio, NULL, NULL, NULL ) ;
BIO_free(bio);
if (privateKey == NULL) {
LOG_ERROR("Failed to load privateKey");
return "";
}
} else if (privateKeyUri_.scheme == "file") {
fp = fopen(privateKeyUri_.path.c_str(), "r");
if (fp == NULL) {
LOG_ERROR("Failed to open athenz private key file: " << privateKeyUri_.path);
return "";
}

privateKey = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
fclose(fp);
if (privateKey == NULL) {
LOG_ERROR("Failed to read private key: " << privateKeyUri_.path);
return "";
}
} else {
LOG_ERROR("Unsupported URI Scheme: " << privateKeyUri_.scheme);
return "";
}

fclose(fp);

SHA256( (unsigned char *)unsignedToken, unsignedTokenString.length(), hash );
RSA_sign(NID_sha256, hash, SHA256_DIGEST_LENGTH, signature, &siglen, privateKey);

Expand Down Expand Up @@ -285,4 +325,17 @@ namespace pulsar {
return roleHeader_;
}

PrivateKeyUri ZTSClient::parseUri(const char* uri) {
PrivateKeyUri uriSt;
// scheme mediatype[;base64] path file
static const boost::regex expression("^(\?:([^:/\?#]+):)(\?:([;/\\-\\w]*),)\?(/\?(\?:[^\?#/]*/)*)\?([^\?#]*)");
boost::cmatch groups;
if (boost::regex_match(uri, groups, expression)) {
uriSt.scheme = groups.str(1);
uriSt.mediaTypeAndEncodingType = groups.str(2);
uriSt.data = groups.str(4);
uriSt.path = groups.str(3) + groups.str(4);
}
return uriSt;
}
}
14 changes: 12 additions & 2 deletions pulsar-client-cpp/lib/auth/athenz/ZTSClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ namespace pulsar {
long long expiryTime;
};

struct PrivateKeyUri {
std::string scheme;
std::string mediaTypeAndEncodingType;
std::string data;
std::string path;
};

class ZTSClient {
public:
ZTSClient(std::map<std::string, std::string>& params);
Expand All @@ -38,7 +45,7 @@ namespace pulsar {
std::string tenantDomain_;
std::string tenantService_;
std::string providerDomain_;
std::string privateKeyPath_;
PrivateKeyUri privateKeyUri_;
std::string ztsUrl_;
std::string keyId_;
std::string principalHeader_;
Expand All @@ -47,7 +54,10 @@ namespace pulsar {
static std::map<std::string, RoleToken> roleTokenCache_;
static std::string getSalt();
static std::string ybase64Encode(const unsigned char *input, int length);
static char* base64Decode(const char *input);
const std::string getPrincipalToken() const;
};
static PrivateKeyUri parseUri(const char* uri);

friend class ZTSClientWrapper;
};
}
2 changes: 1 addition & 1 deletion pulsar-client-cpp/tests/AuthPluginTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ TEST(AuthPluginTest, testAthenz) {
params["tenantDomain"] = "pulsar.test.tenant";
params["tenantService"] = "service";
params["providerDomain"] = "pulsar.test.provider";
params["privateKeyPath"] = "../../pulsar-broker/src/test/resources/authentication/tls/client-key.pem";
params["privateKey"] = "file:../../pulsar-broker/src/test/resources/authentication/tls/client-key.pem";
params["ztsUrl"] = "http://localhost:9999";
pulsar::AuthenticationPtr auth = pulsar::AuthFactory::create("../lib/auth/libauthathenz.so", params);
ASSERT_EQ(auth->getAuthMethodName(), "athenz");
Expand Down
2 changes: 1 addition & 1 deletion pulsar-client-cpp/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ add_executable(main ${TEST_SOURCES})

target_include_directories(main PRIVATE ${CMAKE_SOURCE_DIR}/lib)

target_link_libraries(main ${CLIENT_LIBS} ${GTEST_LIBRARY_PATH})
target_link_libraries(main ${CLIENT_LIBS} ${GTEST_LIBRARY_PATH} ztsClient)
71 changes: 71 additions & 0 deletions pulsar-client-cpp/tests/ZTSClientTest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* 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.
*/
#include "lib/auth/athenz/ZTSClient.h"
#include <gtest/gtest.h>

using namespace pulsar;

namespace pulsar{

class ZTSClientWrapper {
public:
static PrivateKeyUri parseUri(const char* uri) {
return ZTSClient::parseUri(uri);
}
};
}

TEST(ZTSClientTest, testZTSClient) {

{
PrivateKeyUri uri = ZTSClientWrapper::parseUri("file:/path/to/private.key");
ASSERT_EQ("file", uri.scheme);
ASSERT_EQ("/path/to/private.key", uri.path);
}

{
PrivateKeyUri uri = ZTSClientWrapper::parseUri("file:///path/to/private.key");
ASSERT_EQ("file", uri.scheme);
ASSERT_EQ("///path/to/private.key", uri.path);
}

{
PrivateKeyUri uri = ZTSClientWrapper::parseUri("data:application/x-pem-file;base64,SGVsbG8gV29ybGQK");
ASSERT_EQ("data", uri.scheme);
ASSERT_EQ("application/x-pem-file;base64", uri.mediaTypeAndEncodingType);
ASSERT_EQ("SGVsbG8gV29ybGQK", uri.data);
}

{
PrivateKeyUri uri = ZTSClientWrapper::parseUri("");
ASSERT_EQ("", uri.scheme);
ASSERT_EQ("", uri.path);
ASSERT_EQ("", uri.mediaTypeAndEncodingType);
ASSERT_EQ("", uri.data);
}

{
PrivateKeyUri uri = ZTSClientWrapper::parseUri("/path/to/private.key");
ASSERT_EQ("", uri.scheme);
ASSERT_EQ("", uri.path);
ASSERT_EQ("", uri.mediaTypeAndEncodingType);
ASSERT_EQ("", uri.data);
}

}

0 comments on commit c65207e

Please sign in to comment.