8000 Bug fix/micro optimize auth by jsteemann · Pull Request #10316 · arangodb/arangodb · GitHub
[go: up one dir, main page]

Skip to content

Bug fix/micro optimize auth #10316

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 35 additions & 34 deletions arangod/Auth/TokenCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,18 @@
#include <velocypack/Builder.h>
#include <velocypack/Collection.h>
#include <velocypack/Iterator.h>
#include <velocypack/StringRef.h>
#include <velocypack/velocypack-aliases.h>

using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::velocypack;
using namespace arangodb::rest;

namespace {
velocypack::StringRef const hs256String("HS256");
velocypack::StringRef const jwtString("JWT");
}

auth::TokenCache::TokenCache(auth::UserManager* um, double timeout)
: _userManager(um),
Expand Down Expand Up @@ -153,7 +159,7 @@ auth::TokenCache::Entry auth::TokenCache::checkAuthenticationBasic(std::string c
expiry += TRI_microtime();
}

auth::TokenCache::Entry entry(username, authorized, expiry);
auth::TokenCache::Entry entry(std::move(username), authorized, expiry);
{
WRITE_LOCKER(guard, _basicLock);
if (authorized) {
Expand Down Expand Up @@ -232,7 +238,7 @@ auth::TokenCache::Entry auth::TokenCache::checkAuthenticationJWT(std::string con
}

std::shared_ptr<VPackBuilder> auth::TokenCache::parseJson(std::string const& str,
std::string const& hint) {
char const* hint) {
std::shared_ptr<VPackBuilder> result;
VPackParser parser;
try {
Expand All @@ -255,7 +261,7 @@ std::shared_ptr<VPackBuilder> auth::TokenCache::parseJson(std::string const& str
bool auth::TokenCache::validateJwtHeader(std::string const& header) {
std::shared_ptr<VPackBuilder> headerBuilder =
parseJson(StringUtils::decodeBase64U(header), "jwt header");
if (headerBuilder.get() == nullptr) {
if (headerBuilder == nullptr) {
return false;
}

Expand All @@ -267,20 +273,15 @@ bool auth::TokenCache::validateJwtHeader(std::string const& header) {
VPackSlice const algSlice = headerSlice.get("alg");
VPackSlice const typSlice = headerSlice.get("typ");

if (!algSlice.isString()) {
return false;
}

if (!typSlice.isString()) {
if (!algSlice.isString() || !typSlice.isString()) {
return false;
}

if (algSlice.copyString() != "HS256") {
if (!algSlice.isEqualString(::hs256String)) {
return false;
}

std::string typ = typSlice.copyString();
if (typ != "JWT") {

if (!typSlice.isEqualString(::jwtString)) {
return false;
}

Expand All @@ -290,7 +291,7 @@ bool auth::TokenCache::validateJwtHeader(std::string const& header) {
auth::TokenCache::Entry auth::TokenCache::validateJwtBody(std::string const& body) {
std::shared_ptr<VPackBuilder> bodyBuilder =
parseJson(StringUtils::decodeBase64U(body), "jwt body");
if (bodyBuilder.get() == nullptr) {
if (bodyBuilder == nullptr) {
LOG_TOPIC("99524", TRACE, Logger::AUTHENTICATION) << "invalid JWT body";
return auth::TokenCache::Entry::Unauthenticated();
}
Expand All @@ -307,14 +308,14 @@ auth::TokenCache::Entry auth::TokenCache::validateJwtBody(std::string const& bod
return auth::TokenCache::Entry::Unauthenticated();
}

if (issSlice.copyString() != "arangodb") {
if (!issSlice.isEqualString(velocypack::StringRef("arangodb"))) {
LOG_TOPIC("2547e", TRACE, arangodb::Logger::AUTHENTICATION) << "invalid iss value";
return auth::TokenCache::Entry::Unauthenticated();
}

auth::TokenCache::Entry authResult("", false, 0);
if (bodySlice.hasKey("preferred_username")) {
VPackSlice const usernameSlice = bodySlice.get("preferred_username");
VPackSlice const usernameSlice = bodySlice.get("preferred_username");
if (!usernameSlice.isNone()) {
if (!usernameSlice.isString() || usernameSlice.getStringLength() == 0) {
return auth::TokenCache::Entry::Unauthenticated();
}
Expand All @@ -330,8 +331,8 @@ auth::TokenCache::Entry auth::TokenCache::validateJwtBody(std::string const& bod
return auth::TokenCache::Entry::Unauthenticated();
}

if (bodySlice.hasKey("allowed_paths")) {
VPackSlice const paths = bodySlice.get("allowed_paths");
VPackSlice const paths = bodySlice.get("allowed_paths");
if (!paths.isNone()) {
if (!paths.isArray()) {
LOG_TOPIC("89898", TRACE, arangodb::Logger::AUTHENTICATION)
<< "allowed_paths must be an array";
Expand All @@ -353,8 +354,8 @@ auth::TokenCache::Entry auth::TokenCache::validateJwtBody(std::string const& bod
}

// mop: optional exp (cluster currently uses non expiring jwts)
if (bodySlice.hasKey("exp")) {
VPackSlice const expSlice = bodySlice.get("exp");
VPackSlice const expSlice = bodySlice.get("exp");
if (!expSlice.isNone()) {
if (!expSlice.isNumber()) {
8000 LOG_TOPIC("74735", TRACE, Logger::AUTHENTICATION) << "invalid exp value";
return authResult; // unauthenticated
Expand Down Expand Up @@ -417,22 +418,22 @@ std::string auth::TokenCache::generateJwt(VPackSlice const& payload) const {
bool hasIat = payload.hasKey("iat");
if (hasIss && hasIat) {
return generateRawJwt(payload);
} else {
VPackBuilder bodyBuilder;
{
VPackObjectBuilder p(&bodyBuilder);
if (!hasIss) {
bodyBuilder.add("iss", VPackValue("arangodb"));
}
if (!hasIat) {
bodyBuilder.add("iat", VPackValue(TRI_microtime() / 1000));
}
for (auto const& obj : VPackObjectIterator(payload)) {
bodyBuilder.add(obj.key.copyString(), obj.value);
}
}

VPackBuilder bodyBuilder;
{
VPackObjectBuilder p(&bodyBuilder);
if (!hasIss) {
bodyBuilder.add("iss", VPackValue("arangodb"));
}
if (!hasIat) {
bodyBuilder.add("iat", VPackValue(TRI_microtime() / 1000));
}
for (auto const& obj : VPackObjectIterator(payload)) {
bodyBuilder.add(obj.key.copyString(), obj.value);
}
return generateRawJwt(bodyBuilder.slice());
}
return generateRawJwt(bodyBuilder.slice());
}

/// generate a JWT token for internal cluster communication
Expand Down
7FE0 2 changes: 1 addition & 1 deletion arangod/Auth/TokenCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class TokenCache {
TokenCache::Entry validateJwtBody(std::string const&);
bool validateJwtHMAC256Signature(std::string const&, std::string const&);

std::shared_ptr<velocypack::Builder> parseJson(std::string const&, std::string const&);
std::shared_ptr<velocypack::Builder> parseJson(std::string const& str, char const* hint);

/// generate new _jwtToken
void generateJwtToken();
Expand Down
0