Skip to content
Snippets Groups Projects
Verified Commit 8b43244d authored by Timm Fitschen's avatar Timm Fitschen
Browse files

WIP: acm

parent 429ddd35
No related branches found
No related tags found
2 merge requests!42Release 0.2.0,!40F dot in username
Showing with 844 additions and 70 deletions
......@@ -81,6 +81,7 @@ add_subdirectory(doc)
set(PROTO_FILES
${PROJECT_SOURCE_DIR}/proto/proto/caosdb/info/v1/main.proto
${PROJECT_SOURCE_DIR}/proto/proto/caosdb/entity/v1/main.proto
${PROJECT_SOURCE_DIR}/proto/proto/caosdb/acm/v1alpha1/main.proto
)
set(PROTO_PATH ${PROJECT_SOURCE_DIR}/proto/proto)
......@@ -173,6 +174,7 @@ target_link_libraries(caosdb
target_include_directories(caosdb PUBLIC
$<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
$<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:include>
)
target_include_directories(caosdb SYSTEM PUBLIC
......
......@@ -20,6 +20,7 @@
# add all header files to this list
set(libcaosdb_INCL
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/acm/role.h
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/authentication.h
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/certificate_provider.h
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/configuration.h
......
/*
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale.com>
* Copyright (C) 2022 IndiScale GmbH <info@indiscale.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* @brief PermissionRules grant or deny permissions to roles.
*
* @file caosdb/acm/permission_rule.h
* @author Timm Fitchen
* @date 2022-02-11
*/
#ifndef CAOSDB_ACM_PERMISSION_RULE_H
#define CAOSDB_ACM_PERMISSION_RULE_H
#include <unordered_set> // for unordered_set
#include <string> // for string
namespace caosdb::acm {
class PermissionRuleImpl;
class PermissionRule {
public:
PermissionRule(std::string permission, bool isGrant, bool isPriority);
explicit PermissionRule(PermissionRuleImpl *wrapped);
PermissionRule(const PermissionRule &rule);
auto operator=(const PermissionRule &rule) -> PermissionRule &;
~PermissionRule();
auto ToString() const -> std::string;
[[nodiscard]] auto IsGrant() const -> const bool;
auto SetGrant(bool isGrant) -> void;
[[nodiscard]] auto IsPriority() const -> const bool;
auto SetPriority(bool isPriority) -> void;
[[nodiscard]] auto GetPermission() const -> const std::string &;
auto operator==(const PermissionRule &other) const -> bool;
private:
PermissionRuleImpl *impl;
};
struct HashPermissionRule {
size_t operator()(const PermissionRule& rule) const {
return std::hash<std::string>()(rule.GetPermission());
}
};
using PermissionRules = std::unordered_set<PermissionRule, HashPermissionRule>;
} // namespace caosdb::acm
#endif
/*
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale.com>
* Copyright (C) 2022 IndiScale GmbH <info@indiscale.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* @brief Roles, together with users, and permissions are a fundamental concept
* of the access controll management of CaosDB.
*
* @file caosdb/acm/role.h
* @author Timm Fitchen
* @date 2022-02-11
*/
#ifndef CAOSDB_ACM_ROLES_H
#define CAOSDB_ACM_ROLES_H
#include "caosdb/acm/permission_rule.h" // for PermissionRule
#include <string> // for string
#include <vector> // for vector
namespace caosdb::connection {
class Connection;
}
namespace caosdb::acm {
class RoleImpl;
class Role {
public:
explicit Role(std::string name);
explicit Role(RoleImpl *wrapped);
Role(std::string name, std::string description);
Role(const Role &role);
auto operator=(const Role &role) -> Role &;
~Role();
auto ToString() const -> std::string;
[[nodiscard]] auto GetName() const -> const std::string &;
auto SetName(std::string name) -> void;
[[nodiscard]] auto GetDescription() const -> const std::string &;
auto SetDescription(std::string description) -> void;
// TODO(tf) declare and implement:
[[nodiscard]] auto GetPermissionRules() const -> const PermissionRules &;
// auto SetPermissionRules(PermissionRules rules) -> void;
// auto ClearPermissionRules() -> void;
auto Grant(std::string permission, bool priority) -> void;
// auto Deny(std::string permission, bool priority) -> void;
auto RevokeGrant(std::string permission, bool priority) -> void;
// auto RevokeDenial(std::string permission, bool priority) -> void;
friend class caosdb::connection::Connection;
private:
RoleImpl *wrapped;
};
} // namespace caosdb::acm
#endif
......@@ -27,6 +27,8 @@
* @date 2021-05-18
* @brief Configuration and setup of the connection.
*/
#include "caosdb/acm/role.h" // for Role
#include "caosdb/acm/v1alpha1/main.grpc.pb.h" // for AccessControlMan...
#include "caosdb/authentication.h" // for Authenticator
#include "caosdb/configuration.h" // for ConnectionConfigura...
#include "caosdb/entity/v1/main.grpc.pb.h" // for EntityTransactionSe...
......@@ -39,8 +41,11 @@
#include <map> // for map
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string, basic_string
#include <vector> // for vector
namespace caosdb::connection {
using caosdb::acm::Role;
using caosdb::acm::v1alpha1::AccessControlManagementService;
using caosdb::authentication::Authenticator;
using caosdb::configuration::ConnectionConfiguration;
using caosdb::entity::v1::EntityTransactionService;
......@@ -89,8 +94,22 @@ public:
return this->version_info.get();
};
/**
* Create a new transaction object which uses this connection and return it.
*/
[[nodiscard]] auto CreateTransaction() const -> std::unique_ptr<Transaction>;
/**
* List all known roles.
*/
[[nodiscard]] auto ListRoles() const -> std::vector<Role>;
[[nodiscard]] auto RetrieveSingleRole(std::string name) const -> Role;
auto CreateSingleRole(const Role &role) const -> void;
auto DeleteSingleRole(std::string name) const -> void;
private:
/// GRPC-Channel (HTTP/2 Connection plus Authentication). We use a shared
/// pointer because Transaction instances also own the channel.
......@@ -107,6 +126,10 @@ private:
/// Service for file transmission (download and upload). We use a shared
/// pointer because Transaction instances also own this service stub.
std::shared_ptr<FileTransmissionService::Stub> file_transmission_service;
/// Service for Access Controll Management (Role, Useraccounts, Permissions).
/// We use a unique pointer because only this connection owns and uses this
/// service.
std::unique_ptr<AccessControlManagementService::Stub> access_controll_management_service;
};
/**
......
......@@ -21,6 +21,9 @@
# add all source files to this list
set(libcaosdb_SRC
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/acm/role.cpp
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/acm/role_impl.h
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/acm/permission_rule.cpp
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/authentication.cpp
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/entity.cpp
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/logging.cpp
......
/*
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale.com>
* Copyright (C) 2022 IndiScale GmbH <info@indiscale.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "caosdb/acm/permission_rule.h"
#include "caosdb/acm/permission_rule_impl.h" // for PermissionRuleImpl
#include "caosdb/acm/v1alpha1/main.pb.h" // for ListPermissionRulesRequest
#include "caosdb/protobuf_helper.h" // for ProtoMessageWrapper
#include <utility> // for move
namespace caosdb::acm {
using caosdb::utility::ScalarProtoMessageWrapper;
using ProtoPermissionRule = caosdb::acm::v1alpha1::PermissionRule;
PermissionRuleImpl::PermissionRuleImpl() : ScalarProtoMessageWrapper<ProtoPermissionRule>() {}
PermissionRuleImpl::PermissionRuleImpl(ProtoPermissionRule *rule)
: ScalarProtoMessageWrapper<ProtoPermissionRule>(rule) {}
PermissionRuleImpl::PermissionRuleImpl(std::string permission, bool isGrant, bool isPriority)
: PermissionRuleImpl() {
this->wrapped->set_permission(std::move(permission));
this->wrapped->set_grant(isGrant);
this->wrapped->set_priority(isPriority);
}
PermissionRule::PermissionRule(std::string permission, bool isGrant, bool isPriority)
: impl(new PermissionRuleImpl(std::move(permission), isGrant, isPriority)) {}
PermissionRule::PermissionRule(const PermissionRule &rule) : impl(new PermissionRuleImpl()) {
this->impl->wrapped->CopyFrom(*(rule.impl->wrapped));
}
auto PermissionRule::operator=(const PermissionRule &rule) -> PermissionRule & {
this->impl->wrapped->CopyFrom(*(rule.impl->wrapped));
return *this;
}
PermissionRule::~PermissionRule() { delete this->impl; }
auto PermissionRule::ToString() const -> std::string { return this->impl->ToString(); }
[[nodiscard]] auto PermissionRule::IsGrant() const -> const bool {
return this->impl->wrapped->grant();
}
auto PermissionRule::SetGrant(bool isGrant) -> void { this->impl->wrapped->set_grant(isGrant); }
[[nodiscard]] auto PermissionRule::IsPriority() const -> const bool {
return this->impl->wrapped->priority();
}
auto PermissionRule::SetPriority(bool isPriority) -> void {
this->impl->wrapped->set_priority(isPriority);
}
auto PermissionRule::operator==(const PermissionRule &other) const -> bool {
return this->GetPermission() == other.GetPermission();
}
auto PermissionRule::GetPermission() const -> const std::string & {
return this->impl->wrapped->permission();
}
} // namespace caosdb::acm
/*
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale.com>
* Copyright (C) 2022 IndiScale GmbH <info@indiscale.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef CAOSDB_ACM_PERMISSION_RULE_IMPL_H
#define CAOSDB_ACM_PERMISSION_RULE_IMPL_H
#include "caosdb/acm/role.h"
#include "caosdb/acm/v1alpha1/main.pb.h" // for ListRolesRequest
#include "caosdb/protobuf_helper.h" // for ProtoMessageWrapper
#include <utility> // for move
namespace caosdb::acm {
using caosdb::utility::ScalarProtoMessageWrapper;
using ProtoPermissionRule = caosdb::acm::v1alpha1::PermissionRule;
/**
* PermissionRuleImpl class is designed to hide the implementation which makes direct use
* of the protobuf objects underneath from the clients of the caosdb library.
*/
class PermissionRuleImpl : public ScalarProtoMessageWrapper<ProtoPermissionRule> {
public:
/**
* Constructor. Instanciate a role from the server's responces.
*/
PermissionRuleImpl(ProtoPermissionRule *rule);
PermissionRuleImpl();
PermissionRuleImpl(std::string permission, bool isGrant, bool isPriority);
friend class PermissionRule;
};
} // namespace caosdb::acm
#endif
/*
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale.com>
* Copyright (C) 2022 IndiScale GmbH <info@indiscale.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "caosdb/acm/role.h"
#include "caosdb/acm/permission_rule.h" // for PermissionRule
#include "caosdb/acm/role_impl.h" // for RoleImpl
#include "caosdb/acm/v1alpha1/main.pb.h" // for ListRolesRequest
#include "caosdb/protobuf_helper.h" // for ProtoMessageWrapper
#include <utility> // for move
#include <vector> // for vector
namespace caosdb::acm {
using caosdb::utility::ScalarProtoMessageWrapper;
using ProtoRole = caosdb::acm::v1alpha1::Role;
using ProtoRolePermissions = caosdb::acm::v1alpha1::RolePermissions;
using ProtoRoleCapabilities = caosdb::acm::v1alpha1::RoleCapabilities;
using ProtoListRoleItem = caosdb::acm::v1alpha1::ListRoleItem;
RoleImpl::RoleImpl(std::string name, std::string description)
: ScalarProtoMessageWrapper<ProtoRole>() {
if (!name.empty()) {
this->wrapped->set_name(name);
}
if (!description.empty()) {
this->wrapped->set_description(description);
}
}
RoleImpl::RoleImpl(ProtoRole *role) : ScalarProtoMessageWrapper<ProtoRole>(role) {}
RoleImpl::RoleImpl(ProtoListRoleItem &role_item)
: ScalarProtoMessageWrapper<ProtoRole>(role_item.release_role()) {}
RoleImpl::RoleImpl(std::string name) : RoleImpl(std::move(name), "") {}
Role::Role(RoleImpl *wrapped) : wrapped(std::move(wrapped)) {}
Role::Role(std::string name, std::string description)
: wrapped(new RoleImpl(std::move(name), std::move(description))) {}
Role::Role(std::string name) : Role(std::move(name), {""}) {}
Role::Role(const Role &role) : Role(role.GetName(), role.GetDescription()) {}
auto Role::operator=(const Role &role) -> Role & {
this->wrapped->wrapped->CopyFrom(*(role.wrapped->wrapped));
return *this;
}
Role::~Role() { delete this->wrapped; }
auto Role::GetName() const -> const std::string & { return this->wrapped->wrapped->name(); }
auto Role::SetName(std::string name) -> void {
if (!name.empty()) {
this->wrapped->wrapped->set_name(std::move(name));
} else {
this->wrapped->wrapped->clear_name();
}
}
auto Role::GetDescription() const -> const std::string & {
return this->wrapped->wrapped->description();
}
auto Role::SetDescription(std::string description) -> void {
if (!description.empty()) {
this->wrapped->wrapped->set_description(std::move(description));
} else {
this->wrapped->wrapped->clear_description();
}
}
auto Role::ToString() const -> std::string { return this->wrapped->ToString(); }
[[nodiscard]] auto Role::GetPermissionRules() const -> const PermissionRules & {
return this->wrapped->rules;
}
auto Role::Grant(std::string permission, bool isPriority) -> void {
this->wrapped->rules.emplace(std::move(permission), true, isPriority);
}
auto Role::RevokeGrant(std::string permission, bool isPriority) -> void {
auto rule = this->wrapped->rules.begin();
while (rule != this->wrapped->rules.end()) {
if (rule->IsGrant() && rule->IsPriority() == isPriority &&
rule->GetPermission() == permission) {
this->wrapped->rules.erase(rule);
return;
} else {
rule++;
}
}
}
} // namespace caosdb::acm
/*
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale.com>
* Copyright (C) 2022 IndiScale GmbH <info@indiscale.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "caosdb/acm/role.h"
#include "caosdb/acm/v1alpha1/main.pb.h" // for ListRolesRequest
#include "caosdb/protobuf_helper.h" // for ProtoMessageWrapper
#include <utility> // for move
namespace caosdb::acm {
using caosdb::utility::ScalarProtoMessageWrapper;
using ProtoRole = caosdb::acm::v1alpha1::Role;
using ProtoRolePermissions = caosdb::acm::v1alpha1::RolePermissions;
using ProtoRoleCapabilities = caosdb::acm::v1alpha1::RoleCapabilities;
using ProtoListRoleItem = caosdb::acm::v1alpha1::ListRoleItem;
/**
* RoleImpl class is designed to hide the implementation which makes direct use
* of the protobuf objects underneath from the clients of the caosdb library.
*/
class RoleImpl : public ScalarProtoMessageWrapper<ProtoRole> {
public:
/**
* Constructor. Instanciate a role with the given name.
*/
explicit RoleImpl(std::string name);
/**
* Constructor. Instanciate a role with the given name and description.
*/
RoleImpl(std::string name, std::string description);
/**
* Constructor. Instanciate a role from the server's responces.
*/
RoleImpl(ProtoRole *role);
/**
* Constructor. Instanciate a role from a listRoles RPC.
*/
RoleImpl(ProtoListRoleItem &role);
friend class Role;
friend class caosdb::connection::Connection;
private:
PermissionRules rules;
};
} // namespace caosdb::acm
......@@ -20,6 +20,9 @@
*
*/
#include "caosdb/connection.h"
#include "caosdb/acm/role_impl.h" // for RoleImpl
#include "caosdb/acm/v1alpha1/main.grpc.pb.h" // for AccessControlMan...
#include "caosdb/acm/v1alpha1/main.pb.h" // for ListRolesRequest
#include "caosdb/configuration.h" // for ConnectionConfigur...
#include "caosdb/exceptions.h" // for ConfigurationError
#include "caosdb/info.h" // for VersionInfo
......@@ -27,13 +30,23 @@
#include "caosdb/info/v1/main.pb.h" // for GetVersionInfoRequest
#include "caosdb/transaction.h" // for Transaction
#include "caosdb/transaction_status.h" // for TransactionStatus
#include "grpcpp/impl/codegen/status_code_enum.h" // for StatusCode, UNAUTH...
#include <grpcpp/create_channel.h> // for CreateChannel
#include <grpcpp/impl/codegen/client_context.h> // for ClientContext
#include <grpcpp/impl/codegen/status.h> // for Status
#include <grpcpp/impl/codegen/status_code_enum.h> // for StatusCode, UNAUTH...
#include <string> // for string, operator+
namespace caosdb::connection {
using caosdb::acm::RoleImpl;
using caosdb::acm::v1alpha1::AccessControlManagementService;
using caosdb::acm::v1alpha1::CreateSingleRoleRequest;
using caosdb::acm::v1alpha1::CreateSingleRoleResponse;
using caosdb::acm::v1alpha1::DeleteSingleRoleRequest;
using caosdb::acm::v1alpha1::DeleteSingleRoleResponse;
using caosdb::acm::v1alpha1::ListRolesRequest;
using caosdb::acm::v1alpha1::ListRolesResponse;
using caosdb::acm::v1alpha1::RetrieveSingleRoleRequest;
using caosdb::acm::v1alpha1::RetrieveSingleRoleResponse;
using caosdb::configuration::ConfigurationManager;
using caosdb::configuration::ConnectionConfiguration;
using caosdb::entity::v1::EntityTransactionService;
......@@ -53,6 +66,8 @@ Connection::Connection(const ConnectionConfiguration &configuration) {
this->entity_transaction_service =
std::make_shared<EntityTransactionService::Stub>(this->channel);
this->file_transmission_service = std::make_shared<FileTransmissionService::Stub>(this->channel);
this->access_controll_management_service =
std::make_unique<AccessControlManagementService::Stub>(this->channel);
}
auto Connection::RetrieveVersionInfoNoExceptions() const noexcept -> TransactionStatus {
......@@ -97,6 +112,121 @@ auto Connection::RetrieveVersionInfo() const -> const VersionInfo & {
return std::make_unique<Transaction>(entity_service, file_service);
}
[[nodiscard]] auto Connection::RetrieveSingleRole(std::string name) const -> Role {
RetrieveSingleRoleRequest request;
request.set_name(name);
RetrieveSingleRoleResponse response;
grpc::ClientContext context;
const grpc::Status grpc_status =
this->access_controll_management_service->RetrieveSingleRole(&context, request, &response);
auto status = TransactionStatus::SUCCESS();
if (!grpc_status.ok()) {
switch (grpc_status.error_code()) {
case grpc::StatusCode::UNAUTHENTICATED:
status = TransactionStatus::AUTHENTICATION_ERROR(grpc_status.error_message());
break;
case grpc::StatusCode::UNAVAILABLE:
status = TransactionStatus::CONNECTION_ERROR();
break;
default:
auto error_message = grpc_status.error_message();
status = TransactionStatus::RPC_ERROR(std::to_string(grpc_status.error_code()) + " - " +
error_message);
}
}
status.ThrowExceptionIfError();
auto *role = response.release_role();
return Role(new RoleImpl(role));
}
auto Connection::DeleteSingleRole(std::string name) const -> void {
DeleteSingleRoleRequest request;
request.set_name(name);
DeleteSingleRoleResponse response;
grpc::ClientContext context;
const grpc::Status grpc_status =
this->access_controll_management_service->DeleteSingleRole(&context, request, &response);
auto status = TransactionStatus::SUCCESS();
std::vector<Role> result;
if (!grpc_status.ok()) {
switch (grpc_status.error_code()) {
case grpc::StatusCode::UNAUTHENTICATED:
status = TransactionStatus::AUTHENTICATION_ERROR(grpc_status.error_message());
break;
case grpc::StatusCode::UNAVAILABLE:
status = TransactionStatus::CONNECTION_ERROR();
break;
default:
auto error_message = grpc_status.error_message();
status = TransactionStatus::RPC_ERROR(std::to_string(grpc_status.error_code()) + " - " +
error_message);
}
}
status.ThrowExceptionIfError();
}
auto Connection::CreateSingleRole(const Role &role) const -> void {
CreateSingleRoleRequest request;
request.set_allocated_role(role.wrapped->wrapped);
CreateSingleRoleResponse response;
grpc::ClientContext context;
const grpc::Status grpc_status =
this->access_controll_management_service->CreateSingleRole(&context, request, &response);
auto status = TransactionStatus::SUCCESS();
std::vector<Role> result;
if (!grpc_status.ok()) {
switch (grpc_status.error_code()) {
case grpc::StatusCode::UNAUTHENTICATED:
status = TransactionStatus::AUTHENTICATION_ERROR(grpc_status.error_message());
break;
case grpc::StatusCode::UNAVAILABLE:
status = TransactionStatus::CONNECTION_ERROR();
break;
default:
auto error_message = grpc_status.error_message();
status = TransactionStatus::RPC_ERROR(std::to_string(grpc_status.error_code()) + " - " +
error_message);
}
}
status.ThrowExceptionIfError();
}
[[nodiscard]] auto Connection::ListRoles() const -> std::vector<Role> {
const ListRolesRequest request;
ListRolesResponse response;
grpc::ClientContext context;
const grpc::Status grpc_status =
this->access_controll_management_service->ListRoles(&context, request, &response);
auto status = TransactionStatus::SUCCESS();
std::vector<Role> result;
if (!grpc_status.ok()) {
switch (grpc_status.error_code()) {
case grpc::StatusCode::UNAUTHENTICATED:
status = TransactionStatus::AUTHENTICATION_ERROR(grpc_status.error_message());
break;
case grpc::StatusCode::UNAVAILABLE:
status = TransactionStatus::CONNECTION_ERROR();
break;
default:
auto error_message = grpc_status.error_message();
status = TransactionStatus::RPC_ERROR(std::to_string(grpc_status.error_code()) + " - " +
error_message);
}
}
status.ThrowExceptionIfError();
auto *roles = response.mutable_roles();
for (auto &role_item : *roles) {
auto *implementation = new RoleImpl(role_item);
result.emplace_back(implementation);
}
return result;
}
auto ConnectionManager::mHasConnection(const std::string &name) const -> bool {
auto it = connections.find(name);
return it != connections.end();
......
......@@ -29,11 +29,7 @@
#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE
#include "caosdb/transaction.h" // for Transaction, ResultSet
#include "caosdb/transaction_status.h" // for TransactionSt...
#include <boost/log/core/record.hpp> // for record
#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring...
#include <boost/log/sources/record_ostream.hpp> // for operator<<
#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_...
#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_...
#include <boost/program_options.hpp> // for options_description
#include <exception> // for exception
#include <iostream> // for operator<<, basic_ostream, basic_ost...
#include <memory> // for unique_ptr, allocator, __shared_ptr_...
......@@ -41,14 +37,27 @@
const auto logger_name = "libcaosdb";
auto main() -> int {
using boost::program_options::bool_switch;
using boost::program_options::command_line_parser;
using boost::program_options::notify;
using boost::program_options::options_description;
using boost::program_options::parse_command_line;
using boost::program_options::positional_options_description;
using boost::program_options::store;
using boost::program_options::value;
using boost::program_options::variables_map;
using caosdb::acm::Role;
std::cout << "CaosDB C++ client (libcaosdb " << caosdb::LIBCAOSDB_VERSION_MINOR << "."
auto print_version(bool print) -> void {
if (print) {
std::cout << "CaosDB C++ client (libcaosdb " << caosdb::LIBCAOSDB_VERSION_MAJOR << "."
<< caosdb::LIBCAOSDB_VERSION_MINOR << "." << caosdb::LIBCAOSDB_VERSION_PATCH << ")\n"
<< "We don't miss the H of caos.\n"
<< std::endl;
}
}
try {
auto test_connection() -> void {
const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection();
connection->RetrieveVersionInfoNoExceptions();
......@@ -57,10 +66,13 @@ auto main() -> int {
std::cout << "Server Version: " << v_info->GetMajor() << "." << v_info->GetMinor() << "."
<< v_info->GetPatch() << "-" << v_info->GetPreRelease() << "-" << v_info->GetBuild()
<< std::endl;
}
// retrieve an entity
auto retrieve_entity_by_id(std::string id) -> void {
std::cout << "Retrieve entity " << id << std::endl;
const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection();
auto transaction(connection->CreateTransaction());
transaction->RetrieveById("21");
transaction->RetrieveById(id);
transaction->ExecuteAsynchronously();
auto t_stat = transaction->WaitForIt();
CAOSDB_LOG_INFO(logger_name) << "status: " << t_stat.GetCode() << " // "
......@@ -69,20 +81,94 @@ auto main() -> int {
for (const auto &entity : result_set) {
std::cout << entity.ToString() << std::endl;
}
}
// execute a query
std::string query("FIND Property \"Prop *\"");
std::cout << "Trying to execute a query:\n" << query << std::endl;
auto execute_query(std::string query) -> void {
std::cout << "Execute query:\n" << query << std::endl;
const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection();
auto q_transaction(connection->CreateTransaction());
q_transaction->Query(query);
q_transaction->ExecuteAsynchronously();
t_stat = q_transaction->WaitForIt();
auto t_stat = q_transaction->WaitForIt();
CAOSDB_LOG_INFO(logger_name) << "status: " << t_stat.GetCode() << " // "
<< t_stat.GetDescription();
const auto &result_set_2 = q_transaction->GetResultSet();
for (const auto &entity : result_set_2) {
std::cout << entity.ToString() << std::endl;
}
}
auto list_roles() -> void {
std::cout << "Known roles:" << std::endl;
const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection();
auto roles = connection->ListRoles();
for (const auto role : roles) {
std::cout << role.ToString() << std::endl;
}
}
auto retrieve_role(std::string name) {
const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection();
auto role = connection->RetrieveSingleRole(name);
std::cout << role.ToString() << std::endl;
}
auto create_role(std::string name) {
const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection();
Role role(name);
connection->CreateSingleRole(role);
std::cout << "OK" << std::endl;
}
auto delete_role(std::string name) {
const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection();
connection->DeleteSingleRole(name);
std::cout << "OK" << std::endl;
}
auto main(int argc, const char *argv[]) -> int {
try {
command_line_parser parser(argc, argv);
options_description desc{"Options"};
desc.add_options()("help,h", "Show help.")("version,V", bool_switch()->notifier(print_version),
"Print version of libcaosdb.")(
"test-connection,t", "Test the connection to the caosdb server.")(
"retrieve", value<std::string>()->notifier(retrieve_entity_by_id),
"Retrieve an entity by id and print its JSON representation.")(
"execute-query", value<std::string>()->notifier(execute_query),
"Execute a query and print the results")("list-roles", "List all known roles")(
"retrieve-role", value<std::string>()->notifier(retrieve_role), "Retrieve a role by name")(
"create-role", value<std::string>()->notifier(create_role), "Create a new role")(
"delete-role", value<std::string>()->notifier(delete_role), "Create a new role");
parser.options(desc);
// TODO(tf) add positional parameters
// positional_options_description pos_desc;
// pos_desc.add("phone", 1);
// parser.positional(pos_desc);
variables_map vm;
store(parser.run(), vm);
notify(vm);
if (vm.count("help")) {
std::cout << desc << std::endl;
} else if (vm["version"].as<bool>()) {
} else if (vm.count("test-connection")) {
test_connection();
} else if (vm.count("list-roles")) {
list_roles();
} else if (vm.count("retrieve-role")) {
} else if (vm.count("retrieve")) {
} else if (vm.count("create-role")) {
} else if (vm.count("delete-role")) {
} else if (vm.count("execute-query")) {
} else {
print_version(true);
test_connection();
}
return 0;
} catch (const caosdb::exceptions::ConfigurationError &exc) {
......@@ -92,7 +178,7 @@ auto main() -> int {
std::cout << "Exception: " << exc.what() << std::endl;
return 1;
} catch (...) {
std::cout << "Some other exception." << std::endl;
std::cout << "Unknown error." << std::endl;
return 2;
}
}
......@@ -29,6 +29,7 @@ set(test_cases
test_issues
test_list_properties
test_protobuf
test_role
test_transaction
test_utility
test_value
......@@ -41,7 +42,7 @@ set(test_cases
# special linting for tests
set(_CMAKE_CXX_CLANG_TIDY_TEST_CHECKS
"${_CMAKE_CXX_CLANG_TIDY_CHECKS},-cert-err58-cpp,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-owning-memory,-modernize-use-trailing-return-type,-google-readability-avoid-underscore-in-googletest-name,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-cppcoreguidelines-avoid-goto,-hicpp-avoid-goto,-readability-function-cognitive-complexity,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-clang-analyzer-cplusplus.Move"
"${_CMAKE_CXX_CLANG_TIDY_CHECKS},-cert-err58-cpp,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-owning-memory,-modernize-use-trailing-return-type,-google-readability-avoid-underscore-in-googletest-name,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-cppcoreguidelines-avoid-goto,-hicpp-avoid-goto,-readability-function-cognitive-complexity,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-clang-analyzer-cplusplus.Move,-clang-diagnostic-unused-result"
)
# add special cmake functions for gtest
......
......@@ -87,4 +87,11 @@ TEST_F(test_connection, connection_manager_get_connection) {
EXPECT_TRUE(ConnectionManager::GetConnection("local-caosdb-admin"));
}
TEST_F(test_connection, test_list_roles) {
auto connection = ConnectionManager::GetDefaultConnection();
EXPECT_THROW_MESSAGE(auto results = connection->ListRoles(), caosdb::exceptions::ConnectionError,
"The attempt to execute this transaction was not successful because the "
"connection to the server could not be established.");
}
} // namespace caosdb::connection
/*
*
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale.com>
* Copyright (C) 2022 IndiScale GmbH <info@indiscale.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "caosdb/acm/role.h" // for Role
#include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApiRe...
#include <gtest/gtest_pred_impl.h> // for Test, EXPECT_EQ, TEST
#include <memory> // for allocator
namespace caosdb::acm {
TEST(test_role, role_name) {
auto role = Role("role1");
EXPECT_EQ(role.GetName(), "role1");
role.SetName("role2");
EXPECT_EQ(role.GetName(), "role2");
}
TEST(test_role, role_description) {
auto role1 = Role("role1", "description1");
EXPECT_EQ(role1.GetName(), "role1");
EXPECT_EQ(role1.GetDescription(), "description1");
role1.SetName("role3");
EXPECT_EQ(role1.GetDescription(), "description1");
auto role2 = Role("role2", "description1");
EXPECT_EQ(role2.GetDescription(), "description1");
EXPECT_EQ(role2.GetName(), "role2");
role2.SetDescription("description2");
EXPECT_EQ(role2.GetDescription(), "description2");
EXPECT_EQ(role2.GetName(), "role2");
}
TEST(test_role, get_permission_rules) {
auto role1 = Role("role1", "description1");
EXPECT_TRUE(role1.GetPermissionRules().empty());
role1.Grant("SOME_PERMISSION", false);
EXPECT_FALSE(role1.GetPermissionRules().empty());
role1.Grant("SOME_OTHER_PERMISSION", true);
EXPECT_FALSE(role1.GetPermissionRules().empty());
role1.RevokeGrant("SOME_PERMISSION", false);
EXPECT_FALSE(role1.GetPermissionRules().empty());
role1.RevokeGrant("SOME_OTHER_PERMISSION", true);
EXPECT_TRUE(role1.GetPermissionRules().empty());
}
} // namespace caosdb::acm
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment