120 lines
4.3 KiB
C++
120 lines
4.3 KiB
C++
/*
|
|
* TokenSignStlTypes.cpp
|
|
*
|
|
* This source file is part of the FoundationDB open source project
|
|
*
|
|
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
|
|
*
|
|
* Licensed 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 "fdbrpc/TokenSign.h"
|
|
#include "fdbrpc/TokenSignStdTypes.h"
|
|
#include "flow/PKey.h"
|
|
#include "flow/MkCert.h"
|
|
#include <stdexcept>
|
|
|
|
namespace {
|
|
|
|
// converts std::optional<STANDARD_TYPE(S)> to Optional<FLOW_TYPE(T)>
|
|
template <class T, class S>
|
|
void convertAndAssign(Arena& arena, Optional<T>& to, const std::optional<S>& from) {
|
|
if (!from.has_value()) {
|
|
to.reset();
|
|
return;
|
|
}
|
|
if constexpr (std::is_same_v<S, std::vector<std::string>>) {
|
|
static_assert(std::is_same_v<T, VectorRef<StringRef>>,
|
|
"Source type std::vector<std::string> must convert to VectorRef<StringRef>");
|
|
const auto& value = from.value();
|
|
if (value.empty()) {
|
|
to = VectorRef<StringRef>();
|
|
} else {
|
|
// no need to deep copy string because we have the underlying memory for the duration of token signing.
|
|
auto buf = new (arena) StringRef[value.size()];
|
|
for (auto i = 0u; i < value.size(); i++) {
|
|
buf[i] = StringRef(value[i]);
|
|
}
|
|
to = VectorRef<StringRef>(buf, value.size());
|
|
}
|
|
} else if constexpr (std::is_same_v<S, std::vector<int64_t>>) {
|
|
static_assert(std::is_same_v<T, VectorRef<int64_t>>,
|
|
"Source type std::vector<int64_t> must convert to VectorRef<int64_t>");
|
|
const auto& value = from.value();
|
|
if (value.empty()) {
|
|
to = VectorRef<int64_t>();
|
|
} else {
|
|
auto buf = new (arena) int64_t[value.size()];
|
|
for (auto i = 0; i < value.size(); i++)
|
|
buf[i] = value[i];
|
|
to = VectorRef<int64_t>(buf, value.size());
|
|
}
|
|
} else if constexpr (std::is_same_v<S, std::string>) {
|
|
static_assert(std::is_same_v<T, StringRef>, "Source type std::string must convert to StringRef");
|
|
const auto& value = from.value();
|
|
// no need to deep copy string because we have the underlying memory for the duration of token signing.
|
|
to = StringRef(value);
|
|
} else {
|
|
static_assert(std::is_same_v<S, T>,
|
|
"Source types that aren't std::vector<std::string>, std::vector<int64_t>, or std::string must "
|
|
"have the same destination type");
|
|
static_assert(std::is_trivially_copy_assignable_v<S>,
|
|
"Source types that aren't std::vector<std::string> or std::string must not use heap memory");
|
|
to = from.value();
|
|
}
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
namespace authz::jwt::stdtypes {
|
|
|
|
std::string makeEcP256PrivateKeyPem() {
|
|
try {
|
|
PrivateKey pk = mkcert::makeEcP256();
|
|
auto tmpArena = Arena();
|
|
auto pem = pk.writePem(tmpArena);
|
|
return pem.toString();
|
|
} catch (Error& e) {
|
|
throw std::runtime_error(e.name());
|
|
}
|
|
}
|
|
|
|
std::string signToken(const TokenSpec& tokenSpec, const std::string& privateKeyPem) {
|
|
try {
|
|
auto arena = Arena();
|
|
auto privateKey = PrivateKey(PemEncoded{}, StringRef(privateKeyPem));
|
|
// translate TokenSpec (uses STL types) to TokenRef (uses Flow types)
|
|
auto t = authz::jwt::TokenRef{};
|
|
t.algorithm = tokenSpec.algorithm;
|
|
t.keyId = StringRef(tokenSpec.keyId);
|
|
convertAndAssign(arena, t.issuer, tokenSpec.issuer);
|
|
convertAndAssign(arena, t.subject, tokenSpec.subject);
|
|
convertAndAssign(arena, t.audience, tokenSpec.audience);
|
|
convertAndAssign(arena, t.issuedAtUnixTime, tokenSpec.issuedAtUnixTime);
|
|
convertAndAssign(arena, t.expiresAtUnixTime, tokenSpec.expiresAtUnixTime);
|
|
convertAndAssign(arena, t.notBeforeUnixTime, tokenSpec.notBeforeUnixTime);
|
|
convertAndAssign(arena, t.tokenId, tokenSpec.tokenId);
|
|
convertAndAssign(arena, t.tenants, tokenSpec.tenants);
|
|
return signToken(arena, t, privateKey).toString();
|
|
} catch (Error& e) {
|
|
if (e.code() == error_code_pkey_decode_error) {
|
|
// bad PEM
|
|
throw std::invalid_argument(e.name());
|
|
} else {
|
|
throw std::runtime_error(e.name());
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace authz::jwt::stdtypes
|