From 8a9adaa9c38a3269942181abadb5f700b7661ccb Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Thu, 26 Feb 2015 14:39:39 +0100 Subject: [PATCH 01/16] Fix basename() usage in ChecksumGenerator Contents of a string passed to basename() as an argument may be modified (it depends on implementation). In order not to perform unexpected changes, duplicate of given string is passed to basename(). Change-Id: Ib783629160f9528a6054dd0f78b9ebd5e6870fb6 --- src/chsgen/ChecksumGenerator.cpp | 32 +++++++++++++++++++++++--------- src/chsgen/ChecksumGenerator.h | 4 ++-- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/chsgen/ChecksumGenerator.cpp b/src/chsgen/ChecksumGenerator.cpp index 6255403..fcc76dc 100644 --- a/src/chsgen/ChecksumGenerator.cpp +++ b/src/chsgen/ChecksumGenerator.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -43,8 +45,10 @@ const char ChecksumGenerator::m_fieldSeparator(StorageConfig::fieldSeparator); const char ChecksumGenerator::m_recordSeparator(StorageConfig::recordSeparator); const std::string ChecksumGenerator::m_backupFilenameSuffix(StorageConfig::backupFilenameSuffix); -ChecksumGenerator::ChecksumGenerator(int argc, char * const *argv) : m_copyStream(std::string()) { - m_filename = (1 < argc ? argv[1] : std::string()); +ChecksumGenerator::ChecksumGenerator(int argc, char * const *argv) { + if (argc > 1) { + m_pathname = argv[1]; + } } int ChecksumGenerator::run(void) { @@ -65,11 +69,14 @@ int ChecksumGenerator::run(void) { } catch (const std::length_error &ex) { std::cerr << ex.what() << std::endl; return CYNARA_API_UNKNOWN_ERROR; + } catch (const std::bad_alloc &ex) { + std::cerr << ex.what() << std::endl; + return CYNARA_API_OUT_OF_MEMORY; } } const std::string ChecksumGenerator::generate(const std::string &data) { - auto checksum = crypt(data.c_str(), "$1$"); + const char *checksum = crypt(data.c_str(), "$1$"); if (nullptr != checksum) { return std::string(checksum); @@ -85,10 +92,10 @@ const std::string ChecksumGenerator::generate(const std::string &data) { }; void ChecksumGenerator::openFileStream(void) { - m_inputStream.open(m_filename); + m_inputStream.open(m_pathname); if (!m_inputStream.is_open()) { - throw FileNotFoundException(m_filename); + throw FileNotFoundException(m_pathname); } } @@ -100,14 +107,21 @@ void ChecksumGenerator::copyFileStream(void) { } void ChecksumGenerator::printRecord(void) const { - std::string filename(basename(m_filename.c_str())); - getBasicFilename(filename); + std::unique_ptr pathnameDuplicate(strdup(m_pathname.c_str()), free); + if (pathnameDuplicate == nullptr) { + LOGE("Insufficient memory available to allocate duplicate filename: <%s>", + m_pathname.c_str()); + throw std::bad_alloc(); + } + + std::string basename(::basename(pathnameDuplicate.get())); + removeBackupSuffix(basename); - std::cout << filename << m_fieldSeparator << generate(m_copyStream.str()) + std::cout << basename << m_fieldSeparator << generate(m_copyStream.str()) << m_recordSeparator; } -void ChecksumGenerator::getBasicFilename(std::string &filename) const { +void ChecksumGenerator::removeBackupSuffix(std::string &filename) const { auto backupSuffixPos = filename.rfind(m_backupFilenameSuffix); if (std::string::npos != backupSuffixPos && diff --git a/src/chsgen/ChecksumGenerator.h b/src/chsgen/ChecksumGenerator.h index a3e96e0..30e34fb 100644 --- a/src/chsgen/ChecksumGenerator.h +++ b/src/chsgen/ChecksumGenerator.h @@ -42,11 +42,11 @@ private: void openFileStream(void); void copyFileStream(void); void printRecord(void) const; - void getBasicFilename(std::string &filename) const; + void removeBackupSuffix(std::string &filename) const; std::ifstream m_inputStream; std::stringstream m_copyStream; - std::string m_filename; + std::string m_pathname; static const char m_fieldSeparator; static const char m_recordSeparator; static const std::string m_backupFilenameSuffix; -- 2.7.4 From 7832866a7fbf8b6425e180d1dbdfe7b80ab8f96d Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Tue, 23 Dec 2014 14:53:59 +0100 Subject: [PATCH 02/16] Introduce ChecksumValidator ChecksumValidator computes checksums for every file listed in checksum index equivalent using crypt(3). As a result, base64-like (custom alphabet) encoded strings are produced and compared with last known corresponding digest. Its 4-character prefix indicates used algorithm. Class will be later used as an integrity mechanism extension. Change-Id: Ibaba636bae30c747e8eac5561e9b130d4398518e --- src/storage/CMakeLists.txt | 2 + src/storage/ChecksumValidator.cpp | 142 ++++++++++++++++++++++++++++++++++++++ src/storage/ChecksumValidator.h | 65 +++++++++++++++++ test/CMakeLists.txt | 1 + 4 files changed, 210 insertions(+) create mode 100644 src/storage/ChecksumValidator.cpp create mode 100644 src/storage/ChecksumValidator.h diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt index 7bccc8c..996b37a 100644 --- a/src/storage/CMakeLists.txt +++ b/src/storage/CMakeLists.txt @@ -24,6 +24,7 @@ SET(CYNARA_LIB_CYNARA_STORAGE_PATH ${CYNARA_PATH}/storage) SET(LIB_CYNARA_STORAGE_SOURCES ${CYNARA_LIB_CYNARA_STORAGE_PATH}/BucketDeserializer.cpp + ${CYNARA_LIB_CYNARA_STORAGE_PATH}/ChecksumValidator.cpp ${CYNARA_LIB_CYNARA_STORAGE_PATH}/InMemoryStorageBackend.cpp ${CYNARA_LIB_CYNARA_STORAGE_PATH}/Integrity.cpp ${CYNARA_LIB_CYNARA_STORAGE_PATH}/Storage.cpp @@ -51,6 +52,7 @@ SET_TARGET_PROPERTIES( TARGET_LINK_LIBRARIES(${TARGET_LIB_CYNARA_STORAGE} ${CYNARA_DEP_LIBRARIES} ${TARGET_CYNARA_COMMON} + crypt ) INSTALL(TARGETS ${TARGET_LIB_CYNARA_STORAGE} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/src/storage/ChecksumValidator.cpp b/src/storage/ChecksumValidator.cpp new file mode 100644 index 0000000..1354ad1 --- /dev/null +++ b/src/storage/ChecksumValidator.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/** + * @file src/storage/ChecksumValidator.cpp + * @author Pawel Wieczorek + * @version 1.0 + * @brief This file contains ChecksumValidator implementation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ChecksumValidator.h" + +namespace Cynara { + +const std::string ChecksumValidator::m_checksumFilename(PathConfig::StoragePath::checksumFilename); +const std::string ChecksumValidator::m_backupFilenameSuffix( + PathConfig::StoragePath::backupFilenameSuffix); + +void ChecksumValidator::load(std::istream &stream) { + m_sums.clear(); + + std::string line; + std::size_t lineNum = 1; + while (std::getline(stream, line, PathConfig::StoragePath::recordSeparator)) { + try { + std::size_t beginToken = 0; + std::string filename = parseFilename(line, beginToken); + std::string checksum = parseChecksum(line, beginToken); + + m_sums.insert({ filename, checksum }); + ++lineNum; + } catch (const ChecksumRecordCorruptedException &ex) { + throw ex.withLineNumber(lineNum); + } + } +}; + +const std::string ChecksumValidator::generate(const std::string &data) { + const char *checksum = crypt(data.c_str(), "$1$"); + + if (nullptr != checksum) { + return checksum; + } + + int err = errno; + if (err == ENOSYS) { + LOGE("'crypt' function was not implemented; error [%d] : <%s>", err, strerror(err)); + } else { + LOGE("'crypt' function error [%d] : <%s>", err, strerror(err)); + } + throw UnexpectedErrorException(err, strerror(err)); +}; + +void ChecksumValidator::compare(std::istream &stream, const std::string &pathname, + bool isBackupValid) { + if (isChecksumIndex(pathname)) { + return; + } + + std::unique_ptr pathnameDuplicate(strdup(pathname.c_str()), free); + if (pathnameDuplicate == nullptr) { + LOGE("Insufficient memory available to allocate duplicate filename: <%s>", + pathname.c_str()); + throw std::bad_alloc(); + } + + std::string filename(::basename(pathnameDuplicate.get())); + std::stringstream copyStream; + + if (isBackupValid) { + auto backupSuffixPos = filename.rfind(m_backupFilenameSuffix); + + if ((std::string::npos != backupSuffixPos) && + (filename.size() == (backupSuffixPos + m_backupFilenameSuffix.size()))) { + filename.erase(backupSuffixPos); + } + } + + std::copy(std::istreambuf_iterator(stream), + std::istreambuf_iterator(), + std::ostreambuf_iterator(copyStream)); + stream.seekg(0); + + if (m_sums[filename] != generate(copyStream.str())) { + throw ChecksumRecordCorruptedException(m_sums[filename]); + } +}; + +const std::string ChecksumValidator::parseFilename(const std::string &line, + std::size_t &beginToken) { + std::size_t filenameEndToken = line.find(PathConfig::StoragePath::fieldSeparator, beginToken); + if (filenameEndToken != beginToken && filenameEndToken != std::string::npos) { + auto filename = line.substr(beginToken, filenameEndToken - beginToken); + beginToken = filenameEndToken + 1; + return filename; + } + throw ChecksumRecordCorruptedException(line); +} + +const std::string ChecksumValidator::parseChecksum(const std::string &line, + std::size_t &beginToken) { + if (beginToken >= line.size()) { + throw ChecksumRecordCorruptedException(line); + } + + auto checksum = line.substr(beginToken); + beginToken = line.size(); + return checksum; +} + +bool ChecksumValidator::isChecksumIndex(const std::string &filename) const { + auto checksum = m_dbPath + m_checksumFilename; + return (filename == checksum || filename == checksum + m_backupFilenameSuffix); +} + +} // namespace Cynara diff --git a/src/storage/ChecksumValidator.h b/src/storage/ChecksumValidator.h new file mode 100644 index 0000000..bfd577b --- /dev/null +++ b/src/storage/ChecksumValidator.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/** + * @file src/storage/ChecksumValidator.h + * @author Pawel Wieczorek + * @version 1.0 + * @brief This file contains ChecksumValidator header. + */ + +#ifndef SRC_STORAGE_CHECKSUMVALIDATOR_H_ +#define SRC_STORAGE_CHECKSUMVALIDATOR_H_ + +#include +#include +#include +#include + +namespace Cynara { + +class ChecksumValidator; +typedef std::unique_ptr ChecksumValidatorUniquePtr; + +class ChecksumValidator { +public: + ChecksumValidator(const std::string &path) : m_dbPath(path) {} + + void load(std::istream &stream); + void compare(std::istream &stream, const std::string &pathname, bool isBackupValid); + + void clear(void) { + m_sums.clear(); + } + + static const std::string generate(const std::string &data); + +protected: + typedef std::unordered_map Checksums; + + bool isChecksumIndex(const std::string &pathname) const; + + static const std::string parseFilename(const std::string &line, std::size_t &beginToken); + static const std::string parseChecksum(const std::string &line, std::size_t &beginToken); + + Checksums m_sums; + const std::string m_dbPath; + static const std::string m_checksumFilename; + static const std::string m_backupFilenameSuffix; +}; + +} // namespace Cynara + +#endif // SRC_STORAGE_CHECKSUMVALIDATOR_H_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d937d3c..f9b42a8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -63,6 +63,7 @@ SET(CYNARA_SOURCES_FOR_TESTS ${CYNARA_SRC}/helpers/creds-commons/creds-commons.cpp ${CYNARA_SRC}/service/main/CmdlineParser.cpp ${CYNARA_SRC}/storage/BucketDeserializer.cpp + ${CYNARA_SRC}/storage/ChecksumValidator.cpp ${CYNARA_SRC}/storage/InMemoryStorageBackend.cpp ${CYNARA_SRC}/storage/Integrity.cpp ${CYNARA_SRC}/storage/Storage.cpp -- 2.7.4 From 9f0e503b603acb3bcb7dfedd6fd27216070e6be7 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Tue, 27 Jan 2015 11:47:19 +0100 Subject: [PATCH 03/16] Add tests for ChecksumValidator Add tests checking if ChecksumValidator properly: * generates checksums, * loads them or rejects corrupted records, * supports backup files. Change-Id: I2e4222283cc0676490134819561824df6661034f --- test/CMakeLists.txt | 1 + test/storage/checksum/checksumvalidator.cpp | 154 +++++++++++++++++++++++ test/storage/checksum/checksumvalidatorfixture.h | 54 ++++++++ test/storage/checksum/fakechecksumvalidator.h | 37 ++++++ 4 files changed, 246 insertions(+) create mode 100644 test/storage/checksum/checksumvalidator.cpp create mode 100644 test/storage/checksum/checksumvalidatorfixture.h create mode 100644 test/storage/checksum/fakechecksumvalidator.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f9b42a8..5050634 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -92,6 +92,7 @@ SET(CYNARA_TESTS_SOURCES cyad/policy_parser.cpp helpers.cpp service/main/cmdlineparser.cpp + storage/checksum/checksumvalidator.cpp storage/performance/bucket.cpp storage/storage/policies.cpp storage/storage/check.cpp diff --git a/test/storage/checksum/checksumvalidator.cpp b/test/storage/checksum/checksumvalidator.cpp new file mode 100644 index 0000000..19918f3 --- /dev/null +++ b/test/storage/checksum/checksumvalidator.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/** + * @file test/storage/checksum/checksumvalidator.cpp + * @author Pawel Wieczorek + * @version 1.0 + * @brief Tests of ChecksumValidator + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "checksumvalidatorfixture.h" +#include "fakechecksumvalidator.h" + +using namespace Cynara; + +const std::string ChecksumValidatorFixture::m_dbPath("/fake/path/"); +const std::string ChecksumValidatorFixture::m_filename("fakeFilename"); +const std::string ChecksumValidatorFixture::m_checksum("$1$$fakeChecksum"); +const std::string ChecksumValidatorFixture::m_backupFilenameSuffix( + PathConfig::StoragePath::backupFilenameSuffix); +const char ChecksumValidatorFixture::m_fieldSeparator(PathConfig::StoragePath::fieldSeparator); +const char ChecksumValidatorFixture::m_recordSeparator(PathConfig::StoragePath::recordSeparator); +const size_t ChecksumValidatorFixture::m_firstLine(1); + +/** + * @brief Verify if generate() can use systems' crypt(3) implementation + * @test Expected result: no exceptions are thrown and non-empty string is returned + */ +TEST_F(ChecksumValidatorFixture, generateChecksum) { + for (const auto &data : { std::string("test-data"), std::string() }) { + SCOPED_TRACE(data); + + std::string returnedChecksum; + ASSERT_NO_THROW(returnedChecksum = ChecksumValidator::generate(data)); + ASSERT_NE(std::string(), returnedChecksum); + } +} + +/** + * @brief Verify if load() can successfully parse sample checksum record + * @test Expected result: + * - no exceptions are thrown from load() + * - proper checksums are stored for corresponding files + */ +TEST_F(ChecksumValidatorFixture, parseCorrectRecords) { + std::istringstream checksums(m_filename + m_fieldSeparator + m_checksum); + + FakeChecksumValidator validator(m_dbPath); + ASSERT_NO_THROW(validator.load(checksums)); + ASSERT_EQ(m_checksum, validator.sums().at(m_filename)); +} + +/** + * @brief Verify if load() rejects storing corrupted checksum records + * @test Expected result: + * - load() throws ChecksumRecordCorruptedException + * - no data is stored (there was no correct data to insert) + */ +TEST_F(ChecksumValidatorFixture, parseCorruptedRecords) { + const auto badLines = { m_filename + m_fieldSeparator, + m_filename + m_checksum, + m_fieldSeparator + m_checksum }; + + FakeChecksumValidator validator(m_dbPath); + + for (const auto &badLine : badLines) { + SCOPED_TRACE(badLine); + std::istringstream checksums(badLine); + + ASSERT_THROW(validator.load(checksums), ChecksumRecordCorruptedException); + ASSERT_TRUE(validator.sums().empty()); + } +} + +/** + * @brief Verify if compare() can successfully check sample database file + * @test Expected result: no exceptions are thrown and file contents are still readable + */ +TEST_F(ChecksumValidatorFixture, compareBasicAndBackup) { + FakeChecksumValidator validator(m_dbPath); + std::string checksumsContents; + simpleChecksumsContents(checksumsContents); + + std::istringstream checksums(checksumsContents); + validator.load(checksums); + + std::unordered_map files = { { "_", std::string() }, + { "buckets", ";0x0;\n" } }; + + for (const auto &file : files) { + const auto filename = m_dbPath + file.first; + const auto contents = file.second; + std::istringstream fakeFile(contents); + + SCOPED_TRACE(filename); + + ASSERT_NO_THROW(validator.compare(fakeFile, filename, false)); + ASSERT_NO_THROW(validator.compare(fakeFile, filename + m_backupFilenameSuffix, true)); + + ASSERT_EQ(contents, fakeFile.str()); + } +} + +/** + * @brief Verify if compare() throws an exception when checksum mismatch is detected + * @test Expected result: ChecksumRecordCorruptedException is thrown + */ +TEST_F(ChecksumValidatorFixture, checksumMismatch) { + FakeChecksumValidator validator(m_dbPath); + std::string checksumsContents; + simpleChecksumsContents(checksumsContents); + + std::istringstream checksums(checksumsContents); + validator.load(checksums); + + // Please note that default policy is set to ALLOW instead of DENY + std::unordered_map files = { { "_", "client;user;privilege;0x0;" }, + { "buckets", ";0xFFFF;\n" } }; + + for (const auto &file : files) { + const auto filename = m_dbPath + file.first; + const auto contents = file.second; + std::istringstream fakeFile(contents); + SCOPED_TRACE(filename); + + ASSERT_THROW(validator.compare(fakeFile, filename, false), + ChecksumRecordCorruptedException); + } +} diff --git a/test/storage/checksum/checksumvalidatorfixture.h b/test/storage/checksum/checksumvalidatorfixture.h new file mode 100644 index 0000000..6fb28f6 --- /dev/null +++ b/test/storage/checksum/checksumvalidatorfixture.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/** + * @file test/storage/checksum/checksumvalidatorfixture.h + * @author Pawel Wieczorek + * @version 1.0 + * @brief Fixture for ChecksumValidator tests + */ + +#ifndef CHECKSUMVALIDATORFIXTURE_H_ +#define CHECKSUMVALIDATORFIXTURE_H_ + +#include +#include + +#include +#include +#include +#include + +class ChecksumValidatorFixture : public ::testing::Test { +protected: + void simpleChecksumsContents(std::string &contents) { + std::stringstream buffer; + buffer << "_" << m_fieldSeparator << "$1$$qRPK7m23GJusamGpoGLby/" << m_recordSeparator + << "buckets" << m_fieldSeparator << "$1$$6ZlVs5lw2nZgVmiw0BdY21" + << m_recordSeparator; + + contents = buffer.str(); + } + + static const std::string m_dbPath; + static const std::string m_filename; + static const std::string m_checksum; + static const std::string m_backupFilenameSuffix; + static const char m_fieldSeparator; + static const char m_recordSeparator; + static const size_t m_firstLine; +}; + +#endif /* CHECKSUMVALIDATORFIXTURE_H_ */ diff --git a/test/storage/checksum/fakechecksumvalidator.h b/test/storage/checksum/fakechecksumvalidator.h new file mode 100644 index 0000000..af3ed82 --- /dev/null +++ b/test/storage/checksum/fakechecksumvalidator.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/** + * @file test/storage/checksum/fakechecksumvalidator.h + * @author Pawel Wieczorek + * @version 1.0 + * @brief Mock of ChecksumValidator + */ + +#ifndef FAKECHECKSUMVALIDATOR_H_ +#define FAKECHECKSUMVALIDATOR_H_ + +#include + +class FakeChecksumValidator : public Cynara::ChecksumValidator { +public: + using Cynara::ChecksumValidator::ChecksumValidator; + + const Checksums &sums(void) { + return m_sums; + } +}; + +#endif /* FAKECHECKSUMVALIDATOR_H_ */ -- 2.7.4 From 58d92c8f005be204b6d0cb990d8276aed1f3b76a Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Mon, 12 Jan 2015 15:01:54 +0100 Subject: [PATCH 04/16] Make StorageSerializer a template class This patch modifies StorageSerializer so that it will be able to use other streams than std::ostream and its derivatives. Within current class hierarchy custom output streams with overloaded insertion operator (operator<<) cannot be used, as it is non-virtual in std::ostream. Change-Id: I3e713329c55aacfbb8daa23a5c4579d4c5db9f52 --- src/storage/CMakeLists.txt | 3 +- src/storage/InMemoryStorageBackend.cpp | 6 +-- src/storage/InMemoryStorageBackend.h | 3 +- src/storage/StorageSerializer.cpp | 92 ---------------------------------- src/storage/StorageSerializer.h | 68 ++++++++++++++++++++++++- test/CMakeLists.txt | 1 - test/storage/serializer/dump.cpp | 8 +-- test/storage/serializer/dump_load.cpp | 4 +- test/storage/serializer/serialize.cpp | 27 +++++----- 9 files changed, 93 insertions(+), 119 deletions(-) delete mode 100644 src/storage/StorageSerializer.cpp diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt index 996b37a..72f0ec2 100644 --- a/src/storage/CMakeLists.txt +++ b/src/storage/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +# Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,7 +29,6 @@ SET(LIB_CYNARA_STORAGE_SOURCES ${CYNARA_LIB_CYNARA_STORAGE_PATH}/Integrity.cpp ${CYNARA_LIB_CYNARA_STORAGE_PATH}/Storage.cpp ${CYNARA_LIB_CYNARA_STORAGE_PATH}/StorageDeserializer.cpp - ${CYNARA_LIB_CYNARA_STORAGE_PATH}/StorageSerializer.cpp ) INCLUDE_DIRECTORIES( diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp index a5e08b1..d6655e2 100644 --- a/src/storage/InMemoryStorageBackend.cpp +++ b/src/storage/InMemoryStorageBackend.cpp @@ -100,7 +100,7 @@ void InMemoryStorageBackend::save(void) { std::string indexFilename = m_dbPath + m_indexFilename; openDumpFileStream(indexStream, indexFilename + m_backupFilenameSuffix); - StorageSerializer storageSerializer(indexStream); + StorageSerializer storageSerializer(indexStream); storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener, this, std::placeholders::_1)); @@ -253,14 +253,14 @@ std::shared_ptr InMemoryStorageBackend::bucketStreamOpener( } } -std::shared_ptr InMemoryStorageBackend::bucketDumpStreamOpener( +std::shared_ptr > InMemoryStorageBackend::bucketDumpStreamOpener( const PolicyBucketId &bucketId) { std::string bucketFilename = m_dbPath + m_bucketFilenamePrefix + bucketId + m_backupFilenameSuffix; auto bucketStream = std::make_shared(); openDumpFileStream(bucketStream, bucketFilename); - return std::make_shared(bucketStream); + return std::make_shared >(bucketStream); } void InMemoryStorageBackend::postLoadCleanup(bool isBackupValid) { diff --git a/src/storage/InMemoryStorageBackend.h b/src/storage/InMemoryStorageBackend.h index c9e63c2..10251c7 100644 --- a/src/storage/InMemoryStorageBackend.h +++ b/src/storage/InMemoryStorageBackend.h @@ -71,7 +71,8 @@ protected: virtual void openDumpFileStream(std::shared_ptr stream, const std::string &filename); - std::shared_ptr bucketDumpStreamOpener(const PolicyBucketId &bucketId); + std::shared_ptr > bucketDumpStreamOpener( + const PolicyBucketId &bucketId); virtual void postLoadCleanup(bool isBackupValid); diff --git a/src/storage/StorageSerializer.cpp b/src/storage/StorageSerializer.cpp deleted file mode 100644 index 9f701dd..0000000 --- a/src/storage/StorageSerializer.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved - * - * 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. - */ -/** - * @file src/storage/StorageSerializer.cpp - * @author Aleksander Zdyb - * @version 1.0 - * @brief Implementation of Cynara::StorageSerializer methods - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "StorageSerializer.h" - -namespace Cynara { - -StorageSerializer::StorageSerializer(std::shared_ptr os) : m_outStream(os) { -} - -void StorageSerializer::dump(const Buckets &buckets, - BucketStreamOpener streamOpener) { - - for (const auto bucketIter : buckets) { - const auto &bucket = bucketIter.second; - - dumpFields(bucket.id(), bucket.defaultPolicy().policyType(), - bucket.defaultPolicy().metadata()); - } - - for (const auto bucketIter : buckets) { - const auto &bucketId = bucketIter.first; - const auto &bucket = bucketIter.second; - auto bucketSerializer = streamOpener(bucketId); - - if (bucketSerializer != nullptr) { - bucketSerializer->dump(bucket); - } else { - throw BucketSerializationException(bucketId); - } - } -} - -void StorageSerializer::dump(const PolicyBucket& bucket) { - for (auto it = std::begin(bucket); it != std::end(bucket); ++it) { - const auto &policy = *it; - dump(policy); - } -} - -void StorageSerializer::dump(const PolicyKeyFeature &keyFeature) { - *m_outStream << keyFeature.toString(); -} - -void StorageSerializer::dump(const PolicyType &policyType) { - auto oldFormat = m_outStream->flags(); - *m_outStream << "0x" << std::uppercase << std::hex << policyType; - m_outStream->flags(oldFormat); -} - -void StorageSerializer::dump(const PolicyResult::PolicyMetadata &metadata) { - *m_outStream << metadata; -} - -void StorageSerializer::dump(const PolicyCollection::value_type &policy) { - const auto &key = policy->key(); - const auto &result = policy->result(); - - dumpFields(key.client(), key.user(), key.privilege(), result.policyType(), result.metadata()); -} - -} /* namespace Cynara */ diff --git a/src/storage/StorageSerializer.h b/src/storage/StorageSerializer.h index 42982b2..40eb784 100644 --- a/src/storage/StorageSerializer.h +++ b/src/storage/StorageSerializer.h @@ -25,9 +25,13 @@ #include #include +#include #include +#include #include +#include +#include #include #include #include @@ -39,13 +43,14 @@ namespace Cynara { +template class StorageSerializer { public: typedef std::function(const PolicyBucketId &)> BucketStreamOpener; - StorageSerializer(std::shared_ptr os); + StorageSerializer(std::shared_ptr os); virtual ~StorageSerializer() {}; virtual void dump(const Buckets &buckets, @@ -72,9 +77,68 @@ protected: void dump(const PolicyCollection::value_type &policy); private: - std::shared_ptr m_outStream; + std::shared_ptr m_outStream; }; +template +StorageSerializer::StorageSerializer(std::shared_ptr os) : m_outStream(os) { +} + +template +void StorageSerializer::dump(const Buckets &buckets, BucketStreamOpener streamOpener) { + for (const auto bucketIter : buckets) { + const auto &bucket = bucketIter.second; + + dumpFields(bucket.id(), bucket.defaultPolicy().policyType(), + bucket.defaultPolicy().metadata()); + } + + for (const auto bucketIter : buckets) { + const auto &bucketId = bucketIter.first; + const auto &bucket = bucketIter.second; + auto bucketSerializer = streamOpener(bucketId); + + if (bucketSerializer != nullptr) { + bucketSerializer->dump(bucket); + } else { + throw BucketSerializationException(bucketId); + } + } +} + +template +void StorageSerializer::dump(const PolicyBucket &bucket) { + for (auto it = std::begin(bucket); it != std::end(bucket); ++it) { + const auto &policy = *it; + dump(policy); + } +} + +template +void StorageSerializer::dump(const PolicyKeyFeature &keyFeature) { + *m_outStream << keyFeature.toString(); +} + +template +void StorageSerializer::dump(const PolicyType &policyType) { + auto oldFormat = m_outStream->flags(); + *m_outStream << "0x" << std::uppercase << std::hex << policyType; + m_outStream->flags(oldFormat); +} + +template +void StorageSerializer::dump(const PolicyResult::PolicyMetadata &metadata) { + *m_outStream << metadata; +} + +template +void StorageSerializer::dump(const PolicyCollection::value_type &policy) { + const auto &key = policy->key(); + const auto &result = policy->result(); + + dumpFields(key.client(), key.user(), key.privilege(), result.policyType(), result.metadata()); +} + } /* namespace Cynara */ #endif /* SRC_STORAGE_STORAGESERIALIZER_H_ */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5050634..9cf89d7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -68,7 +68,6 @@ SET(CYNARA_SOURCES_FOR_TESTS ${CYNARA_SRC}/storage/Integrity.cpp ${CYNARA_SRC}/storage/Storage.cpp ${CYNARA_SRC}/storage/StorageDeserializer.cpp - ${CYNARA_SRC}/storage/StorageSerializer.cpp ) SET(CYNARA_TESTS_SOURCES diff --git a/test/storage/serializer/dump.cpp b/test/storage/serializer/dump.cpp index 2eafcf7..1daaf32 100644 --- a/test/storage/serializer/dump.cpp +++ b/test/storage/serializer/dump.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,7 +51,7 @@ TEST(serializer_dump, dump_empty_bucket) { auto oss = std::make_shared(); PolicyBucket bucket("empty"); - StorageSerializer serializer(oss); + StorageSerializer serializer(oss); serializer.dump(bucket); ASSERT_EQ("", oss->str()); @@ -69,7 +69,7 @@ TEST(serializer_dump, dump_bucket) { Policy::simpleWithKey(pk2, DENY) })); auto outStream = std::make_shared(); - StorageSerializer serializer(outStream); + StorageSerializer serializer(outStream); serializer.dump(bucket); // Split stream into records @@ -99,7 +99,7 @@ TEST(serializer_dump, dump_bucket_bucket) { Policy::bucketWithKey(pk3, bucketId) }}; auto outStream = std::make_shared(); - StorageSerializer serializer(outStream); + StorageSerializer serializer(outStream); serializer.dump(bucket); // Split stream into records diff --git a/test/storage/serializer/dump_load.cpp b/test/storage/serializer/dump_load.cpp index f3eff9b..cd4ce5c 100644 --- a/test/storage/serializer/dump_load.cpp +++ b/test/storage/serializer/dump_load.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,7 @@ TEST(dump_load, bucket) { auto ioStream = std::make_shared(); - StorageSerializer serializer(ioStream); + StorageSerializer serializer(ioStream); serializer.dump(bucket); BucketDeserializer deserializer(ioStream); diff --git a/test/storage/serializer/serialize.cpp b/test/storage/serializer/serialize.cpp index 938283d..1681a5b 100644 --- a/test/storage/serializer/serialize.cpp +++ b/test/storage/serializer/serialize.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,21 +37,24 @@ class FakeStreamForBucketId { public: + typedef std::shared_ptr > + StringstreamStorageSerializerPtr; + MOCK_METHOD1(streamForBucketId, - std::shared_ptr(const Cynara::PolicyBucketId &)); + StringstreamStorageSerializerPtr(const Cynara::PolicyBucketId &)); - Cynara::StorageSerializer::BucketStreamOpener streamOpener() { + Cynara::StorageSerializer::BucketStreamOpener streamOpener() { return std::bind(&FakeStreamForBucketId::streamForBucketId, this, std::placeholders::_1); } }; // Fake StorageSerializer for Cynara::PolicyBucket -class FakeStorageSerializer : public Cynara::StorageSerializer { +class FakeStorageSerializer : public Cynara::StorageSerializer { public: - FakeStorageSerializer(std::shared_ptr o) : Cynara::StorageSerializer(o), - outStream(o) {} + FakeStorageSerializer(std::shared_ptr o) + : Cynara::StorageSerializer(o), outStream(o) {} MOCK_METHOD1(dump, void(const Cynara::PolicyBucket &bucket)); - std::shared_ptr outStream; + std::shared_ptr outStream; }; class StorageSerializerFixture : public ::testing::Test { @@ -67,8 +70,8 @@ using namespace Cynara; // Be sure no calls to streamForBucketId() are made // and output stream is not touched TEST_F(StorageSerializerFixture, dump_buckets_empty) { - auto outStream = std::make_shared(); - StorageSerializer serializer(outStream); + auto outStream = std::make_shared(); + StorageSerializer serializer(outStream); serializer.dump(Buckets(), fakeStreamOpener.streamOpener()); // Stream should be empty @@ -83,7 +86,7 @@ TEST_F(StorageSerializerFixture, dump_buckets) { // Will be returned as serializer for buckets auto fakeBucketSerializer = std::make_shared( - std::make_shared()); + std::make_shared()); buckets = { { "bucket1", PolicyBucket("bucket1", PredefinedPolicyType::DENY) }, @@ -93,7 +96,7 @@ TEST_F(StorageSerializerFixture, dump_buckets) { }; auto outStream = std::make_shared(); - StorageSerializer dbSerializer(outStream); + StorageSerializer dbSerializer(outStream); // Make sure stream was opened for each bucket EXPECT_CALL(fakeStreamOpener, streamForBucketId(_)) @@ -128,7 +131,7 @@ TEST_F(StorageSerializerFixture, dump_buckets_io_error) { }; auto outStream = std::make_shared(); - StorageSerializer dbSerializer(outStream); + StorageSerializer dbSerializer(outStream); // Make sure stream was opened for each bucket EXPECT_CALL(fakeStreamOpener, streamForBucketId(_)) -- 2.7.4 From bf8b0794dbe4d401430cae787e6bc3e6e0d09224 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Thu, 15 Jan 2015 08:19:15 +0100 Subject: [PATCH 05/16] Introduce ChecksumStream ChecksumStream will replace std::ofstream for saving database contents in storage. This way data will be not only written to the files, but also its checksums will be computed and stored in given stream (database index equivalent for storing checksums). Checksum computing is performed during stream destruction in order to be sure that all necessary data was already collected. Change-Id: I4a9ff2e29361f337cacd790d77364feca854a706 --- src/storage/CMakeLists.txt | 1 + src/storage/ChecksumStream.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++ src/storage/ChecksumStream.h | 70 +++++++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 1 + 4 files changed, 143 insertions(+) create mode 100644 src/storage/ChecksumStream.cpp create mode 100644 src/storage/ChecksumStream.h diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt index 72f0ec2..f75bc06 100644 --- a/src/storage/CMakeLists.txt +++ b/src/storage/CMakeLists.txt @@ -24,6 +24,7 @@ SET(CYNARA_LIB_CYNARA_STORAGE_PATH ${CYNARA_PATH}/storage) SET(LIB_CYNARA_STORAGE_SOURCES ${CYNARA_LIB_CYNARA_STORAGE_PATH}/BucketDeserializer.cpp + ${CYNARA_LIB_CYNARA_STORAGE_PATH}/ChecksumStream.cpp ${CYNARA_LIB_CYNARA_STORAGE_PATH}/ChecksumValidator.cpp ${CYNARA_LIB_CYNARA_STORAGE_PATH}/InMemoryStorageBackend.cpp ${CYNARA_LIB_CYNARA_STORAGE_PATH}/Integrity.cpp diff --git a/src/storage/ChecksumStream.cpp b/src/storage/ChecksumStream.cpp new file mode 100644 index 0000000..551307e --- /dev/null +++ b/src/storage/ChecksumStream.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/** + * @file src/storage/ChecksumStream.cpp + * @author Pawel Wieczorek + * @version 1.0 + * @brief This file contains ChecksumStream implementation. + */ + +#include +#include + +#include + +#include + +#include "ChecksumStream.h" + +namespace Cynara { + +const char ChecksumStream::m_fieldSeparator(PathConfig::StoragePath::fieldSeparator); +const char ChecksumStream::m_recordSeparator(PathConfig::StoragePath::recordSeparator); + +ChecksumStream::~ChecksumStream() { + if (!std::uncaught_exception()) { + save(); + } +} + +ChecksumStream& ChecksumStream::operator<<(std::ostream& (*manip)(std::ostream&)) { + m_bufStream << manip; + m_outStream << manip; + return *this; +} + +void ChecksumStream::open(const std::string &filename, std::ios_base::openmode mode) { + m_outStream.open(filename, mode); +} + +bool ChecksumStream::is_open(void) const { + return m_outStream.is_open(); +} + +std::ios_base::fmtflags ChecksumStream::flags(void) const { + return m_outStream.flags(); +} + +std::ios_base::fmtflags ChecksumStream::flags(std::ios_base::fmtflags flags) { + return m_outStream.flags(flags); +} + +void ChecksumStream::save() { + m_outStream.close(); + *m_chsStream << m_filename << m_fieldSeparator << ChecksumValidator::generate(m_bufStream.str()) + << m_recordSeparator; +} + +} // namespace Cynara diff --git a/src/storage/ChecksumStream.h b/src/storage/ChecksumStream.h new file mode 100644 index 0000000..ddc6e6f --- /dev/null +++ b/src/storage/ChecksumStream.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/** + * @file src/storage/ChecksumStream.h + * @author Pawel Wieczorek + * @version 1.0 + * @brief This file contains ChecksumStream header. + */ + +#ifndef SRC_STORAGE_CHECKSUMSTREAM_H_ +#define SRC_STORAGE_CHECKSUMSTREAM_H_ + +#include +#include +#include +#include +#include + +namespace Cynara { + +class ChecksumStream { +public: + ChecksumStream(const std::string &filename, const std::shared_ptr &stream) + : m_chsStream(stream), m_filename(filename) { + } + ~ChecksumStream(); + + template + ChecksumStream& operator<<(const Type &item); + ChecksumStream& operator<<(std::ostream& (*manip)(std::ostream&)); + + void open(const std::string &filename, std::ios_base::openmode mode); + bool is_open(void) const; + std::ios_base::fmtflags flags(void) const; + std::ios_base::fmtflags flags(std::ios_base::fmtflags flags); + +private: + void save(void); + + std::shared_ptr m_chsStream; + std::ofstream m_outStream; + std::stringstream m_bufStream; + const std::string m_filename; + static const char m_fieldSeparator; + static const char m_recordSeparator; +}; + +template +ChecksumStream& ChecksumStream::operator<<(const Type& item) { + m_bufStream << item; + m_outStream << item; + return *this; +} + +} // namespace Cynara + +#endif // SRC_STORAGE_CHECKSUMSTREAM_H_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9cf89d7..189268d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -63,6 +63,7 @@ SET(CYNARA_SOURCES_FOR_TESTS ${CYNARA_SRC}/helpers/creds-commons/creds-commons.cpp ${CYNARA_SRC}/service/main/CmdlineParser.cpp ${CYNARA_SRC}/storage/BucketDeserializer.cpp + ${CYNARA_SRC}/storage/ChecksumStream.cpp ${CYNARA_SRC}/storage/ChecksumValidator.cpp ${CYNARA_SRC}/storage/InMemoryStorageBackend.cpp ${CYNARA_SRC}/storage/Integrity.cpp -- 2.7.4 From f08a80ee755ba5aed0450bb04eaa235e3966ab05 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Tue, 23 Dec 2014 17:18:16 +0100 Subject: [PATCH 06/16] Adjust InMemoryStorageBackend to ChecksumValidator InMemoryStorageBackend uses ChecksumValidator as a checksum loader and comparator. This patch also includes files needed by storage unit tests to work properly. Change-Id: I541975351275bd6a30e7cf627697c9657161312f --- src/storage/InMemoryStorageBackend.cpp | 27 ++++++++++++++++++++------- src/storage/InMemoryStorageBackend.h | 9 +++++++-- src/storage/Integrity.cpp | 8 +++++++- test/db/db2/checksum | 1 + test/db/db3/checksum | 2 ++ test/db/db4/checksum | 3 +++ test/db/db5/checksum | 3 +++ test/db/db6/checksum | 3 +++ test/db/db6/checksum~ | 3 +++ 9 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 test/db/db2/checksum create mode 100644 test/db/db3/checksum create mode 100644 test/db/db4/checksum create mode 100644 test/db/db5/checksum create mode 100644 test/db/db6/checksum create mode 100644 test/db/db6/checksum~ diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp index d6655e2..249eccf 100644 --- a/src/storage/InMemoryStorageBackend.cpp +++ b/src/storage/InMemoryStorageBackend.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ namespace Cynara { +const std::string InMemoryStorageBackend::m_chsFilename(PathConfig::StoragePath::checksumFilename); const std::string InMemoryStorageBackend::m_indexFilename(PathConfig::StoragePath::indexFilename); const std::string InMemoryStorageBackend::m_backupFilenameSuffix( PathConfig::StoragePath::backupFilenameSuffix); @@ -58,26 +60,32 @@ const std::string InMemoryStorageBackend::m_bucketFilenamePrefix( PathConfig::StoragePath::bucketFilenamePrefix); InMemoryStorageBackend::InMemoryStorageBackend(const std::string &path) : m_dbPath(path), - m_integrity(path) { + m_checksum(path), m_integrity(path) { } void InMemoryStorageBackend::load(void) { bool isBackupValid = m_integrity.backupGuardExists(); std::string bucketSuffix = ""; std::string indexFilename = m_dbPath + m_indexFilename; + std::string chsFilename = m_dbPath + m_chsFilename; if (isBackupValid) { bucketSuffix += m_backupFilenameSuffix; indexFilename += m_backupFilenameSuffix; + chsFilename += m_backupFilenameSuffix; } try { + auto chsStream = std::make_shared(); + openFileStream(chsStream, chsFilename, isBackupValid); + m_checksum.load(*chsStream); + auto indexStream = std::make_shared(); - openFileStream(indexStream, indexFilename); + openFileStream(indexStream, indexFilename, isBackupValid); StorageDeserializer storageDeserializer(indexStream, std::bind(&InMemoryStorageBackend::bucketStreamOpener, this, - std::placeholders::_1, bucketSuffix)); + std::placeholders::_1, bucketSuffix, isBackupValid)); storageDeserializer.initBuckets(buckets()); storageDeserializer.loadBuckets(buckets()); @@ -86,6 +94,7 @@ void InMemoryStorageBackend::load(void) { buckets().clear(); // TODO: Implement emergency mode toggle } + m_checksum.clear(); if (!hasBucket(defaultPolicyBucketId)) { LOGN("Creating defaultBucket."); @@ -222,7 +231,7 @@ void InMemoryStorageBackend::erasePolicies(const PolicyBucketId &bucketId, bool } void InMemoryStorageBackend::openFileStream(std::shared_ptr stream, - const std::string &filename) { + const std::string &filename, bool isBackupValid) { // TODO: Consider adding exceptions to streams and handling them: // stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); stream->open(filename); @@ -230,6 +239,8 @@ void InMemoryStorageBackend::openFileStream(std::shared_ptr strea if (!stream->is_open()) { throw FileNotFoundException(filename); } + + m_checksum.compare(*stream, filename, isBackupValid); } void InMemoryStorageBackend::openDumpFileStream(std::shared_ptr stream, @@ -242,14 +253,16 @@ void InMemoryStorageBackend::openDumpFileStream(std::shared_ptr s } std::shared_ptr InMemoryStorageBackend::bucketStreamOpener( - const PolicyBucketId &bucketId, const std::string &filenameSuffix) { + const PolicyBucketId &bucketId, const std::string &filenameSuffix, bool isBackupValid) { std::string bucketFilename = m_dbPath + m_bucketFilenamePrefix + bucketId + filenameSuffix; auto bucketStream = std::make_shared(); try { - openFileStream(bucketStream, bucketFilename); + openFileStream(bucketStream, bucketFilename, isBackupValid); return std::make_shared(bucketStream); } catch (const FileNotFoundException &) { return nullptr; + } catch (const std::bad_alloc &) { + return nullptr; } } @@ -269,7 +282,7 @@ void InMemoryStorageBackend::postLoadCleanup(bool isBackupValid) { } //in case there were unnecessary files in db directory m_integrity.deleteNonIndexedFiles(std::bind(&InMemoryStorageBackend::hasBucket, this, - std::placeholders::_1)); + std::placeholders::_1)); } } /* namespace Cynara */ diff --git a/src/storage/InMemoryStorageBackend.h b/src/storage/InMemoryStorageBackend.h index 10251c7..65af96b 100644 --- a/src/storage/InMemoryStorageBackend.h +++ b/src/storage/InMemoryStorageBackend.h @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -65,9 +66,11 @@ public: const PolicyKey &filter); protected: - void openFileStream(std::shared_ptr stream, const std::string &filename); + void openFileStream(std::shared_ptr stream, const std::string &filename, + bool isBackupValid); std::shared_ptr bucketStreamOpener(const PolicyBucketId &bucketId, - const std::string &fileNameSuffix); + const std::string &fileNameSuffix, + bool isBackupValid); virtual void openDumpFileStream(std::shared_ptr stream, const std::string &filename); @@ -79,7 +82,9 @@ protected: private: std::string m_dbPath; Buckets m_buckets; + ChecksumValidator m_checksum; Integrity m_integrity; + static const std::string m_chsFilename; static const std::string m_indexFilename; static const std::string m_backupFilenameSuffix; static const std::string m_bucketFilenamePrefix; diff --git a/src/storage/Integrity.cpp b/src/storage/Integrity.cpp index 5dfa624..0b8e583 100644 --- a/src/storage/Integrity.cpp +++ b/src/storage/Integrity.cpp @@ -83,6 +83,7 @@ void Integrity::syncDatabase(const Buckets &buckets, bool syncBackup) { } syncElement(m_dbPath + m_indexFilename + suffix); + syncElement(m_dbPath + PathConfig::StoragePath::checksumFilename + suffix); syncDirectory(m_dbPath); } @@ -152,7 +153,8 @@ void Integrity::syncElement(const std::string &filename, int flags, mode_t mode) if (fileFd < 0) { int err = errno; if (err != EEXIST) { - LOGE("'open' function error [%d] : <%s>", err, strerror(err)); + LOGE("File <%s> : 'open' function error [%d] : <%s>", filename.c_str(), err, + strerror(err)); throw UnexpectedErrorException(err, strerror(err)); } else { throw CannotCreateFileException(filename); @@ -194,9 +196,12 @@ void Integrity::createPrimaryHardLinks(const Buckets &buckets) { } const auto &indexFilename = m_dbPath + m_indexFilename; + const auto &checksumFilename = m_dbPath + PathConfig::StoragePath::checksumFilename; deleteHardLink(indexFilename); createHardLink(indexFilename + m_backupFilenameSuffix, indexFilename); + deleteHardLink(checksumFilename); + createHardLink(checksumFilename + m_backupFilenameSuffix, checksumFilename); } void Integrity::deleteBackupHardLinks(const Buckets &buckets) { @@ -209,6 +214,7 @@ void Integrity::deleteBackupHardLinks(const Buckets &buckets) { } deleteHardLink(m_dbPath + m_indexFilename + m_backupFilenameSuffix); + deleteHardLink(m_dbPath + PathConfig::StoragePath::checksumFilename + m_backupFilenameSuffix); } void Integrity::createHardLink(const std::string &oldName, const std::string &newName) { diff --git a/test/db/db2/checksum b/test/db/db2/checksum new file mode 100644 index 0000000..a91e13a --- /dev/null +++ b/test/db/db2/checksum @@ -0,0 +1 @@ +buckets;$1$$QYBGLyef4xp18EzYIMd/U0 diff --git a/test/db/db3/checksum b/test/db/db3/checksum new file mode 100644 index 0000000..39a8d89 --- /dev/null +++ b/test/db/db3/checksum @@ -0,0 +1,2 @@ +buckets;$1$$QYBGLyef4xp18EzYIMd/U0 +_;$1$$qRPK7m23GJusamGpoGLby/ diff --git a/test/db/db4/checksum b/test/db/db4/checksum new file mode 100644 index 0000000..e2477f0 --- /dev/null +++ b/test/db/db4/checksum @@ -0,0 +1,3 @@ +buckets;$1$$Z6OUrCl62KbAaZ16Cexgm0 +_;$1$$qRPK7m23GJusamGpoGLby/ +_additional;$1$$qRPK7m23GJusamGpoGLby/ diff --git a/test/db/db5/checksum b/test/db/db5/checksum new file mode 100644 index 0000000..b578233 --- /dev/null +++ b/test/db/db5/checksum @@ -0,0 +1,3 @@ +buckets;$1$$Z6OUrCl62KbAaZ16Cexgm0 +_;$1$$qRPK7m23GJusamGpoGLby/ +_additional;$1$$NIRf1PrhNP0QOAOGJ4VDf/ diff --git a/test/db/db6/checksum b/test/db/db6/checksum new file mode 100644 index 0000000..a951841 --- /dev/null +++ b/test/db/db6/checksum @@ -0,0 +1,3 @@ +buckets;$1$$Z6OUrCl62KbAaZ16Cexgm0 +_;$1$$qRPK7m23GJusamGpoGLby/ +_additional;$1$$Shj03wOSJf.nmFjldRTO.1 diff --git a/test/db/db6/checksum~ b/test/db/db6/checksum~ new file mode 100644 index 0000000..e2477f0 --- /dev/null +++ b/test/db/db6/checksum~ @@ -0,0 +1,3 @@ +buckets;$1$$Z6OUrCl62KbAaZ16Cexgm0 +_;$1$$qRPK7m23GJusamGpoGLby/ +_additional;$1$$qRPK7m23GJusamGpoGLby/ -- 2.7.4 From e47f0b094278df45f6d38483718fafeba4d558d0 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Thu, 15 Jan 2015 10:53:18 +0100 Subject: [PATCH 07/16] Adjust InMemoryStorageBackend to ChecksumStream Now InMemoryStorageBackend uses ChecksumStream instead of std::ofstream. New member function dumpDatabase() was introduced in order to destruct database index stream before calling integrity mechanism. Change-Id: I5ea943e1ec21f02cea97699993ddbd0f3eeb0a62 --- src/storage/InMemoryStorageBackend.cpp | 43 +++++++++++++++++----------------- src/storage/InMemoryStorageBackend.h | 24 +++++++++++++++---- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp index 249eccf..57a4b56 100644 --- a/src/storage/InMemoryStorageBackend.cpp +++ b/src/storage/InMemoryStorageBackend.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -105,13 +104,11 @@ void InMemoryStorageBackend::load(void) { } void InMemoryStorageBackend::save(void) { - auto indexStream = std::make_shared(); - std::string indexFilename = m_dbPath + m_indexFilename; - openDumpFileStream(indexStream, indexFilename + m_backupFilenameSuffix); + std::string checksumFilename = m_dbPath + m_chsFilename; + auto chsStream = std::make_shared(); + openDumpFileStream(chsStream, checksumFilename + m_backupFilenameSuffix); - StorageSerializer storageSerializer(indexStream); - storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener, - this, std::placeholders::_1)); + dumpDatabase(chsStream); m_integrity.syncDatabase(buckets(), true); m_integrity.createBackupGuard(); @@ -230,7 +227,17 @@ void InMemoryStorageBackend::erasePolicies(const PolicyBucketId &bucketId, bool } } -void InMemoryStorageBackend::openFileStream(std::shared_ptr stream, +void InMemoryStorageBackend::dumpDatabase(const std::shared_ptr &chsStream) { + auto indexStream = std::make_shared(m_indexFilename, chsStream); + std::string indexFilename = m_dbPath + m_indexFilename; + openDumpFileStream(indexStream, indexFilename + m_backupFilenameSuffix); + + StorageSerializer storageSerializer(indexStream); + storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener, + this, std::placeholders::_1, chsStream)); +} + +void InMemoryStorageBackend::openFileStream(const std::shared_ptr &stream, const std::string &filename, bool isBackupValid) { // TODO: Consider adding exceptions to streams and handling them: // stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); @@ -243,15 +250,6 @@ void InMemoryStorageBackend::openFileStream(std::shared_ptr strea m_checksum.compare(*stream, filename, isBackupValid); } -void InMemoryStorageBackend::openDumpFileStream(std::shared_ptr stream, - const std::string &filename) { - stream->open(filename, std::ofstream::out | std::ofstream::trunc); - - if (!stream->is_open()) { - throw CannotCreateFileException(filename); - } -} - std::shared_ptr InMemoryStorageBackend::bucketStreamOpener( const PolicyBucketId &bucketId, const std::string &filenameSuffix, bool isBackupValid) { std::string bucketFilename = m_dbPath + m_bucketFilenamePrefix + bucketId + filenameSuffix; @@ -266,14 +264,15 @@ std::shared_ptr InMemoryStorageBackend::bucketStreamOpener( } } -std::shared_ptr > InMemoryStorageBackend::bucketDumpStreamOpener( - const PolicyBucketId &bucketId) { +std::shared_ptr > InMemoryStorageBackend::bucketDumpStreamOpener( + const PolicyBucketId &bucketId, const std::shared_ptr &chsStream) { std::string bucketFilename = m_dbPath + m_bucketFilenamePrefix + bucketId + m_backupFilenameSuffix; - auto bucketStream = std::make_shared(); + auto bucketStream = std::make_shared(m_bucketFilenamePrefix + bucketId, + chsStream); - openDumpFileStream(bucketStream, bucketFilename); - return std::make_shared >(bucketStream); + openDumpFileStream(bucketStream, bucketFilename); + return std::make_shared >(bucketStream); } void InMemoryStorageBackend::postLoadCleanup(bool isBackupValid) { diff --git a/src/storage/InMemoryStorageBackend.h b/src/storage/InMemoryStorageBackend.h index 65af96b..ea1f2bd 100644 --- a/src/storage/InMemoryStorageBackend.h +++ b/src/storage/InMemoryStorageBackend.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include +#include #include #include #include @@ -66,16 +68,18 @@ public: const PolicyKey &filter); protected: - void openFileStream(std::shared_ptr stream, const std::string &filename, + void dumpDatabase(const std::shared_ptr &chsStream); + void openFileStream(const std::shared_ptr &stream, const std::string &filename, bool isBackupValid); std::shared_ptr bucketStreamOpener(const PolicyBucketId &bucketId, const std::string &fileNameSuffix, bool isBackupValid); - virtual void openDumpFileStream(std::shared_ptr stream, - const std::string &filename); - std::shared_ptr > bucketDumpStreamOpener( - const PolicyBucketId &bucketId); + template + void openDumpFileStream(const std::shared_ptr &stream, + const std::string &filename); + std::shared_ptr > bucketDumpStreamOpener( + const PolicyBucketId &bucketId, const std::shared_ptr &chsStream); virtual void postLoadCleanup(bool isBackupValid); @@ -98,6 +102,16 @@ protected: } }; +template +void InMemoryStorageBackend::openDumpFileStream(const std::shared_ptr &stream, + const std::string &filename) { + stream->open(filename, std::ofstream::out | std::ofstream::trunc); + + if (!stream->is_open()) { + throw CannotCreateFileException(filename); + } +} + } /* namespace Cynara */ #endif /* SRC_STORAGE_INMEMORYSTORAGEBACKEND_H_ */ -- 2.7.4 From d760937d27e7c88fd61796465544810b0bdfb799 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Wed, 4 Feb 2015 15:05:30 +0100 Subject: [PATCH 08/16] Prepare service for database corruption handling When database corruption is detected, no administrative actions are allowed and all responses to check requests are DENY. Administrative API has to be informed about detected corruption. This patch modifies protocol so that this information is passed. Unit tests are also adjusted to the protocol changes this patch introduces. Change-Id: If3ab5d6ca1671167890956b986a4768cc828f3f5 --- src/common/protocol/ProtocolAdmin.cpp | 57 ++++++--- src/common/response/AdminCheckResponse.h | 13 +- src/common/response/CodeResponse.h | 4 +- src/common/response/DescriptionListResponse.h | 12 +- src/common/response/ListResponse.h | 13 +- src/service/logic/Logic.cpp | 134 +++++++++++++-------- src/service/logic/Logic.h | 2 + test/common/protocols/admin/admincheckresponse.cpp | 72 ++++++++--- .../protocols/admin/descriptionlistresponse.cpp | 69 ++++++++--- test/common/protocols/admin/listresponse.cpp | 76 ++++++++---- 10 files changed, 320 insertions(+), 132 deletions(-) diff --git a/src/common/protocol/ProtocolAdmin.cpp b/src/common/protocol/ProtocolAdmin.cpp index 238374b..35eedd8 100644 --- a/src/common/protocol/ProtocolAdmin.cpp +++ b/src/common/protocol/ProtocolAdmin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ * @file src/common/protocol/ProtocolAdmin.cpp * @author Lukasz Wojciechowski * @author Adam Malinowski + * @author Pawel Wieczorek * @version 1.0 * @brief This file implements protocol class for administration */ @@ -233,17 +234,20 @@ ResponsePtr ProtocolAdmin::deserializeAdminCheckResponse(void) { PolicyType result; PolicyResult::PolicyMetadata additionalInfo; bool bucketValid; + bool dbCorrupted; ProtocolDeserialization::deserialize(m_frameHeader, result); ProtocolDeserialization::deserialize(m_frameHeader, additionalInfo); ProtocolDeserialization::deserialize(m_frameHeader, bucketValid); + ProtocolDeserialization::deserialize(m_frameHeader, dbCorrupted); const PolicyResult policyResult(result, additionalInfo); - LOGD("Deserialized AdminCheckResponse: result [%" PRIu16 "], metadata <%s>, bucketValid [%d]", - policyResult.policyType(), policyResult.metadata().c_str(), static_cast(bucketValid)); + LOGD("Deserialized AdminCheckResponse: result [%" PRIu16 "], metadata <%s>, bucketValid [%d], " + "dbCorrupted [%d]", policyResult.policyType(), policyResult.metadata().c_str(), + static_cast(bucketValid), static_cast(dbCorrupted)); - return std::make_shared(policyResult, bucketValid, + return std::make_shared(policyResult, bucketValid, dbCorrupted, m_frameHeader.sequenceNumber()); } @@ -269,10 +273,14 @@ ResponsePtr ProtocolAdmin::deserializeDescriptionListResponse(void) { ProtocolDeserialization::deserialize(m_frameHeader, descriptions[fields].name); } - LOGD("Deserialized DescriptionListResponse: number of descriptions [%" PRIu16 "]", - descriptionsCount); + bool dbCorrupted; + ProtocolDeserialization::deserialize(m_frameHeader, dbCorrupted); - return std::make_shared(descriptions, m_frameHeader.sequenceNumber()); + LOGD("Deserialized DescriptionListResponse: number of descriptions [%" PRIu16 "], " + "dbCorrupted [%d]", descriptionsCount, static_cast(dbCorrupted)); + + return std::make_shared(descriptions, dbCorrupted, + m_frameHeader.sequenceNumber()); } ResponsePtr ProtocolAdmin::deserializeListResponse(void) { @@ -298,13 +306,18 @@ ResponsePtr ProtocolAdmin::deserializeListResponse(void) { PolicyResult(policyType, metadata))); } - bool isBucketValid; - ProtocolDeserialization::deserialize(m_frameHeader, isBucketValid); + bool bucketValid; + bool dbCorrupted; + ProtocolDeserialization::deserialize(m_frameHeader, bucketValid); + ProtocolDeserialization::deserialize(m_frameHeader, dbCorrupted); + + LOGD("Deserialized ListResponse: number of policies [%" PRIu16 "], bucketValid [%d], " + "dbCorrupted [%d]", policiesCount, static_cast(bucketValid), + static_cast(dbCorrupted)); - LOGD("Deserialized ListResponse: number of policies [%" PRIu16 "], isBucketValid [%d]", - policiesCount, isBucketValid); + return std::make_shared(policies, bucketValid, dbCorrupted, + m_frameHeader.sequenceNumber()); - return std::make_shared(policies, isBucketValid, m_frameHeader.sequenceNumber()); } ResponsePtr ProtocolAdmin::extractResponseFromBuffer(BinaryQueuePtr bufferQueue) { @@ -471,9 +484,10 @@ void ProtocolAdmin::execute(RequestContextPtr context, SetPoliciesRequestPtr req void ProtocolAdmin::execute(RequestContextPtr context, AdminCheckResponsePtr response) { LOGD("Serializing AdminCheckResponse: op [%" PRIu8 "], sequenceNumber [%" PRIu16 "], " - "policyType [%" PRIu16 "], metadata <%s>, bucketValid [%d]", OpAdminCheckPolicyResponse, - response->sequenceNumber(), response->result().policyType(), - response->result().metadata().c_str(), static_cast(response->isBucketValid())); + "policyType [%" PRIu16 "], metadata <%s>, bucketValid [%d], dbCorrupted [%d]", + OpAdminCheckPolicyResponse, response->sequenceNumber(), response->result().policyType(), + response->result().metadata().c_str(), static_cast(response->isBucketValid()), + static_cast(response->isDbCorrupted())); ProtocolFrame frame = ProtocolFrameSerializer::startSerialization( response->sequenceNumber()); @@ -482,6 +496,7 @@ void ProtocolAdmin::execute(RequestContextPtr context, AdminCheckResponsePtr res ProtocolSerialization::serialize(frame, response->result().policyType()); ProtocolSerialization::serialize(frame, response->result().metadata()); ProtocolSerialization::serialize(frame, response->isBucketValid()); + ProtocolSerialization::serialize(frame, response->isDbCorrupted()); ProtocolFrameSerializer::finishSerialization(frame, *(context->responseQueue())); } @@ -504,8 +519,8 @@ void ProtocolAdmin::execute(RequestContextPtr context, DescriptionListResponsePt = static_cast(response->descriptions().size()); LOGD("Serializing DescriptionListResponse: op [%" PRIu8 "], sequenceNumber [%" PRIu16 "], " - "number of descriptions [%" PRIu16 "]", OpDescriptionListResponse, - response->sequenceNumber(), descriptionsSize); + "number of descriptions [%" PRIu16 "], dbCorrupted [%d]", OpDescriptionListResponse, + response->sequenceNumber(), descriptionsSize, static_cast(response->isDbCorrupted())); ProtocolFrame frame = ProtocolFrameSerializer::startSerialization(response->sequenceNumber()); @@ -515,6 +530,8 @@ void ProtocolAdmin::execute(RequestContextPtr context, DescriptionListResponsePt ProtocolSerialization::serialize(frame, desc.type); ProtocolSerialization::serialize(frame, desc.name); } + ProtocolSerialization::serialize(frame, response->isDbCorrupted()); + ProtocolFrameSerializer::finishSerialization(frame, *(context->responseQueue())); } @@ -523,8 +540,9 @@ void ProtocolAdmin::execute(RequestContextPtr context, ListResponsePtr response) = static_cast(response->policies().size()); LOGD("Serializing ListResponse: op [%" PRIu8 "], sequenceNumber [%" PRIu16 "], " - "number of policies [%" PRIu16 "], isBucketValid [%d]", OpListResponse, - response->sequenceNumber(), policiesSize, response->isBucketValid()); + "number of policies [%" PRIu16 "], bucketValid [%d], dbCorrupted [%d]", OpListResponse, + response->sequenceNumber(), policiesSize, static_cast(response->isBucketValid()), + static_cast(response->isDbCorrupted())); ProtocolFrame frame = ProtocolFrameSerializer::startSerialization(response->sequenceNumber()); @@ -540,6 +558,7 @@ void ProtocolAdmin::execute(RequestContextPtr context, ListResponsePtr response) ProtocolSerialization::serialize(frame, policy.result().metadata()); } ProtocolSerialization::serialize(frame, response->isBucketValid()); + ProtocolSerialization::serialize(frame, response->isDbCorrupted()); ProtocolFrameSerializer::finishSerialization(frame, *(context->responseQueue())); } diff --git a/src/common/response/AdminCheckResponse.h b/src/common/response/AdminCheckResponse.h index c2bbf30..d553fd9 100644 --- a/src/common/response/AdminCheckResponse.h +++ b/src/common/response/AdminCheckResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ /** * @file src/common/response/AdminCheckResponse.h * @author Lukasz Wojciechowski + * @author Pawel Wieczorek * @version 1.0 * @brief This file defines response class for admin check request */ @@ -33,9 +34,10 @@ namespace Cynara { class AdminCheckResponse : public Response { public: - AdminCheckResponse(const PolicyResult &result, bool bucketValid, + AdminCheckResponse(const PolicyResult &result, bool bucketValid, bool dbCorrupted, ProtocolFrameSequenceNumber sequenceNumber) : - Response(sequenceNumber), m_result(result), m_bucketValid(bucketValid) { + Response(sequenceNumber), m_result(result), m_bucketValid(bucketValid), + m_dbCorrupted(dbCorrupted) { } virtual ~AdminCheckResponse() {} @@ -51,9 +53,14 @@ public: return m_bucketValid; } + bool isDbCorrupted(void) const { + return m_dbCorrupted; + } + private: const PolicyResult m_result; bool m_bucketValid; + bool m_dbCorrupted; }; } // namespace Cynara diff --git a/src/common/response/CodeResponse.h b/src/common/response/CodeResponse.h index f5790f4..78b21c1 100644 --- a/src/common/response/CodeResponse.h +++ b/src/common/response/CodeResponse.h @@ -16,6 +16,7 @@ /** * @file src/common/response/CodeResponse.h * @author Lukasz Wojciechowski + * @author Pawel Wieczorek * @version 1.0 * @brief This file defines class for responding to a request with a code */ @@ -36,7 +37,8 @@ public: NO_BUCKET, NO_POLICY_TYPE, NOT_ALLOWED, - FAILED + FAILED, + DB_CORRUPTED }; const Code m_code; diff --git a/src/common/response/DescriptionListResponse.h b/src/common/response/DescriptionListResponse.h index a963775..310ee63 100644 --- a/src/common/response/DescriptionListResponse.h +++ b/src/common/response/DescriptionListResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ /** * @file src/common/response/DescriptionListResponse.h * @author Zofia Abramowska + * @author Pawel Wieczorek * @version 1.0 * @brief This file defines response class for plugins description list response */ @@ -34,21 +35,26 @@ namespace Cynara { class DescriptionListResponse : public Response { public: - DescriptionListResponse(const std::vector &descriptions, + DescriptionListResponse(const std::vector &descriptions, bool dbCorrupted, ProtocolFrameSequenceNumber sequenceNumber) : - Response(sequenceNumber), m_descriptions(descriptions) { + Response(sequenceNumber), m_descriptions(descriptions), m_dbCorrupted(dbCorrupted) { } virtual ~DescriptionListResponse() {}; virtual void execute(ResponsePtr self, ResponseTakerPtr taker, RequestContextPtr context) const; + bool isDbCorrupted(void) const { + return m_dbCorrupted; + } + const std::vector &descriptions(void) const { return m_descriptions; } private: std::vector m_descriptions; + bool m_dbCorrupted; }; } // namespace Cynara diff --git a/src/common/response/ListResponse.h b/src/common/response/ListResponse.h index ec52736..2a67225 100644 --- a/src/common/response/ListResponse.h +++ b/src/common/response/ListResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ /** * @file src/common/response/ListResponse.h * @author Lukasz Wojciechowski + * @author Pawel Wieczorek * @version 1.0 * @brief This file defines response class for policies list request */ @@ -35,9 +36,10 @@ namespace Cynara { class ListResponse : public Response { public: - ListResponse(const std::vector &policies, bool bucketValid, + ListResponse(const std::vector &policies, bool bucketValid, bool dbCorrupted, ProtocolFrameSequenceNumber sequenceNumber) : - Response(sequenceNumber), m_policies(policies), m_bucketValid(bucketValid) { + Response(sequenceNumber), m_policies(policies), m_bucketValid(bucketValid), + m_dbCorrupted(dbCorrupted) { } virtual ~ListResponse() {}; @@ -48,6 +50,10 @@ public: return m_bucketValid; } + bool isDbCorrupted(void) const { + return m_dbCorrupted; + } + const std::vector &policies(void) const { return m_policies; } @@ -55,6 +61,7 @@ public: private: std::vector m_policies; bool m_bucketValid; + bool m_dbCorrupted; }; } // namespace Cynara diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index 6a1bece..a6e3c12 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -17,6 +17,7 @@ * @file src/service/logic/Logic.cpp * @author Lukasz Wojciechowski * @author Zofia Abramowska + * @author Pawel Wieczorek * @version 1.0 * @brief This file implements main class of logic layer in cynara service */ @@ -76,7 +77,7 @@ namespace Cynara { -Logic::Logic() { +Logic::Logic() : m_dbCorrupted(false) { } Logic::~Logic() { @@ -96,15 +97,20 @@ void Logic::execute(RequestContextPtr context UNUSED, SignalRequestPtr request) void Logic::execute(RequestContextPtr context, AdminCheckRequestPtr request) { PolicyResult result; bool bucketValid = true; - try { - result = m_storage->checkPolicy(request->key(), request->startBucket(), - request->recursive()); - } catch (const BucketNotExistsException &ex) { + + if (m_dbCorrupted) { bucketValid = false; + } else { + try { + result = m_storage->checkPolicy(request->key(), request->startBucket(), + request->recursive()); + } catch (const BucketNotExistsException &ex) { + bucketValid = false; + } } context->returnResponse(context, std::make_shared(result, bucketValid, - request->sequenceNumber())); + m_dbCorrupted, request->sequenceNumber())); } void Logic::execute(RequestContextPtr context, AgentActionRequestPtr request) { @@ -183,7 +189,7 @@ bool Logic::check(const RequestContextPtr &context, const PolicyKey &key, return false; } - result = m_storage->checkPolicy(key); + result = (m_dbCorrupted ? PredefinedPolicyType::DENY : m_storage->checkPolicy(key)); switch (result.policyType()) { case PredefinedPolicyType::ALLOW : @@ -286,19 +292,23 @@ void Logic::execute(RequestContextPtr context, DescriptionListRequestPtr request descriptions.insert(descriptions.begin(), predefinedPolicyDescr.begin(), predefinedPolicyDescr.end()); context->returnResponse(context, std::make_shared(descriptions, - request->sequenceNumber())); + m_dbCorrupted, request->sequenceNumber())); } void Logic::execute(RequestContextPtr context, EraseRequestPtr request) { auto code = CodeResponse::Code::OK; - try { - m_storage->erasePolicies(request->startBucket(), request->recursive(), request->filter()); - onPoliciesChanged(); - } catch (const DatabaseException &ex) { - code = CodeResponse::Code::FAILED; - } catch (const BucketNotExistsException &ex) { - code = CodeResponse::Code::NO_BUCKET; + if (m_dbCorrupted) { + code = CodeResponse::Code::DB_CORRUPTED; + } else { + try { + m_storage->erasePolicies(request->startBucket(), request->recursive(), request->filter()); + onPoliciesChanged(); + } catch (const DatabaseException &ex) { + code = CodeResponse::Code::FAILED; + } catch (const BucketNotExistsException &ex) { + code = CodeResponse::Code::NO_BUCKET; + } } context->returnResponse(context, std::make_shared(code, @@ -308,18 +318,22 @@ void Logic::execute(RequestContextPtr context, EraseRequestPtr request) { void Logic::execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request) { auto code = CodeResponse::Code::OK; - try { - checkSinglePolicyType(request->result().policyType(), true, true); - m_storage->addOrUpdateBucket(request->bucketId(), request->result()); - onPoliciesChanged(); - } catch (const DatabaseException &ex) { - code = CodeResponse::Code::FAILED; - } catch (const DefaultBucketSetNoneException &ex) { - code = CodeResponse::Code::NOT_ALLOWED; - } catch (const InvalidBucketIdException &ex) { - code = CodeResponse::Code::NOT_ALLOWED; - } catch (const UnknownPolicyTypeException &ex) { - code = CodeResponse::Code::NO_POLICY_TYPE; + if (m_dbCorrupted) { + code = CodeResponse::Code::DB_CORRUPTED; + } else { + try { + checkSinglePolicyType(request->result().policyType(), true, true); + m_storage->addOrUpdateBucket(request->bucketId(), request->result()); + onPoliciesChanged(); + } catch (const DatabaseException &ex) { + code = CodeResponse::Code::FAILED; + } catch (const DefaultBucketSetNoneException &ex) { + code = CodeResponse::Code::NOT_ALLOWED; + } catch (const InvalidBucketIdException &ex) { + code = CodeResponse::Code::NOT_ALLOWED; + } catch (const UnknownPolicyTypeException &ex) { + code = CodeResponse::Code::NO_POLICY_TYPE; + } } context->returnResponse(context, std::make_shared(code, @@ -328,48 +342,64 @@ void Logic::execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr re void Logic::execute(RequestContextPtr context, ListRequestPtr request) { bool bucketValid = true; - std::vector policies; - try { - policies = m_storage->listPolicies(request->bucket(), request->filter()); - } catch (const BucketNotExistsException &ex) { + + if (m_dbCorrupted) { bucketValid = false; + } else { + try { + policies = m_storage->listPolicies(request->bucket(), request->filter()); + } catch (const BucketNotExistsException &ex) { + bucketValid = false; + } } context->returnResponse(context, std::make_shared(policies, bucketValid, - request->sequenceNumber())); + m_dbCorrupted, request->sequenceNumber())); } void Logic::execute(RequestContextPtr context, RemoveBucketRequestPtr request) { auto code = CodeResponse::Code::OK; - try { - m_storage->deleteBucket(request->bucketId()); - onPoliciesChanged(); - } catch (const DatabaseException &ex) { - code = CodeResponse::Code::FAILED; - } catch (const BucketNotExistsException &ex) { - code = CodeResponse::Code::NO_BUCKET; - } catch (const DefaultBucketDeletionException &ex) { - code = CodeResponse::Code::NOT_ALLOWED; + + if (m_dbCorrupted) { + code = CodeResponse::Code::DB_CORRUPTED; + } else { + try { + m_storage->deleteBucket(request->bucketId()); + onPoliciesChanged(); + } catch (const DatabaseException &ex) { + code = CodeResponse::Code::FAILED; + } catch (const BucketNotExistsException &ex) { + code = CodeResponse::Code::NO_BUCKET; + } catch (const DefaultBucketDeletionException &ex) { + code = CodeResponse::Code::NOT_ALLOWED; + } } + context->returnResponse(context, std::make_shared(code, request->sequenceNumber())); } void Logic::execute(RequestContextPtr context, SetPoliciesRequestPtr request) { auto code = CodeResponse::Code::OK; - try { - checkPoliciesTypes(request->policiesToBeInsertedOrUpdated(), true, false); - m_storage->insertPolicies(request->policiesToBeInsertedOrUpdated()); - m_storage->deletePolicies(request->policiesToBeRemoved()); - onPoliciesChanged(); - } catch (const DatabaseException &ex) { - code = CodeResponse::Code::FAILED; - } catch (const BucketNotExistsException &ex) { - code = CodeResponse::Code::NO_BUCKET; - } catch (const UnknownPolicyTypeException &ex) { - code = CodeResponse::Code::NO_POLICY_TYPE; + + if (m_dbCorrupted) { + code = CodeResponse::Code::DB_CORRUPTED; + } else { + try { + checkPoliciesTypes(request->policiesToBeInsertedOrUpdated(), true, false); + m_storage->insertPolicies(request->policiesToBeInsertedOrUpdated()); + m_storage->deletePolicies(request->policiesToBeRemoved()); + onPoliciesChanged(); + } catch (const DatabaseException &ex) { + code = CodeResponse::Code::FAILED; + } catch (const BucketNotExistsException &ex) { + code = CodeResponse::Code::NO_BUCKET; + } catch (const UnknownPolicyTypeException &ex) { + code = CodeResponse::Code::NO_POLICY_TYPE; + } } + context->returnResponse(context, std::make_shared(code, request->sequenceNumber())); } diff --git a/src/service/logic/Logic.h b/src/service/logic/Logic.h index 2a4ff8a..3e8ee8c 100644 --- a/src/service/logic/Logic.h +++ b/src/service/logic/Logic.h @@ -17,6 +17,7 @@ * @file src/service/logic/Logic.h * @author Lukasz Wojciechowski * @author Zofia Abramowska + * @author Pawel Wieczorek * @version 1.0 * @brief This file defines main class of logic layer in cynara service */ @@ -95,6 +96,7 @@ private: StoragePtr m_storage; SocketManagerPtr m_socketManager; AuditLog m_auditLog; + bool m_dbCorrupted; bool check(const RequestContextPtr &context, const PolicyKey &key, ProtocolFrameSequenceNumber checkId, PolicyResult &result); diff --git a/test/common/protocols/admin/admincheckresponse.cpp b/test/common/protocols/admin/admincheckresponse.cpp index 666f65e..5aa2386 100644 --- a/test/common/protocols/admin/admincheckresponse.cpp +++ b/test/common/protocols/admin/admincheckresponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ /** * @file test/common/protocols/admin/admincheckresponse.cpp * @author Lukasz Wojciechowski + * @author Pawel Wieczorek * @version 1.0 * @brief Tests for Cynara::AdminCheckResponse usage in Cynara::ProtocolAdmin */ @@ -34,10 +35,13 @@ template<> void compare(const Cynara::AdminCheckResponse &resp1, const Cynara::AdminCheckResponse &resp2) { EXPECT_EQ(resp1.result(), resp2.result()); EXPECT_EQ(resp1.isBucketValid(), resp2.isBucketValid()); + EXPECT_EQ(resp1.isDbCorrupted(), resp2.isDbCorrupted()); } static const bool VALID_BUCKET = true; static const bool NO_BUCKET = false; +static const bool DB_OK = false; +static const bool DB_CORRUPTED = true; } /* anonymous namespace */ @@ -48,19 +52,21 @@ using namespace TestDataCollection; /* *** compare by objects test cases *** */ TEST(ProtocolAdmin, AdminCheckResponse01) { - auto response = std::make_shared(Results::allow, VALID_BUCKET, SN::min); + auto response = std::make_shared(Results::allow, VALID_BUCKET, DB_OK, + SN::min); auto protocol = std::make_shared(); testResponse(response, protocol); } TEST(ProtocolAdmin, AdminCheckResponse02) { - auto response = std::make_shared(Results::deny, NO_BUCKET, SN::min_1); + auto response = std::make_shared(Results::deny, NO_BUCKET, DB_OK, + SN::min_1); auto protocol = std::make_shared(); testResponse(response, protocol); } TEST(ProtocolAdmin, AdminCheckResponse03) { - auto response = std::make_shared(Results::bucket_empty, VALID_BUCKET, + auto response = std::make_shared(Results::bucket_empty, VALID_BUCKET, DB_OK, SN::min_2); auto protocol = std::make_shared(); testResponse(response, protocol); @@ -68,25 +74,42 @@ TEST(ProtocolAdmin, AdminCheckResponse03) { TEST(ProtocolAdmin, AdminCheckResponse04) { auto response = std::make_shared(Results::bucket_not_empty, NO_BUCKET, - SN::max); + DB_OK, SN::max); auto protocol = std::make_shared(); testResponse(response, protocol); } TEST(ProtocolAdmin, AdminCheckResponse05) { - auto response = std::make_shared(Results::none, VALID_BUCKET, SN::max_1); + auto response = std::make_shared(Results::none, VALID_BUCKET, DB_OK, + SN::max_1); auto protocol = std::make_shared(); testResponse(response, protocol); } TEST(ProtocolAdmin, AdminCheckResponse06) { - auto response = std::make_shared(Results::plugin_1, NO_BUCKET, SN::max_2); + auto response = std::make_shared(Results::plugin_1, NO_BUCKET, DB_OK, + SN::max_2); auto protocol = std::make_shared(); testResponse(response, protocol); } TEST(ProtocolAdmin, AdminCheckResponse07) { - auto response = std::make_shared(Results::plugin_2, VALID_BUCKET, SN::mid); + auto response = std::make_shared(Results::plugin_2, VALID_BUCKET, DB_OK, + SN::mid); + auto protocol = std::make_shared(); + testResponse(response, protocol); +} + +/** + * @brief Verify if AdminCheckResponse is properly (de)serialized while database is corrupted + * @test Expected result: + * - PolicyResult set to DENY + * - bucketValid flag set to false (NO_BUCKET) + * - dbCorrupted flag set to true (DB_CORRUPTED) + */ +TEST(ProtocolAdmin, AdminCheckResponse08) { + auto response = std::make_shared(Results::deny, NO_BUCKET, DB_CORRUPTED, + SN::max); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -94,19 +117,21 @@ TEST(ProtocolAdmin, AdminCheckResponse07) { /* *** compare by serialized data test cases *** */ TEST(ProtocolAdmin, AdminCheckResponseBinary01) { - auto response = std::make_shared(Results::allow, VALID_BUCKET, SN::min); + auto response = std::make_shared(Results::allow, VALID_BUCKET, DB_OK, + SN::min); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } TEST(ProtocolAdmin, AdminCheckResponseBinary02) { - auto response = std::make_shared(Results::deny, NO_BUCKET, SN::min_1); + auto response = std::make_shared(Results::deny, NO_BUCKET, DB_OK, + SN::min_1); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } TEST(ProtocolAdmin, AdminCheckResponseBinary03) { - auto response = std::make_shared(Results::bucket_empty, VALID_BUCKET, + auto response = std::make_shared(Results::bucket_empty, VALID_BUCKET, DB_OK, SN::min_2); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); @@ -114,25 +139,42 @@ TEST(ProtocolAdmin, AdminCheckResponseBinary03) { TEST(ProtocolAdmin, AdminCheckResponseBinary04) { auto response = std::make_shared(Results::bucket_not_empty, NO_BUCKET, - SN::max); + DB_OK, SN::max); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } TEST(ProtocolAdmin, AdminCheckResponseBinary05) { - auto response = std::make_shared(Results::none, VALID_BUCKET, SN::max_1); + auto response = std::make_shared(Results::none, VALID_BUCKET, DB_OK, + SN::max_1); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } TEST(ProtocolAdmin, AdminCheckResponseBinary06) { - auto response = std::make_shared(Results::plugin_1, NO_BUCKET, SN::max_2); + auto response = std::make_shared(Results::plugin_1, NO_BUCKET, DB_OK, + SN::max_2); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } TEST(ProtocolAdmin, AdminCheckResponseBinary07) { - auto response = std::make_shared(Results::plugin_2, VALID_BUCKET, SN::mid); + auto response = std::make_shared(Results::plugin_2, VALID_BUCKET, DB_OK, + SN::mid); + auto protocol = std::make_shared(); + binaryTestResponse(response, protocol); +} + +/** + * @brief Verify if AdminCheckResponse is properly (de)serialized while database is corrupted + * @test Expected result: + * - PolicyResult set to DENY + * - bucketValid flag set to false (NO_BUCKET) + * - dbCorrupted flag set to true (DB_CORRUPTED) + */ +TEST(ProtocolAdmin, AdminCheckResponseBinary08) { + auto response = std::make_shared(Results::deny, NO_BUCKET, DB_CORRUPTED, + SN::max); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } diff --git a/test/common/protocols/admin/descriptionlistresponse.cpp b/test/common/protocols/admin/descriptionlistresponse.cpp index 43acbaa..42e8bae 100644 --- a/test/common/protocols/admin/descriptionlistresponse.cpp +++ b/test/common/protocols/admin/descriptionlistresponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ /** * @file test/common/protocols/admin/descriptionlistresponse.cpp * @author Lukasz Wojciechowski + * @author Pawel Wieczorek * @version 1.0 * @brief Tests for Cynara::DescriptionListResponse usage in Cynara::ProtocolAdmin */ @@ -42,8 +43,12 @@ void compare(const Cynara::DescriptionListResponse &resp1, EXPECT_EQ(resp1.descriptions()[i].name, resp2.descriptions()[i].name); EXPECT_EQ(resp1.descriptions()[i].type, resp2.descriptions()[i].type); } + EXPECT_EQ(resp1.isDbCorrupted(), resp2.isDbCorrupted()); } +static const bool DB_OK = false; +static const bool DB_CORRUPTED = true; + } /* namespace anonymous */ using namespace Cynara; @@ -57,7 +62,7 @@ TEST(ProtocolAdmin, DescriptionListResponse01) { PolicyDescription(Types::allow, "allow"), }; - auto response = std::make_shared(descriptions, SN::min); + auto response = std::make_shared(descriptions, DB_OK, SN::min); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -67,7 +72,7 @@ TEST(ProtocolAdmin, DescriptionListResponse02) { PolicyDescription(Types::bucket, "bucket"), }; - auto response = std::make_shared(descriptions, SN::min_1); + auto response = std::make_shared(descriptions, DB_OK, SN::min_1); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -77,7 +82,7 @@ TEST(ProtocolAdmin, DescriptionListResponse03) { PolicyDescription(Types::deny, "deny"), }; - auto response = std::make_shared(descriptions, SN::max); + auto response = std::make_shared(descriptions, DB_OK, SN::max); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -87,7 +92,7 @@ TEST(ProtocolAdmin, DescriptionListResponse04) { PolicyDescription(Types::none, "none"), }; - auto response = std::make_shared(descriptions, SN::max_1); + auto response = std::make_shared(descriptions, DB_OK, SN::max_1); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -97,7 +102,7 @@ TEST(ProtocolAdmin, DescriptionListResponse05) { PolicyDescription(Types::plugin_type, "plugin"), }; - auto response = std::make_shared(descriptions, SN::mid); + auto response = std::make_shared(descriptions, DB_OK, SN::mid); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -113,7 +118,7 @@ TEST(ProtocolAdmin, DescriptionListResponseMultipleDescriptions) { PolicyDescription(Types::plugin_type, "plugin"), }; - auto response = std::make_shared(descriptions, SN::max_2); + auto response = std::make_shared(descriptions, DB_OK, SN::max_2); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -121,7 +126,24 @@ TEST(ProtocolAdmin, DescriptionListResponseMultipleDescriptions) { TEST(ProtocolAdmin, DescriptionListResponseEmptyDescriptions) { std::vector descriptions; - auto response = std::make_shared(descriptions, SN::min_2); + auto response = std::make_shared(descriptions, DB_OK, SN::min_2); + auto protocol = std::make_shared(); + testResponse(response, protocol); +} + +/** + * @brief Verify if DescriptionListResponse is properly (de)serialized while database is corrupted + * @test Expected result: + * - descriptions vector contains predefined policies ALLOW and DENY + * - dbCorrupted flag set to true (DB_CORRUPTED) + */ +TEST(ProtocolAdmin, DescriptionListResponseDatabaseCorrupted) { + std::vector descriptions = { + PolicyDescription(Types::allow, "allow"), + PolicyDescription(Types::bucket, "bucket"), + }; + + auto response = std::make_shared(descriptions, DB_CORRUPTED, SN::max); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -133,7 +155,7 @@ TEST(ProtocolAdmin, DescriptionListResponseBinary01) { PolicyDescription(Types::allow, "allow"), }; - auto response = std::make_shared(descriptions, SN::min); + auto response = std::make_shared(descriptions, DB_OK, SN::min); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -143,7 +165,7 @@ TEST(ProtocolAdmin, DescriptionListResponseBinary02) { PolicyDescription(Types::bucket, "bucket"), }; - auto response = std::make_shared(descriptions, SN::min_1); + auto response = std::make_shared(descriptions, DB_OK, SN::min_1); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -153,7 +175,7 @@ TEST(ProtocolAdmin, DescriptionListResponseBinary03) { PolicyDescription(Types::deny, "deny"), }; - auto response = std::make_shared(descriptions, SN::max); + auto response = std::make_shared(descriptions, DB_OK, SN::max); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -163,7 +185,7 @@ TEST(ProtocolAdmin, DescriptionListResponseBinary04) { PolicyDescription(Types::none, "none"), }; - auto response = std::make_shared(descriptions, SN::max_1); + auto response = std::make_shared(descriptions, DB_OK, SN::max_1); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -173,7 +195,7 @@ TEST(ProtocolAdmin, DescriptionListResponseBinary05) { PolicyDescription(Types::plugin_type, "plugin"), }; - auto response = std::make_shared(descriptions, SN::mid); + auto response = std::make_shared(descriptions, DB_OK, SN::mid); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -189,7 +211,7 @@ TEST(ProtocolAdmin, DescriptionListResponseBinaryMultipleDescriptions) { PolicyDescription(Types::plugin_type, "plugin"), }; - auto response = std::make_shared(descriptions, SN::max_2); + auto response = std::make_shared(descriptions, DB_OK, SN::max_2); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -197,7 +219,24 @@ TEST(ProtocolAdmin, DescriptionListResponseBinaryMultipleDescriptions) { TEST(ProtocolAdmin, DescriptionListResponseBinaryEmptyDescriptions) { std::vector descriptions; - auto response = std::make_shared(descriptions, SN::min_2); + auto response = std::make_shared(descriptions, DB_OK, SN::min_2); + auto protocol = std::make_shared(); + binaryTestResponse(response, protocol); +} + +/** + * @brief Verify if DescriptionListResponse is properly (de)serialized while database is corrupted + * @test Expected result: + * - descriptions vector contains predefined policies ALLOW and DENY + * - dbCorrupted flag set to true (DB_CORRUPTED) + */ +TEST(ProtocolAdmin, DescriptionListResponseBinaryDatabaseCorrupted) { + std::vector descriptions = { + PolicyDescription(Types::allow, "allow"), + PolicyDescription(Types::bucket, "bucket"), + }; + + auto response = std::make_shared(descriptions, DB_CORRUPTED, SN::max); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } diff --git a/test/common/protocols/admin/listresponse.cpp b/test/common/protocols/admin/listresponse.cpp index fddd2ca..67ea03d 100644 --- a/test/common/protocols/admin/listresponse.cpp +++ b/test/common/protocols/admin/listresponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ /** * @file test/common/protocols/admin/listresponse.cpp * @author Lukasz Wojciechowski + * @author Pawel Wieczorek * @version 1.0 * @brief Tests for Cynara::ListResponse usage in Cynara::ProtocolAdmin */ @@ -37,10 +38,13 @@ template<> void compare(const Cynara::ListResponse &resp1, const Cynara::ListResponse &resp2) { EXPECT_EQ(resp1.policies(), resp2.policies()); EXPECT_EQ(resp1.isBucketValid(), resp2.isBucketValid()); + EXPECT_EQ(resp1.isDbCorrupted(), resp2.isDbCorrupted()); } static const bool VALID_BUCKET = true; static const bool NO_BUCKET = false; +static const bool DB_OK = false; +static const bool DB_CORRUPTED = true; } /* namespace anonymous */ @@ -55,7 +59,7 @@ TEST(ProtocolAdmin, ListResponse01) { Policy(Keys::k_nun, Results::allow), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::min); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::min); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -65,7 +69,7 @@ TEST(ProtocolAdmin, ListResponse02) { Policy(Keys::k_cup, Results::deny), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::min_1); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::min_1); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -75,7 +79,7 @@ TEST(ProtocolAdmin, ListResponse03) { Policy(Keys::k_www, Results::bucket_empty), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::min_2); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::min_2); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -85,7 +89,7 @@ TEST(ProtocolAdmin, ListResponse04) { Policy(Keys::k_wuw, Results::bucket_not_empty), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::max); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::max); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -95,7 +99,7 @@ TEST(ProtocolAdmin, ListResponse05) { Policy(Keys::k_aaa, Results::none), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::max_1); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::max_1); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -105,7 +109,7 @@ TEST(ProtocolAdmin, ListResponse06) { Policy(Keys::k_wua, Results::plugin_1), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::max_2); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::max_2); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -115,7 +119,7 @@ TEST(ProtocolAdmin, ListResponse07) { Policy(Keys::k_nua, Results::plugin_2), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::mid); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::mid); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -131,7 +135,7 @@ TEST(ProtocolAdmin, ListResponseMultiplePolicies) { Policy(Keys::k_nua, Results::plugin_2), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::min); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::min); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -139,7 +143,7 @@ TEST(ProtocolAdmin, ListResponseMultiplePolicies) { TEST(ProtocolAdmin, ListResponseEmptyPolicies) { std::vector policies; - auto response = std::make_shared(policies, VALID_BUCKET, SN::min_1); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::min_1); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -147,7 +151,22 @@ TEST(ProtocolAdmin, ListResponseEmptyPolicies) { TEST(ProtocolAdmin, ListResponseNoBucket) { std::vector policies; - auto response = std::make_shared(policies, NO_BUCKET, SN::min_2); + auto response = std::make_shared(policies, NO_BUCKET, DB_OK, SN::min_2); + auto protocol = std::make_shared(); + testResponse(response, protocol); +} + +/** + * @brief Verify if ListResponse is properly (de)serialized while database is corrupted + * @test Expected result: + * - policies vector is empty + * - bucketValid flag set to false (NO_BUCKET) + * - dbCorrupted flag set to true (DB_CORRUPTED) + */ +TEST(ProtocolAdmin, ListResponseDatabaseCorrupted) { + std::vector policies; + + auto response = std::make_shared(policies, NO_BUCKET, DB_CORRUPTED, SN::max); auto protocol = std::make_shared(); testResponse(response, protocol); } @@ -159,7 +178,7 @@ TEST(ProtocolAdmin, ListResponseBinary01) { Policy(Keys::k_nun, Results::allow), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::min); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::min); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -169,7 +188,7 @@ TEST(ProtocolAdmin, ListResponseBinary02) { Policy(Keys::k_cup, Results::deny), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::min_1); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::min_1); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -179,7 +198,7 @@ TEST(ProtocolAdmin, ListResponseBinary03) { Policy(Keys::k_www, Results::bucket_empty), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::min_2); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::min_2); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -189,7 +208,7 @@ TEST(ProtocolAdmin, ListResponseBinary04) { Policy(Keys::k_wuw, Results::bucket_not_empty), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::max); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::max); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -199,7 +218,7 @@ TEST(ProtocolAdmin, ListResponseBinary05) { Policy(Keys::k_aaa, Results::none), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::max_1); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::max_1); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -209,7 +228,7 @@ TEST(ProtocolAdmin, ListResponseBinary06) { Policy(Keys::k_wua, Results::plugin_1), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::max_2); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::max_2); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -219,7 +238,7 @@ TEST(ProtocolAdmin, ListResponseBinary07) { Policy(Keys::k_nua, Results::plugin_2), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::mid); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::mid); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -235,7 +254,7 @@ TEST(ProtocolAdmin, ListResponseBinaryMultiplePolicies) { Policy(Keys::k_nua, Results::plugin_2), }; - auto response = std::make_shared(policies, VALID_BUCKET, SN::min); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::min); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -243,7 +262,7 @@ TEST(ProtocolAdmin, ListResponseBinaryMultiplePolicies) { TEST(ProtocolAdmin, ListResponseBinaryEmptyPolicies) { std::vector policies; - auto response = std::make_shared(policies, VALID_BUCKET, SN::min_1); + auto response = std::make_shared(policies, VALID_BUCKET, DB_OK, SN::min_1); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } @@ -251,7 +270,22 @@ TEST(ProtocolAdmin, ListResponseBinaryEmptyPolicies) { TEST(ProtocolAdmin, ListResponseBinaryNoBucket) { std::vector policies; - auto response = std::make_shared(policies, NO_BUCKET, SN::min_2); + auto response = std::make_shared(policies, NO_BUCKET, DB_OK, SN::min_2); + auto protocol = std::make_shared(); + binaryTestResponse(response, protocol); +} + +/** + * @brief Verify if ListResponse is properly (de)serialized while database is corrupted + * @test Expected result: + * - policies vector is empty + * - bucketValid flag set to false (NO_BUCKET) + * - dbCorrupted flag set to true (DB_CORRUPTED) + */ +TEST(ProtocolAdmin, ListResponseBinaryDatabaseCorrupted) { + std::vector policies; + + auto response = std::make_shared(policies, NO_BUCKET, DB_CORRUPTED, SN::max); auto protocol = std::make_shared(); binaryTestResponse(response, protocol); } -- 2.7.4 From afb5c6f014f2d5b8250b0d0b65377eb8a3fca67c Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Tue, 3 Mar 2015 12:35:48 +0100 Subject: [PATCH 09/16] Handle information about database corruption DatabaseCorruptedException will be thrown to inform about database corruption. This may be handled directly (OfflineLogic) or through responses returned from service logic (OnlineLogic). In both cases proper error code should be returned: CYNARA_API_DATABASE_CORRUPTED (introduced in this patch). Change-Id: Idbafcf241c6689dadd3c5a7f25adc4629ea7cffd --- src/admin/logic/OfflineLogic.cpp | 14 +++++++ src/admin/logic/OnlineLogic.cpp | 19 +++++++++ src/common/error/api.cpp | 3 ++ src/common/exceptions/DatabaseCorruptedException.h | 47 ++++++++++++++++++++++ src/include/cynara-error.h | 3 ++ 5 files changed, 86 insertions(+) create mode 100644 src/common/exceptions/DatabaseCorruptedException.h diff --git a/src/admin/logic/OfflineLogic.cpp b/src/admin/logic/OfflineLogic.cpp index 2a7bc89..98721bc 100644 --- a/src/admin/logic/OfflineLogic.cpp +++ b/src/admin/logic/OfflineLogic.cpp @@ -17,6 +17,7 @@ * @file src/admin/logic/OfflineLogic.cpp * @author Aleksander Zdyb * @author Lukasz Wojciechowski + * @author Pawel Wieczorek * @version 1.0 * @brief This file contains implementation of OfflineLogic class */ @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -90,6 +92,8 @@ int OfflineLogic::setPolicies(const ApiInterface::PoliciesByBucket &insertOrUpda return CYNARA_API_BUCKET_NOT_FOUND; } catch (const DatabaseException &) { return CYNARA_API_OPERATION_FAILED; + } catch (const DatabaseCorruptedException &) { + return CYNARA_API_DATABASE_CORRUPTED; } catch (const UnknownPolicyTypeException &ex) { return CYNARA_API_INVALID_PARAM; } @@ -111,6 +115,8 @@ int OfflineLogic::insertOrUpdateBucket(const PolicyBucketId &bucket, return CYNARA_API_OPERATION_NOT_ALLOWED; } catch (const DatabaseException &) { return CYNARA_API_OPERATION_FAILED; + } catch (const DatabaseCorruptedException &) { + return CYNARA_API_DATABASE_CORRUPTED; } catch (const UnknownPolicyTypeException &ex) { return CYNARA_API_INVALID_PARAM; } @@ -129,6 +135,8 @@ int OfflineLogic::removeBucket(const PolicyBucketId &bucket) { return CYNARA_API_OPERATION_NOT_ALLOWED; } catch (const DatabaseException &) { return CYNARA_API_OPERATION_FAILED; + } catch (const DatabaseCorruptedException &) { + return CYNARA_API_DATABASE_CORRUPTED; } return CYNARA_API_SUCCESS; @@ -141,6 +149,8 @@ int OfflineLogic::adminCheck(const PolicyBucketId &startBucket, bool recursive, result = m_storage->checkPolicy(key, startBucket, recursive); } catch (const BucketNotExistsException &ex) { return CYNARA_API_BUCKET_NOT_FOUND; + } catch (const DatabaseCorruptedException &) { + return CYNARA_API_DATABASE_CORRUPTED; } return CYNARA_API_SUCCESS; @@ -161,6 +171,8 @@ int OfflineLogic::listPolicies(const PolicyBucketId &bucket, const PolicyKey &fi policies = m_storage->listPolicies(bucket, filter); } catch (const BucketNotExistsException &ex) { return CYNARA_API_BUCKET_NOT_FOUND; + } catch (const DatabaseCorruptedException &) { + return CYNARA_API_DATABASE_CORRUPTED; } return CYNARA_API_SUCCESS; @@ -174,6 +186,8 @@ int OfflineLogic::erasePolicies(const PolicyBucketId &startBucket, bool recursiv onPoliciesChanged(); } catch (const BucketNotExistsException &) { return CYNARA_API_BUCKET_NOT_FOUND; + } catch (const DatabaseCorruptedException &) { + return CYNARA_API_DATABASE_CORRUPTED; } return CYNARA_API_SUCCESS; diff --git a/src/admin/logic/OnlineLogic.cpp b/src/admin/logic/OnlineLogic.cpp index 9671111..e8964b0 100644 --- a/src/admin/logic/OnlineLogic.cpp +++ b/src/admin/logic/OnlineLogic.cpp @@ -18,6 +18,7 @@ * @author Lukasz Wojciechowski * @author Aleksander Zdyb * @author Zofia Abramowska + * @author Pawel Wieczorek * @version 1.0 * @brief This file contains implementation of online version of Logic class */ @@ -110,6 +111,9 @@ static int interpretCodeResponse(const CodeResponse::Code &code) { case CodeResponse::Code::FAILED: LOGC("Cynara service answered: Operation failed."); return CYNARA_API_OPERATION_FAILED; + case CodeResponse::Code::DB_CORRUPTED: + LOGC("Cynara service answered: Database is corrupted."); + return CYNARA_API_DATABASE_CORRUPTED; default: LOGE("Unexpected response code from server: [%d]", static_cast(code)); @@ -157,6 +161,11 @@ int OnlineLogic::adminCheck(const PolicyBucketId &startBucket, bool recursive, c return ret; } + if (adminCheckResponse->isDbCorrupted()) { + LOGC("Cynara service answered: Database is corrupted."); + return CYNARA_API_DATABASE_CORRUPTED; + } + LOGD("AdminCheckResponse: policyType [%" PRIu16 "], metadata <%s>, bucketValid [%d]", adminCheckResponse->result().policyType(), adminCheckResponse->result().metadata().c_str(), static_cast(adminCheckResponse->isBucketValid())); @@ -179,6 +188,11 @@ int OnlineLogic::listPolicies(const PolicyBucketId &bucket, const PolicyKey &fil return ret; } + if (listResponse->isDbCorrupted()) { + LOGC("Cynara service answered: Database is corrupted."); + return CYNARA_API_DATABASE_CORRUPTED; + } + LOGD("listResponse: number of policies [%zu], bucketValid [%d]", listResponse->policies().size(), listResponse->isBucketValid()); @@ -208,6 +222,11 @@ int OnlineLogic::listDescriptions(std::vector &descriptions) return ret; } + if (descrResponse->isDbCorrupted()) { + LOGC("Cynara service answered: Database is corrupted."); + return CYNARA_API_DATABASE_CORRUPTED; + } + LOGD("descriptionListResponse: number of plugin descriptions [%zu]", descrResponse->descriptions().size()); diff --git a/src/common/error/api.cpp b/src/common/error/api.cpp index d8243b4..802787c 100644 --- a/src/common/error/api.cpp +++ b/src/common/error/api.cpp @@ -82,6 +82,9 @@ int cynara_strerror(int errnum, char *buf, size_t buflen) { case CYNARA_API_BUFFER_TOO_SHORT: message = "Buffer too short"; break; + case CYNARA_API_DATABASE_CORRUPTED: + message = "Database corrupted"; + break; } if (message == nullptr) diff --git a/src/common/exceptions/DatabaseCorruptedException.h b/src/common/exceptions/DatabaseCorruptedException.h new file mode 100644 index 0000000..960125a --- /dev/null +++ b/src/common/exceptions/DatabaseCorruptedException.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ +/** + * @file src/common/exceptions/DatabaseCorruptedException.h + * @author Pawel Wieczorek + * @version 1.0 + * @brief Implementation of DatabaseCorruptedException + */ + +#ifndef SRC_COMMON_EXCEPTIONS_DATABASECORRUPTEDEXCEPTION_H_ +#define SRC_COMMON_EXCEPTIONS_DATABASECORRUPTEDEXCEPTION_H_ + +#include + +#include "Exception.h" + +namespace Cynara { + +class DatabaseCorruptedException : public Exception { +public: + DatabaseCorruptedException() : m_message("DatabaseCorruptedException") {} + virtual ~DatabaseCorruptedException() {}; + + virtual const std::string &message(void) const { + return m_message; + } + +private: + std::string m_message; +}; + +} /* namespace Cynara */ + +#endif /* SRC_COMMON_EXCEPTIONS_DATABASECORRUPTEDEXCEPTION_H_ */ diff --git a/src/include/cynara-error.h b/src/include/cynara-error.h index 875d877..988b462 100644 --- a/src/include/cynara-error.h +++ b/src/include/cynara-error.h @@ -84,6 +84,9 @@ /*! \brief indicating that provided buffer is too short */ #define CYNARA_API_BUFFER_TOO_SHORT -13 + +/*! \brief indicating that database is corrupted */ +#define CYNARA_API_DATABASE_CORRUPTED -14 /** @}*/ #ifdef __cplusplus -- 2.7.4 From f61768e10f54e40dda71834037155bd9a3b42a4b Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Tue, 3 Mar 2015 12:36:13 +0100 Subject: [PATCH 10/16] Handle database corruption Loading database from storage is now moved to logic layer. InMemoryStorageBackend throws DatabaseCorruptedException to trigger corrupted state toggle when database corruption is detected. Tests which involved database to enter corrupted state were updated. Change-Id: I0df8c38322b4478abb8c6d18c0805f97cfa45161 --- src/service/logic/Logic.cpp | 9 +++++++++ src/service/logic/Logic.h | 1 + src/service/main/Cynara.cpp | 6 ++++-- src/storage/InMemoryStorageBackend.cpp | 4 +++- .../inmemeorystoragebackendfixture.h | 7 +++++++ .../inmemorystoragebackend/inmemorystoragebackend.cpp | 19 +++++++------------ 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index a6e3c12..44fcd97 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -526,4 +527,12 @@ void Logic::handleClientDisconnection(const CheckContextPtr &checkContextPtr) { } } +void Logic::loadDb(void) { + try { + m_storage->load(); + } catch (const DatabaseCorruptedException &) { + m_dbCorrupted = true; + } +} + } // namespace Cynara diff --git a/src/service/logic/Logic.h b/src/service/logic/Logic.h index 3e8ee8c..4f95d30 100644 --- a/src/service/logic/Logic.h +++ b/src/service/logic/Logic.h @@ -88,6 +88,7 @@ public: virtual void execute(RequestContextPtr context, SimpleCheckRequestPtr request); virtual void contextClosed(RequestContextPtr context); + virtual void loadDb(void); private: AgentManagerPtr m_agentManager; diff --git a/src/service/main/Cynara.cpp b/src/service/main/Cynara.cpp index 15ebd99..d43e4a4 100644 --- a/src/service/main/Cynara.cpp +++ b/src/service/main/Cynara.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ * @file src/service/main/Cynara.cpp * @author Lukasz Wojciechowski * @author Aleksander Zdyb + * @author Pawel Wieczorek * @version 1.0 * @brief This file implements main class of cynara service */ @@ -65,7 +66,8 @@ void Cynara::init(void) { m_socketManager->bindLogic(m_logic); m_databaseLock.lock(); // Wait until database lock can be acquired - m_storage->load(); + m_logic->loadDb(); + m_pluginManager->loadPlugins(); } diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp index 57a4b56..141f006 100644 --- a/src/storage/InMemoryStorageBackend.cpp +++ b/src/storage/InMemoryStorageBackend.cpp @@ -16,6 +16,7 @@ /** * @file src/storage/InMemoryStorageBackend.cpp * @author Aleksander Zdyb + * @author Pawel Wieczorek * @version 1.0 * @brief Implementation of InMemoryStorageBackend */ @@ -35,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -91,7 +93,7 @@ void InMemoryStorageBackend::load(void) { } catch (const DatabaseException &) { LOGC("Reading cynara database failed."); buckets().clear(); - // TODO: Implement emergency mode toggle + throw DatabaseCorruptedException(); } m_checksum.clear(); diff --git a/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h b/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h index fbc523b..4bcd05d 100644 --- a/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h +++ b/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h @@ -16,6 +16,7 @@ /** * @file test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h * @author Aleksander Zdyb + * @author Pawel Wieczorek * @version 1.0 * @brief Fixture for InMemeoryStorageBackend tests */ @@ -89,6 +90,12 @@ protected: ASSERT_EQ(Cynara::PredefinedPolicyType::DENY, defaultBucket.defaultPolicy()); } + static void ASSERT_DB_EMPTY(Cynara::Buckets &buckets) { + using ::testing::IsEmpty; + ASSERT_EQ(0, buckets.size()); + ASSERT_THAT(buckets, IsEmpty()); + } + virtual ~InMemeoryStorageBackendFixture() {} const Cynara::PolicyCollection &fullPoliciesCollection(void) { diff --git a/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp b/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp index 1c88335..64091b6 100644 --- a/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp +++ b/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp @@ -25,6 +25,7 @@ #include "exceptions/BucketNotExistsException.h" #include "exceptions/BucketDeserializationException.h" +#include "exceptions/DatabaseCorruptedException.h" #include "exceptions/DefaultBucketDeletionException.h" #include "exceptions/FileNotFoundException.h" #include "storage/InMemoryStorageBackend.h" @@ -196,25 +197,21 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicyFromNonexistentBucket) { // Database dir is empty TEST_F(InMemeoryStorageBackendFixture, load_no_db) { using ::testing::ReturnRef; - using ::testing::Return; auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/empty_db/"; FakeInMemoryStorageBackend backend(testDbPath); EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets)); - EXPECT_CALL(backend, postLoadCleanup(false)).WillOnce(Return()); - backend.load(); - ASSERT_DB_VIRGIN(m_buckets); + EXPECT_THROW(backend.load(), DatabaseCorruptedException); + ASSERT_DB_EMPTY(m_buckets); } // Database dir contains index with default bucket, but no file for this bucket TEST_F(InMemeoryStorageBackendFixture, load_no_default) { using ::testing::ReturnRef; - using ::testing::Return; auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db2/"; FakeInMemoryStorageBackend backend(testDbPath); EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets)); - EXPECT_CALL(backend, postLoadCleanup(false)).WillOnce(Return()); - backend.load(); - ASSERT_DB_VIRGIN(m_buckets); + EXPECT_THROW(backend.load(), DatabaseCorruptedException); + ASSERT_DB_EMPTY(m_buckets); } // Database contains index with default bucket and an empty bucket file @@ -258,13 +255,11 @@ TEST_F(InMemeoryStorageBackendFixture, load_2_buckets) { // Database contains index with 2 buckets; 1st bucket is valid, but second is corrupted TEST_F(InMemeoryStorageBackendFixture, second_bucket_corrupted) { using ::testing::ReturnRef; - using ::testing::Return; auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db5/"; FakeInMemoryStorageBackend backend(testDbPath); EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets)); - EXPECT_CALL(backend, postLoadCleanup(false)).WillOnce(Return()); - backend.load(); - ASSERT_DB_VIRGIN(m_buckets); + EXPECT_THROW(backend.load(), DatabaseCorruptedException); + ASSERT_DB_EMPTY(m_buckets); } /** -- 2.7.4 From f33f7bec830b3c4492d556cd54f63af95ad715c1 Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Thu, 15 Jan 2015 11:27:42 +0100 Subject: [PATCH 11/16] Add tests utilizing short command-line options The tests are automagically generated from their longer sisters' bodies. Change-Id: I1e50314ddee74aaaba42dc29a04c26f237128996 --- test/CMakeLists.txt | 1 + test/cyad/commandline_short.cpp | 253 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 test/cyad/commandline_short.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 189268d..25a70db 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -86,6 +86,7 @@ SET(CYNARA_TESTS_SOURCES credsCommons/parser/Parser.cpp cyad/commandline.cpp cyad/commandline_errors.cpp + cyad/commandline_short.cpp cyad/commands_dispatcher.cpp cyad/helpers.cpp cyad/policy_collection.cpp diff --git a/test/cyad/commandline_short.cpp b/test/cyad/commandline_short.cpp new file mode 100644 index 0000000..357a3dc --- /dev/null +++ b/test/cyad/commandline_short.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ +/** + * @file test/cyad/commandline_short.cpp + * @author Aleksander Zdyb + * @version 1.0 + * @brief Tests for CyadCommandlineParser (short opts) + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include "CyadCommandlineTest.h" + +TEST_F(CyadCommandlineTest, help_short) { + prepare_argv({ "./cyad", "-h" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); +} + +TEST_F(CyadCommandlineTest, deleteBucket_short) { + prepare_argv({ "./cyad", "-d", "bucket" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("bucket", result->bucketId()); +} + +TEST_F(CyadCommandlineTest, setBucket_short) { + prepare_argv({ "./cyad", "-b", "bucket", "-t", "42" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("bucket", result->bucketId()); + ASSERT_EQ("42", result->policyResult().policyType()); + ASSERT_TRUE(result->policyResult().metadata().empty()); +} + +TEST_F(CyadCommandlineTest, setBucketWithMetadata_short) { + const std::string ultimateAnswer = "Answer to The Ultimate Question of Life," + " the Universe, and Everything"; + + prepare_argv({ "./cyad", "-b", "adams", "-t", "42", "-m", ultimateAnswer }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("adams", result->bucketId()); + ASSERT_EQ("42", result->policyResult().policyType()); + ASSERT_EQ(ultimateAnswer, result->policyResult().metadata()); +} + +TEST_F(CyadCommandlineTest, setPolicy_short) { + prepare_argv({ "./cyad", "-s", "-k", "some-bucket", + "-c", "client", "-u", "user", "-p", "privilege", + "-t", "42" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("some-bucket", result->bucketId()); + + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); + ASSERT_EQ("42", result->policyResult().policyType()); + ASSERT_TRUE(result->policyResult().metadata().empty()); +} + +TEST_F(CyadCommandlineTest, setPolicyWithMetadata_short) { + prepare_argv({ "./cyad", "-s", "-k", "some-bucket", + "-c", "client", "-u", "user", "-p", "privilege", + "-t", "42", "-m", "some-metadata" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("some-bucket", result->bucketId()); + + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); + ASSERT_EQ("42", result->policyResult().policyType()); + ASSERT_EQ("some-metadata", result->policyResult().metadata()); +} + +TEST_F(CyadCommandlineTest, setPolicyInDefaultBucket_short) { + prepare_argv({ "./cyad", "-s", "-k", "", + "-c", "client", "-u", "user", "-p", "privilege", + "-t", "ALLOW", "-m", "some-metadata" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("", result->bucketId()); + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); + ASSERT_EQ("ALLOW", result->policyResult().policyType()); + ASSERT_EQ("some-metadata", result->policyResult().metadata()); +} + +TEST_F(CyadCommandlineTest, setPolicyInDefaultBucketNoOption_short) { + prepare_argv({ "./cyad", "-s", + "-c", "client", "-u", "user", "-p", "privilege", + "-t", "ALLOW", "-m", "some-metadata" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("", result->bucketId()); + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); + ASSERT_EQ("ALLOW", result->policyResult().policyType()); + ASSERT_EQ("some-metadata", result->policyResult().metadata()); +} + +TEST_F(CyadCommandlineTest, parsePolicyTypeBase10_short) { + auto parsePolicyType = [] (const char *rawPolicy) -> Cynara::PolicyType { + return Cynara::HumanReadableParser::policyType(rawPolicy); + }; + + ASSERT_EQ(CYNARA_ADMIN_DENY, parsePolicyType("0")); + ASSERT_EQ(CYNARA_ADMIN_NONE, parsePolicyType("1")); + ASSERT_EQ(CYNARA_ADMIN_BUCKET, parsePolicyType("65534")); + ASSERT_EQ(CYNARA_ADMIN_ALLOW, parsePolicyType("65535")); +} + +TEST_F(CyadCommandlineTest, parsePolicyTypeBase16_short) { + auto parsePolicyType = [] (const char *rawPolicy) -> Cynara::PolicyType { + return Cynara::HumanReadableParser::policyType(rawPolicy); + }; + + ASSERT_EQ(CYNARA_ADMIN_DENY, parsePolicyType("0x0")); + ASSERT_EQ(CYNARA_ADMIN_NONE, parsePolicyType("0x1")); + ASSERT_EQ(CYNARA_ADMIN_BUCKET, parsePolicyType("0xFFFE")); + ASSERT_EQ(CYNARA_ADMIN_ALLOW, parsePolicyType("0xFFFF")); +} + +TEST_F(CyadCommandlineTest, parsePolicyTypeHuman_short) { + auto parsePolicyType = [] (const char *rawPolicy) -> Cynara::PolicyType { + return Cynara::HumanReadableParser::policyType(rawPolicy); + }; + + ASSERT_EQ(CYNARA_ADMIN_DENY, parsePolicyType("DENY")); + ASSERT_EQ(CYNARA_ADMIN_NONE, parsePolicyType("NONE")); + ASSERT_EQ(CYNARA_ADMIN_BUCKET, parsePolicyType("BUCKET")); + ASSERT_EQ(CYNARA_ADMIN_ALLOW, parsePolicyType("ALLOW")); +} + +TEST_F(CyadCommandlineTest, setPoliciesBulkFilename_short) { + prepare_argv({ "./cyad", "-s", "-f", "/tmp/input_file" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("/tmp/input_file", result->filename()); +} + +TEST_F(CyadCommandlineTest, setPoliciesBulkStdin_short) { + prepare_argv({ "./cyad", "-s", "-f", "-" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("-", result->filename()); +} + +TEST_F(CyadCommandlineTest, eraseRecursive_short) { + prepare_argv({ "./cyad", "-e", "bucket", "-r", "yes", + "-c", "client", "-u", "user", "-p", "privilege" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("bucket", result->bucketId()); + ASSERT_TRUE(result->recursive()); + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); +} + +TEST_F(CyadCommandlineTest, eraseNonrecursive_short) { + prepare_argv({ "./cyad", "-e", "bucket", "-r", "no", + "-c", "client", "-u", "user", "-p", "privilege" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("bucket", result->bucketId()); + ASSERT_FALSE(result->recursive()); + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); +} + +TEST_F(CyadCommandlineTest, checkDefaultRecursive_short) { + prepare_argv({ "./cyad", "-a", "-r", "no", + "-c", "client", "-u", "user", "-p", "privilege" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ(CYNARA_ADMIN_DEFAULT_BUCKET, result->bucketId()); + ASSERT_FALSE(result->recursive()); + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); +} + +TEST_F(CyadCommandlineTest, listPoliciesDefault_short) { + prepare_argv({ "./cyad", "-l", "", + "-c", "client", "-u", "user", "-p", "privilege" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ(CYNARA_ADMIN_DEFAULT_BUCKET, result->bucketId()); + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); +} + +TEST_F(CyadCommandlineTest, listPoliciesOtherBucket_short) { + prepare_argv({ "./cyad", "-l", "some-bucket", + "-c", "c", "-u", "u", "-p", "p" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("some-bucket", result->bucketId()); + ASSERT_EQ(Cynara::PolicyKey("c", "u", "p"), result->policyKey()); +} + +TEST_F(CyadCommandlineTest, listPoliciesDesc_short) { + prepare_argv({ "./cyad", "-g" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast( + parser.parseMain()); + ASSERT_NE(nullptr, result); +} -- 2.7.4 From 22f18a4393231d20c896246ae94057a9ae185958 Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Mon, 2 Mar 2015 12:30:03 +0100 Subject: [PATCH 12/16] Link cynara-creds-commons with cynara-common This is needed because cynara-creds-commons use logging. Change-Id: If9575313081b9a252d5f711f11f396cdd8eeebd3 --- src/helpers/creds-commons/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/helpers/creds-commons/CMakeLists.txt b/src/helpers/creds-commons/CMakeLists.txt index 961219b..29d37ef 100644 --- a/src/helpers/creds-commons/CMakeLists.txt +++ b/src/helpers/creds-commons/CMakeLists.txt @@ -35,6 +35,10 @@ INCLUDE_DIRECTORIES( ADD_LIBRARY(${TARGET_LIB_CREDS_COMMONS} SHARED ${LIB_CREDS_COMMONS_SOURCES}) +TARGET_LINK_LIBRARIES(${TARGET_LIB_CREDS_COMMONS} + ${TARGET_CYNARA_COMMON} + ) + SET_TARGET_PROPERTIES( ${TARGET_LIB_CREDS_COMMONS} PROPERTIES -- 2.7.4 From d894ff4c814045f28620970fa8397281495ecc87 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Tue, 24 Feb 2015 20:29:29 +0100 Subject: [PATCH 13/16] Add description of simple check request in asynch API Change-Id: I63e3da83cb2cc8284b3c56ce52f88a85b6feac90 --- src/include/cynara-client-async.h | 105 ++++++++++++++++++++++++++++++++------ src/include/cynara-client.h | 6 +-- 2 files changed, 91 insertions(+), 20 deletions(-) diff --git a/src/include/cynara-client-async.h b/src/include/cynara-client-async.h index 1a165c2..0fa37d8 100644 --- a/src/include/cynara-client-async.h +++ b/src/include/cynara-client-async.h @@ -58,10 +58,11 @@ typedef enum { * Values indicating the reason of cynara_response_callback call. * * \var cynara_async_call_cause::CYNARA_CALL_CAUSE_ANSWER - * Callback was called due to response to previous cynara_async_create_request() call. + * Callback was called due to response to previous cynara_async_create_request() or + * cynara_async_create_simple_request() call. * * \var cynara_async_call_cause::CYNARA_CALL_CAUSE_CANCEL - * Callback was called due to request cancelation with cynara_async_cancel_request() call. + * Callback was called due to request cancellation with cynara_async_cancel_request() call. * * \var cynara_async_call_cause::CYNARA_CALL_CAUSE_FINISH * Callback was called due to cynara_async_finish() call. @@ -77,8 +78,8 @@ typedef enum { } cynara_async_call_cause; /** - * \brief Response_callback is registered once in cynara_async_create_request() - * and will be triggered exactly once in 4 kind of situations: + * \brief Response_callback is registered once in cynara_async_create_request() or + * cynara_async_create_simple_request() and will be triggered exactly once in 4 kinds of situations: * 1) after response is received from cynara service (CYNARA_CALL_CAUSE_ANSWER) * 2) when request is canceled with cynara_async_cancel_request() (CYNARA_CALL_CAUSE_CANCEL) * 3) when request was pending for response, but cynara_async_finish() was called @@ -90,9 +91,10 @@ typedef enum { * cynara_async_finish() will be ignored if called from within this callback. * * \param[in] check_id Number identifying check request. Number is generated in - * cynara_async_create_request() and returned to user. It can be used to match - * response with sent request. - * Number is valid since cynara_async_create_request() call till callback call. + * cynara_async_create_request() or cynara_async_create_simple_request and returned to + * user. It can be used to match response with sent request. + * Number is valid since cynara_async_create_request() call or + * cynara_async_create_simple_request call till callback call. * After that the number can be reused by cynara to run new request. * \param[in] cause Cause of triggering this callback. * \param[in] response Response for created request. Should be ignored if cause is not @@ -108,8 +110,8 @@ typedef void (*cynara_response_callback) (cynara_check_id check_id, cynara_async /** * \brief Callback used by cynara async API when status of cynara socket is changed in - * cynara_async_initialize(), cynara_async_create_request(), cynara_async_process(), - * cynara_async_cancel_request() or cynara_async_finish(). + * cynara_async_initialize(), cynara_async_create_request(), cynara_async_create_simple_request(), + * cynara_async_process(), cynara_async_cancel_request() or cynara_async_finish(). * File descriptor changes every time cynara library connects or disconnects cynara service. * Status change is triggered when check_request or cancel needs to be send to * cynara service or sending data has finished and there is nothing more to send to cynara @@ -389,11 +391,11 @@ int cynara_async_check_cache(cynara_async *p_cynara, const char *client, const c * will be triggered in event loop after socket is ready to send request to cynara service. * After request is sent and there is nothing more to send to cynara service, status will change * back to CYNARA_STATUS_FOR_READ. Status changes are delivered with cynara_status_callback. - * When function is succesfully called unique check_id is returned. It is used for matching + * When function is successfully called unique check_id is returned. It is used for matching * generated request with response, that will be received by registered callback. * Because check_id is coded as 16-bit unsigned integer, there can be only 2^16 = 65536 pending * requests. When response callback is called either because of getting answer or because - * of cancel check_id used for taht request is released and can be reused by cynara library. + * of cancel check_id used for that request is released and can be reused by cynara library. * When maximum of pending requests is reached cynara_async_create_request() fails with * CYNARA_API_MAX_PENDING_REQUESTS error code. * @@ -409,7 +411,7 @@ int cynara_async_check_cache(cynara_async *p_cynara, const char *client, const c * cynara_async_initialize(). * Call cynara_async_cancel_request() to cancel pending request. * Call cynara_async_process() to receive response. - * It is guaranteed that if cynara_async_create_request() function suceeds (CYNARA_API_SUCCESS) + * It is guaranteed that if cynara_async_create_request() function succeeds (CYNARA_API_SUCCESS) * a callback will be called exactly once and that it will receive user_response_data. * If function fails (returns negative error code) request won't be generated and won't be pending, * callback function won't be ever called and user_response_data won't be remembered by library. @@ -441,6 +443,73 @@ int cynara_async_create_request(cynara_async *p_cynara, const char *client, cynara_check_id *p_check_id, cynara_response_callback callback, void *user_response_data); + +/** + * \par Description: + * Creates simple access check request to cynara service for (potential) permission to take some + * action or access a resource. + * Set callback and user_response_data to be called and passed when request processing is finished. + * + * \par Purpose: + * This API should be used for a quick check if a user running application identified as client + * has access to a given privilege. + * Response can be received with cynara_async_process(). + * Check id is returned to pair request with response for canceling purposes. + * + * \par Typical use case: + * An application may use this API to check if it has (potential) permission to take some action + * or access resource in future (permissions may rarely change). The typical use would be to disable + * or hide some of functionalities if they probably could not be used anyways. + * + * \par Method of function operation: + * This function is very similar to cynara_async_create_request() with the difference, that in case + * of answer not being one of CYNARA_API_PERMISSION_DENIED or CYNARA_API_PERMISSION_ALLOWED, + * no external application will be consulted. Instead, CYNARA_API_ACCESS_NOT_RESOLVED is returned, + * meaning, that only creating full request through cynara_async_create_request API would yield + * eventual answer. + * If access permission cannot be acquired without usage of external agents, callback can be + * called with CYNARA_CALL_CAUSE_ANSWER and response value being CYNARA_API_ACCESS_NOT_RESOLVED. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. If functions from described API are called by multithreaded + * application from different threads, they must be put into mutex protected critical section. + * + * \par Important notes: + * Call to cynara_async_create_simple_request() needs cynara_async structure to be created first + * with cynara_async_initialize(). + * Call cynara_async_cancel_request() to cancel pending request. + * Call cynara_async_process() to send request and receive response. + * The answer will be taken from cynara's database without consulting any external applications. + * If the answer cannot be resolved in one of CYNARA_API_ACCESS_ALLOWED or + * CYNARA_API_ACCESS_DENIED without communicating with external application, response returned + * through callback will have value CYNARA_API_ACCESS_NOT_RESOLVED. + * + * \param[in] p_cynara cynara_async structure. + * \param[in] client Application or process identifier. + * \param[in] client_session Client defined session. + * \param[in] user User of running client. + * \param[in] privilege Privilege that is a subject of a check. + * \param[out] p_check_id Placeholder for check id. If NULL, then no check_id is returned. + * \param[in] callback Function called when matching response is received. + * If NULL then no callback will be called when response, cancel, finish + * or service not availble error happens. + * \param[in] user_response_data User specific data, passed to callback is being only stored by + * library. Cynara library does not take any actions on this pointer, except for giving + * it back to user in cynara_response_callback. + * Can be NULL. + * + * \return CYNARA_API_SUCCESS on success, + * CYNARA_API_MAX_PENDING_REQUESTS on too much pending requests, + * or other negative error code on error. + */ +int cynara_async_create_simple_request(cynara_async *p_cynara, const char *client, + const char *client_session, const char *user, + const char *privilege, cynara_check_id *p_check_id, + cynara_response_callback callback, void *user_response_data); + /** * \par Description: * Process events that appeared on cynara socket. @@ -449,7 +518,8 @@ int cynara_async_create_request(cynara_async *p_cynara, const char *client, * Process events after they appear on cynara socket. * * \par Typical use case: - * After request was queued with cynara_async_create_request() this API will return response. + * After request was queued with cynara_async_create_request() or + * cynara_async_create_simple_request() this API will return response. * When event loop will return readiness on cynara socket, client should use this API. * * \par Method of function operation: @@ -483,19 +553,20 @@ int cynara_async_process(cynara_async *p_cynara); /** * \par Description: - * Cancel request created by cynara_async_create_request(). + * Cancel request created by cynara_async_create_request() or cynara_async_create_simple_request(). * * \par Purpose: * This API should be used to cancel pending check request, - * created by cynara_async_create_request(). + * created by cynara_async_create_request() or cynara_async_create_simple_request(). * * \par Typical use case: * When cynara client is no longer interested in receiving an answer. * Same check_id value should be used to identify proper request as was generated during - * request creation with cynara_async_create_request(). + * request creation with cynara_async_create_request() or cynara_async_create_simple_request(). * * \par Method of function operation: - * Cancels request created by cynara_async_create_request() call. + * Cancels request created by cynara_async_create_request() or cynara_async_create_simple_request() + * call. * cynara_status_callback callback may be triggered to be able to send cancel to cynara. * cynara_response_callback callback will be triggered with with * cynara_async_call_cause::CYNARA_CALL_CAUSE_CANCEL as cause param. diff --git a/src/include/cynara-client.h b/src/include/cynara-client.h index a617246..89a8e7b 100644 --- a/src/include/cynara-client.h +++ b/src/include/cynara-client.h @@ -252,9 +252,9 @@ int cynara_check(cynara *p_cynara, const char *client, const char *client_sessio * * \par Method of function operation: * This function is very similar to cynara_check() with the difference, that in case of answer not - * being one of CYNARA_API_PERMISSION_DENIED or CYNARA_API_PERMISSION_ALLOWED, no external - * application will be consulted. Instead, CYNARA_API_ACCESS_NOT_RESOLVED is returned, meaning, - * that only running full cynara_check() API would yield eventual answer. + * being one of CYNARA_API_ACCESS_DENIED or CYNARA_API_ACCESS_ALLOWED, no external application will + * be consulted. Instead, CYNARA_API_ACCESS_NOT_RESOLVED is returned, meaning, that only running + * full cynara_check() API would yield eventual answer. * Similarly, like in cynara_check(), argument client_session can be used to distinguish client * sessions and grant possibility to yield answer from cache. * -- 2.7.4 From 7464614457e56fccfec4dc27734508b331ff6bb3 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Wed, 25 Feb 2015 18:38:10 +0100 Subject: [PATCH 14/16] Add implementation of simple asynch check Add implementation in api and logic layers. Protocol layer is shared with synchronous client. Change-Id: Ic8ade619756cb7e0893e3da25a5452e1bf3b0994 --- src/client-async/api/ApiInterface.h | 12 ++-- src/client-async/api/client-async-api.cpp | 40 +++++++++++- src/client-async/check/CheckData.h | 14 +++- src/client-async/logic/Logic.cpp | 104 +++++++++++++++++++++++------- src/client-async/logic/Logic.h | 19 ++++-- 5 files changed, 154 insertions(+), 35 deletions(-) diff --git a/src/client-async/api/ApiInterface.h b/src/client-async/api/ApiInterface.h index 59c82fb..7b7f035 100644 --- a/src/client-async/api/ApiInterface.h +++ b/src/client-async/api/ApiInterface.h @@ -36,10 +36,14 @@ public: virtual int checkCache(const std::string &client, const std::string &session, const std::string &user, const std::string &privilege) = 0; - virtual int createRequest(const std::string &client, const std::string &session, - const std::string &user, const std::string &privilege, - cynara_check_id &checkId, cynara_response_callback callback, - void *userResponseData) = 0; + virtual int createCheckRequest(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData) = 0; + virtual int createSimpleRequest(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData) = 0; virtual int process(void) = 0; virtual int cancelRequest(cynara_check_id checkId) = 0; virtual bool isFinishPermitted(void) = 0; diff --git a/src/client-async/api/client-async-api.cpp b/src/client-async/api/client-async-api.cpp index 38c6fb6..738c79b 100644 --- a/src/client-async/api/client-async-api.cpp +++ b/src/client-async/api/client-async-api.cpp @@ -170,8 +170,44 @@ int cynara_async_create_request(cynara_async *p_cynara, const char *client, return CYNARA_API_INVALID_PARAM; } cynara_check_id checkId; - int ret = p_cynara->impl->createRequest(clientStr, clientSessionStr, userStr, privilegeStr, - checkId, callback, user_response_data); + int ret = p_cynara->impl->createCheckRequest(clientStr, clientSessionStr, userStr, + privilegeStr, checkId, callback, + user_response_data); + if (p_check_id && ret == CYNARA_API_SUCCESS) + *p_check_id = checkId; + return ret; + }); +} + +CYNARA_API +int cynara_async_create_simple_request(cynara_async *p_cynara, const char *client, + const char *client_session, const char *user, + const char *privilege, cynara_check_id *p_check_id, + cynara_response_callback callback, void *user_response_data){ + if (!p_cynara || !p_cynara->impl) + return CYNARA_API_INVALID_PARAM; + if (!client || !client_session || !user || !privilege) + return CYNARA_API_INVALID_PARAM; + + return Cynara::tryCatch([&]() { + std::string clientStr; + std::string clientSessionStr; + std::string userStr; + std::string privilegeStr; + + try { + clientStr = client; + clientSessionStr = client_session; + userStr = user; + privilegeStr = privilege; + } catch (const std::length_error &e) { + LOGE("%s", e.what()); + return CYNARA_API_INVALID_PARAM; + } + cynara_check_id checkId; + int ret = p_cynara->impl->createSimpleRequest(clientStr, clientSessionStr, userStr, + privilegeStr, checkId, callback, + user_response_data); if (p_check_id && ret == CYNARA_API_SUCCESS) *p_check_id = checkId; return ret; diff --git a/src/client-async/check/CheckData.h b/src/client-async/check/CheckData.h index 453af76..37ac92a 100644 --- a/src/client-async/check/CheckData.h +++ b/src/client-async/check/CheckData.h @@ -36,11 +36,14 @@ namespace Cynara { class CheckData { public: - CheckData(const PolicyKey &key, const std::string &session, const ResponseCallback &callback) - : m_key(key), m_session(session), m_callback(callback), m_cancelled(false) {} + CheckData(const PolicyKey &key, const std::string &session, const ResponseCallback &callback, + bool simple) + : m_key(key), m_session(session), m_callback(callback), m_simple(simple), m_cancelled(false) + {} CheckData(CheckData &&other) : m_key(std::move(other.m_key)), m_session(std::move(other.m_session)), - m_callback(std::move(other.m_callback)), m_cancelled(other.m_cancelled) { + m_callback(std::move(other.m_callback)), m_simple(other.m_simple), + m_cancelled(other.m_cancelled) { other.m_cancelled = false; } ~CheckData() {} @@ -57,6 +60,10 @@ public: return m_callback; } + bool isSimple(void) const { + return m_simple; + } + bool cancelled(void) const { return m_cancelled; } @@ -69,6 +76,7 @@ private: PolicyKey m_key; std::string m_session; ResponseCallback m_callback; + bool m_simple; bool m_cancelled; }; diff --git a/src/client-async/logic/Logic.cpp b/src/client-async/logic/Logic.cpp index d5edf79..91769da 100644 --- a/src/client-async/logic/Logic.cpp +++ b/src/client-async/logic/Logic.cpp @@ -35,12 +35,13 @@ #include #include #include +#include #include #include +#include #include #include "Logic.h" - namespace Cynara { Logic::Logic(cynara_status_callback callback, void *userStatusData, const Configuration &conf) @@ -77,7 +78,23 @@ int Logic::checkCache(const std::string &client, const std::string &session, return m_cache->get(session, PolicyKey(client, user, privilege)); } -int Logic::createRequest(const std::string &client, const std::string &session, +int Logic::createCheckRequest(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData) { + return createRequest(false, client, session, user, privilege, checkId, callback, + userResponseData); +} + +int Logic::createSimpleRequest(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData) { + return createRequest(true, client, session, user, privilege, checkId, callback, + userResponseData); +} + +int Logic::createRequest(bool simple, const std::string &client, const std::string &session, const std::string &user, const std::string &privilege, cynara_check_id &checkId, cynara_response_callback callback, void *userResponseData) { @@ -93,8 +110,12 @@ int Logic::createRequest(const std::string &client, const std::string &session, PolicyKey key(client, user, privilege); ResponseCallback responseCallback(callback, userResponseData); - m_checks.insert(CheckPair(sequenceNumber, CheckData(key, session, responseCallback))); - m_socketClient->appendRequest(std::make_shared(key, sequenceNumber)); + m_checks.insert(CheckPair(sequenceNumber, CheckData(key, session, responseCallback, + simple))); + if (simple) + m_socketClient->appendRequest(std::make_shared(key, sequenceNumber)); + else + m_socketClient->appendRequest(std::make_shared(key, sequenceNumber)); onStatusChange(m_socketClient->getSockFd(), cynara_async_status::CYNARA_STATUS_FOR_RW); checkId = static_cast(sequenceNumber); @@ -158,7 +179,12 @@ void Logic::prepareRequestsToSend(void) { m_sequenceContainer.release(it->first); it = m_checks.erase(it); } else { - m_socketClient->appendRequest(std::make_shared(it->second.key(), it->first)); + if (it->second.isSimple()) + m_socketClient->appendRequest(std::make_shared(it->second.key(), + it->first)); + else + m_socketClient->appendRequest(std::make_shared(it->second.key(), + it->first)); ++it; } } @@ -176,22 +202,32 @@ bool Logic::processOut(void) { } } +Logic::CheckMap::iterator Logic::checkResponseValid(ResponsePtr response) { + auto it = m_checks.find(response->sequenceNumber()); + if (it == m_checks.end()) { + LOGC("Critical error. Unknown checkResponse received: sequenceNumber = [%" PRIu16 "]", + response->sequenceNumber()); + throw UnexpectedErrorException("Unexpected response from cynara service"); + } + return it; +} + +void Logic::releaseRequest(Logic::CheckMap::iterator reqIt) { + m_sequenceContainer.release(reqIt->first); + m_checks.erase(reqIt); +} + void Logic::processCheckResponse(CheckResponsePtr checkResponse) { LOGD("checkResponse: policyType = [%" PRIu16 "], metadata = <%s>", checkResponse->m_resultRef.policyType(), checkResponse->m_resultRef.metadata().c_str()); - auto it = m_checks.find(checkResponse->sequenceNumber()); - if (it == m_checks.end()) { - LOGC("Critical error. Unknown checkResponse received: sequenceNumber = [%" PRIu16 "]", - checkResponse->sequenceNumber()); - throw UnexpectedErrorException("Unexpected response from cynara service"); - } + auto it = checkResponseValid(checkResponse); int result = m_cache->update(it->second.session(), it->second.key(), checkResponse->m_resultRef); CheckData checkData(std::move(it->second)); - m_sequenceContainer.release(it->first); - m_checks.erase(it); + releaseRequest(it); + if (!checkData.cancelled()) { bool onAnswerCancel = m_inAnswerCancelResponseCallback; m_inAnswerCancelResponseCallback = true; @@ -201,29 +237,47 @@ void Logic::processCheckResponse(CheckResponsePtr checkResponse) { } } +void Logic::processSimpleCheckResponse(SimpleCheckResponsePtr response) { + LOGD("simpleCheckResponse"); + LOGD("checkResponse: policyType = [%" PRIu16 "], metadata = <%s>", + response->getResult().policyType(), + response->getResult().metadata().c_str()); + + auto it = checkResponseValid(response); + int result = response->getReturnValue(); + if (result == CYNARA_API_SUCCESS) + result = m_cache->update(it->second.session(), it->second.key(), + response->getResult()); + CheckData checkData(std::move(it->second)); + releaseRequest(it); + + if (!checkData.cancelled()) { + bool onAnswerCancel = m_inAnswerCancelResponseCallback; + m_inAnswerCancelResponseCallback = true; + checkData.callback().onAnswer( + static_cast(response->sequenceNumber()), result); + m_inAnswerCancelResponseCallback = onAnswerCancel; + } +} + void Logic::processCancelResponse(CancelResponsePtr cancelResponse) { LOGD("cancelResponse"); - auto it = m_checks.find(cancelResponse->sequenceNumber()); - if (it == m_checks.end()) { - LOGC("Critical error. Unknown cancelResponse received: sequenceNumber = [%" PRIu16 "]", - cancelResponse->sequenceNumber()); - throw UnexpectedErrorException("Unexpected response from cynara service"); - } + auto it = checkResponseValid(cancelResponse); if (!it->second.cancelled()) { LOGC("Critical error. CancelRequest not sent: sequenceNumber = [%" PRIu16 "]", cancelResponse->sequenceNumber()); throw UnexpectedErrorException("Unexpected response from cynara service"); } - m_sequenceContainer.release(it->first); - m_checks.erase(it); + releaseRequest(it); } void Logic::processResponses(void) { ResponsePtr response; CheckResponsePtr checkResponse; CancelResponsePtr cancelResponse; - while (response = m_socketClient->getResponse()) { + SimpleCheckResponsePtr simpleResponse; + while ((response = m_socketClient->getResponse())) { checkResponse = std::dynamic_pointer_cast(response); if (checkResponse) { processCheckResponse(checkResponse); @@ -236,6 +290,12 @@ void Logic::processResponses(void) { continue; } + simpleResponse = std::dynamic_pointer_cast(response); + if (simpleResponse) { + processSimpleCheckResponse(simpleResponse); + continue; + } + LOGC("Critical error. Casting Response to known response failed."); throw UnexpectedErrorException("Unexpected response from cynara service"); } diff --git a/src/client-async/logic/Logic.h b/src/client-async/logic/Logic.h index a38d51d..911215c 100644 --- a/src/client-async/logic/Logic.h +++ b/src/client-async/logic/Logic.h @@ -50,10 +50,14 @@ public: virtual int checkCache(const std::string &client, const std::string &session, const std::string &user, const std::string &privilege); - virtual int createRequest(const std::string &client, const std::string &session, - const std::string &user, const std::string &privilege, - cynara_check_id &checkId, cynara_response_callback callback, - void *userResponseData); + virtual int createCheckRequest(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData); + virtual int createSimpleRequest(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData); virtual int process(void); virtual int cancelRequest(cynara_check_id checkId); virtual bool isFinishPermitted(void); @@ -71,11 +75,18 @@ private: bool m_inAnswerCancelResponseCallback; bool checkCacheValid(void); + int createRequest(bool simple, const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData); void prepareRequestsToSend(void); cynara_async_status socketDataStatus(void); bool processOut(void); + CheckMap::iterator checkResponseValid(ResponsePtr response); + void releaseRequest(Logic::CheckMap::iterator reqIt); void processCheckResponse(CheckResponsePtr checkResponse); void processCancelResponse(CancelResponsePtr cancelResponse); + void processSimpleCheckResponse(SimpleCheckResponsePtr response); void processResponses(void); bool processIn(void); bool ensureConnection(void); -- 2.7.4 From a8a961533ad965b2e16ada2cbef838dd0220e60d Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Tue, 3 Mar 2015 14:26:11 +0100 Subject: [PATCH 15/16] Fix bug in receiving requests in libcynara-agent Method AgentSocketClient::receiveResponseFromServer should hang until it can return a request received from cynara service. However a single read from socket can read more than one request. Received requests are queued. Code did not check if there is a valid request read and queued previously, but always tried to read from socket. Fix changes order - so now code first checks queue and only in case, when there is no valid request waiting a socket is read. Change-Id: I845cd677700e516f252a8958b97ee8facb82170f --- src/agent/socket/AgentSocketClient.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/agent/socket/AgentSocketClient.cpp b/src/agent/socket/AgentSocketClient.cpp index 780c996..0e576ed 100644 --- a/src/agent/socket/AgentSocketClient.cpp +++ b/src/agent/socket/AgentSocketClient.cpp @@ -56,17 +56,14 @@ ResponsePtr AgentSocketClient::askCynaraServer(RequestPtr request) { } ResponsePtr AgentSocketClient::receiveResponseFromServer(void) { - while (true) { + ResponsePtr response; + while (!(response = m_protocol->extractResponseFromBuffer(m_readQueue))) { if (!m_socket.receiveFromServer(*m_readQueue)) { LOGW("Error receiving data from Cynara. Service not available."); return nullptr; } - - ResponsePtr response = m_protocol->extractResponseFromBuffer(m_readQueue); - if (response) { - return response; - } } + return response; } bool AgentSocketClient::sendDataToServer(BinaryQueue &data) { -- 2.7.4 From 9f66119c6b4b2be20608ce4b02afe0c731d4474f Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Mon, 9 Mar 2015 16:54:27 +0100 Subject: [PATCH 16/16] Release 0.6.0 Change-Id: Ia5c5029289dec6653262885b5095221abc63b2d5 --- CMakeLists.txt | 2 +- changelog | 32 ++++++++++++++++++++++++++++++++ packaging/cynara.spec | 2 +- src/admin/CMakeLists.txt | 2 +- src/agent/CMakeLists.txt | 4 ++-- src/client-async/CMakeLists.txt | 4 ++-- src/client-common/CMakeLists.txt | 2 +- src/client/CMakeLists.txt | 2 +- src/common/CMakeLists.txt | 2 +- src/helpers/creds-commons/CMakeLists.txt | 2 +- src/helpers/creds-dbus/CMakeLists.txt | 2 +- src/helpers/creds-socket/CMakeLists.txt | 2 +- src/helpers/session/CMakeLists.txt | 2 +- src/storage/CMakeLists.txt | 2 +- 14 files changed, 47 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 116c14f..a8d8f17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3) PROJECT("cynara") -set(CYNARA_VERSION 0.5.0) +set(CYNARA_VERSION 0.6.0) ############################# cmake packages ################################## diff --git a/changelog b/changelog index 10a0dc7..7d42925 100644 --- a/changelog +++ b/changelog @@ -1,5 +1,37 @@ ############################### +Release: 0.6.0 +Date: 2015.03.09 +Name: Client configuration, simple-check, cynara_strerror, checksums, emergency mode, migration tool. + +Libraries: +libcynara-admin.0.6.0 +libcynara-agent.0.6.0 +libcynara-client-async.0.6.0 +libcynara-client-commmons.0.6.0 +libcynara-client.0.6.0 +libcynara-commons.0.6.0 +libcynara-creds-commons.0.6.0 +libcynara-creds-dbus.0.6.0 +libcynara-creds-socket.0.6.0 +libcynara-session.0.6.0 +libcynara-storage.0.6.0 + +Executables: +cyad +cynara + +Description: +Configuration of cache size for both synchronous and asynchronous client. +New client command - simple_check. +Stringization of errors in cyad and with cynara_strerror. +Checksums mechanism finished. +Emergency mode, when database is corrupted. +Revisited migration tool. +Some bug fixes + +############################### + Release: 0.5.0 Date: 2015.01.16 Name: Cyad, offline-admin, erase, listPolicies, listDescriptions diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 3289855..5021f72 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -1,6 +1,6 @@ Name: cynara Summary: Cynara service with client libraries -Version: 0.5.0 +Version: 0.6.0 Release: 1 Group: Security/Application Privilege License: Apache-2.0 diff --git a/src/admin/CMakeLists.txt b/src/admin/CMakeLists.txt index dcb2419..42e6b9e 100644 --- a/src/admin/CMakeLists.txt +++ b/src/admin/CMakeLists.txt @@ -17,7 +17,7 @@ # SET(LIB_CYNARA_ADMIN_VERSION_MAJOR 0) -SET(LIB_CYNARA_ADMIN_VERSION ${LIB_CYNARA_ADMIN_VERSION_MAJOR}.5.0) +SET(LIB_CYNARA_ADMIN_VERSION ${LIB_CYNARA_ADMIN_VERSION_MAJOR}.6.0) SET(CYNARA_LIB_CYNARA_ADMIN_PATH ${CYNARA_PATH}/admin) diff --git a/src/agent/CMakeLists.txt b/src/agent/CMakeLists.txt index 83d90f6..da71235 100644 --- a/src/agent/CMakeLists.txt +++ b/src/agent/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +# Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ # SET(LIB_CYNARA_AGENT_VERSION_MAJOR 0) -SET(LIB_CYNARA_AGENT_VERSION ${LIB_CYNARA_AGENT_VERSION_MAJOR}.3.0) +SET(LIB_CYNARA_AGENT_VERSION ${LIB_CYNARA_AGENT_VERSION_MAJOR}.6.0) SET(CYNARA_LIB_CYNARA_AGENT_PATH ${CYNARA_PATH}/agent) diff --git a/src/client-async/CMakeLists.txt b/src/client-async/CMakeLists.txt index a9b9971..19d8b3c 100644 --- a/src/client-async/CMakeLists.txt +++ b/src/client-async/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +# Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ # SET(LIB_CYNARA_ASYNC_VERSION_MAJOR 0) -SET(LIB_CYNARA_ASYNC_VERSION ${LIB_CYNARA_ASYNC_VERSION_MAJOR}.0.2) +SET(LIB_CYNARA_ASYNC_VERSION ${LIB_CYNARA_ASYNC_VERSION_MAJOR}.6.0) SET(CYNARA_LIB_CYNARA_ASYNC_PATH ${CYNARA_PATH}/client-async) diff --git a/src/client-common/CMakeLists.txt b/src/client-common/CMakeLists.txt index 6629aec..8984ff6 100644 --- a/src/client-common/CMakeLists.txt +++ b/src/client-common/CMakeLists.txt @@ -17,7 +17,7 @@ # SET(LIB_CYNARA_CLIENT_COMMON_VERSION_MAJOR 0) -SET(LIB_CYNARA_CLIENT_COMMON_VERSION ${LIB_CYNARA_CLIENT_COMMON_VERSION_MAJOR}.5.0) +SET(LIB_CYNARA_CLIENT_COMMON_VERSION ${LIB_CYNARA_CLIENT_COMMON_VERSION_MAJOR}.6.0) SET(LIB_CYNARA_COMMON_PATH ${CYNARA_PATH}/client-common) diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 059fac2..d98059f 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -18,7 +18,7 @@ # SET(LIB_CYNARA_VERSION_MAJOR 0) -SET(LIB_CYNARA_VERSION ${LIB_CYNARA_VERSION_MAJOR}.5.0) +SET(LIB_CYNARA_VERSION ${LIB_CYNARA_VERSION_MAJOR}.6.0) SET(LIB_CYNARA_PATH ${CYNARA_PATH}/client) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index be94ff8..f72bb7e 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -17,7 +17,7 @@ # SET(CYNARA_COMMON_VERSION_MAJOR 0) -SET(CYNARA_COMMON_VERSION ${CYNARA_COMMON_VERSION_MAJOR}.5.0) +SET(CYNARA_COMMON_VERSION ${CYNARA_COMMON_VERSION_MAJOR}.6.0) SET(COMMON_PATH ${CYNARA_PATH}/common) diff --git a/src/helpers/creds-commons/CMakeLists.txt b/src/helpers/creds-commons/CMakeLists.txt index 29d37ef..dc0b25d 100644 --- a/src/helpers/creds-commons/CMakeLists.txt +++ b/src/helpers/creds-commons/CMakeLists.txt @@ -19,7 +19,7 @@ # SET(LIB_CREDS_COMMONS_VERSION_MAJOR 0) -SET(LIB_CREDS_COMMONS_VERSION ${LIB_CREDS_COMMONS_VERSION_MAJOR}.5.0) +SET(LIB_CREDS_COMMONS_VERSION ${LIB_CREDS_COMMONS_VERSION_MAJOR}.6.0) SET(LIB_CREDS_COMMONS_PATH ${CYNARA_PATH}/helpers/creds-commons) diff --git a/src/helpers/creds-dbus/CMakeLists.txt b/src/helpers/creds-dbus/CMakeLists.txt index 4001207..fc7c4cb 100644 --- a/src/helpers/creds-dbus/CMakeLists.txt +++ b/src/helpers/creds-dbus/CMakeLists.txt @@ -19,7 +19,7 @@ # SET(LIB_CREDS_DBUS_VERSION_MAJOR 0) -SET(LIB_CREDS_DBUS_VERSION ${LIB_CREDS_DBUS_VERSION_MAJOR}.5.0) +SET(LIB_CREDS_DBUS_VERSION ${LIB_CREDS_DBUS_VERSION_MAJOR}.6.0) SET(LIB_CREDS_DBUS_PATH ${CYNARA_PATH}/helpers/creds-dbus) diff --git a/src/helpers/creds-socket/CMakeLists.txt b/src/helpers/creds-socket/CMakeLists.txt index 950561c..4c33968 100644 --- a/src/helpers/creds-socket/CMakeLists.txt +++ b/src/helpers/creds-socket/CMakeLists.txt @@ -19,7 +19,7 @@ # SET(LIB_CREDS_SOCKET_VERSION_MAJOR 0) -SET(LIB_CREDS_SOCKET_VERSION ${LIB_CREDS_SOCKET_VERSION_MAJOR}.5.0) +SET(LIB_CREDS_SOCKET_VERSION ${LIB_CREDS_SOCKET_VERSION_MAJOR}.6.0) SET(LIB_CREDS_SOCKET_PATH ${CYNARA_PATH}/helpers/creds-socket) diff --git a/src/helpers/session/CMakeLists.txt b/src/helpers/session/CMakeLists.txt index 7897828..c08da4f 100644 --- a/src/helpers/session/CMakeLists.txt +++ b/src/helpers/session/CMakeLists.txt @@ -19,7 +19,7 @@ # SET(LIB_SESSION_VERSION_MAJOR 0) -SET(LIB_SESSION_VERSION ${LIB_SESSION_VERSION_MAJOR}.5.0) +SET(LIB_SESSION_VERSION ${LIB_SESSION_VERSION_MAJOR}.6.0) SET(LIB_SESSION_PATH ${CYNARA_PATH}/helpers/session) diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt index f75bc06..574d369 100644 --- a/src/storage/CMakeLists.txt +++ b/src/storage/CMakeLists.txt @@ -18,7 +18,7 @@ # SET(LIB_CYNARA_STORAGE_VERSION_MAJOR 0) -SET(LIB_CYNARA_STORAGE_VERSION ${LIB_CYNARA_STORAGE_VERSION_MAJOR}.3.0) +SET(LIB_CYNARA_STORAGE_VERSION ${LIB_CYNARA_STORAGE_VERSION_MAJOR}.6.0) SET(CYNARA_LIB_CYNARA_STORAGE_PATH ${CYNARA_PATH}/storage) -- 2.7.4