// Copyright 2021-2022 James Pace // // 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 #include #include #include #include #include #include // Util. std::tuple checkACL(const std::string &user, const YAML::Node &aclFile); std::vector getKey(const std::string &user, const YAML::Node &keyFile); // Class implementation. Authorizer::Authorizer(const std::string &keyFilePath, const std::string &aclFilePath) : _keyFile{YAML::LoadFile(keyFilePath)}, _aclFile{YAML::LoadFile(aclFilePath)} { } bool Authorizer::add(const std::string &token, const std::string &username) { // We should protect from this already. if (token.empty() or username.empty()) { return false; } const auto keys = getKey(username, _keyFile); // Do any of the keys validate the token? const bool validated = [token, username, keys]() { for (const auto key : keys) { std::cout << "Trying..." << std::endl; if (validate(token, username, key)) { return true; } } return false; }(); if (not validated) { std::cerr << "Not validated." << std::endl; return false; } // Check the ACL file. const auto [can_read, can_write] = checkACL(username, _aclFile); if (can_read) { _readList.add(username, std::chrono::system_clock::now()); } if (can_write) { _writeList.add(username, std::chrono::system_clock::now()); } return true; } bool Authorizer::can_read(const std::string &username) { return _readList.confirm(username); } bool Authorizer::can_write(const std::string &username) { return _writeList.confirm(username); } void Authorizer::logout(const std::string &username) { _writeList.remove(username); _readList.remove(username); _unknownList.remove(username); } void Authorizer::add_unknown(const std::string &username) { _unknownList.add(username, std::chrono::system_clock::now()); } bool Authorizer::is_unknown(const std::string &username) { return (username.empty() or _unknownList.confirm(username)); } // Util. std::tuple checkACL(const std::string &user, const YAML::Node &aclFile) { // TODO: Make sure default exists. YAML::Node userDict; if (aclFile[user]) { userDict = aclFile[user]; } else { userDict = aclFile["default"]; } bool can_read = false; bool can_write = false; if (userDict["can_read"] and userDict["can_read"].as()) { can_read = true; } if (userDict["can_write"] and userDict["can_write"].as()) { can_write = true; } return std::make_tuple(can_read, can_write); } std::vector getKey(const std::string &user, const YAML::Node &keyFile) { // Find this user's entry or the default one. YAML::Node userKey; if(keyFile[user]) { userKey = keyFile[user]; } else { // TODO: Make sure default exists. userKey = keyFile["default"]; } // Get the paths from the yaml file as std::filesystem::paths. std::vector paths; if(not userKey.IsSequence()) { paths.emplace_back(userKey.as()); } else { for(const auto key : userKey) { paths.emplace_back(key.as()); } } // Now convert to an array of optional keys. std::vector keys; for(const auto path : paths) { const auto key = read_key(std::filesystem::absolute(path).string()); if(key) { keys.emplace_back(key.value()); } } return keys; }