From f868f4447f698148efb83b566dc5244d4e455f29 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Tue, 3 Feb 2015 14:13:40 +0100 Subject: [PATCH 01/16] Add new cynara_simple_check synchronous client API New API description put in synchronous client header. New return code added - CYNARA_API_ACCESS_NOT_RESOLVED. Mockup function to Logic added. Change-Id: I57968b3e17cf70c3b294af1faf8158e265ffe2b6 --- src/client/api/ApiInterface.h | 5 ++++- src/client/api/client-api.cpp | 27 ++++++++++++++++++++++ src/client/logic/Logic.cpp | 9 ++++++++ src/client/logic/Logic.h | 2 ++ src/include/cynara-client.h | 52 ++++++++++++++++++++++++++++++++++++++++++- src/include/cynara-error.h | 4 +++- 6 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/client/api/ApiInterface.h b/src/client/api/ApiInterface.h index 3a724c5..f979a1d 100644 --- a/src/client/api/ApiInterface.h +++ b/src/client/api/ApiInterface.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/client/api/ApiInterface.h * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 * @brief This file contains libcynara-client API interface definition. */ @@ -37,6 +38,8 @@ public: virtual int check(const std::string &client, const ClientSession &session, const std::string &user, const std::string &privilege) = 0; + virtual int simpleCheck(const std::string &client, const ClientSession &session, + const std::string &user, const std::string &privilege) = 0; }; } // namespace Cynara diff --git a/src/client/api/client-api.cpp b/src/client/api/client-api.cpp index 3d3189a..3e4134c 100644 --- a/src/client/api/client-api.cpp +++ b/src/client/api/client-api.cpp @@ -143,3 +143,30 @@ int cynara_check(cynara *p_cynara, const char *client, const char *client_sessio return p_cynara->impl->check(clientStr, clientSessionStr, userStr, privilegeStr); }); } + +CYNARA_API +int cynara_simple_check(cynara *p_cynara, const char *client, const char *client_session, + const char *user, const char *privilege) { + 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; + } + return p_cynara->impl->simpleCheck(clientStr, clientSessionStr, userStr, privilegeStr); + }); +} diff --git a/src/client/logic/Logic.cpp b/src/client/logic/Logic.cpp index d34caa6..c171cce 100644 --- a/src/client/logic/Logic.cpp +++ b/src/client/logic/Logic.cpp @@ -81,6 +81,15 @@ int Logic::check(const std::string &client, const ClientSession &session, const return m_cache->update(session, key, result); } +int Logic::simpleCheck(const std::string &client, const ClientSession &session, + const std::string &user, const std::string &privilege) { + (void)client; + (void)session; + (void)user; + (void)privilege; + return CYNARA_API_ACCESS_NOT_RESOLVED; +} + bool Logic::ensureConnection(void) { if (m_socket->isConnected()) return true; diff --git a/src/client/logic/Logic.h b/src/client/logic/Logic.h index 5641ca4..695f7cd 100644 --- a/src/client/logic/Logic.h +++ b/src/client/logic/Logic.h @@ -48,6 +48,8 @@ public: virtual int check(const std::string &client, const ClientSession &session, const std::string &user, const std::string &privilege); + virtual int simpleCheck(const std::string &client, const ClientSession &session, + const std::string &user, const std::string &privilege); private: SocketClientPtr m_socket; PluginCachePtr m_cache; diff --git a/src/include/cynara-client.h b/src/include/cynara-client.h index 61a8fcf..a617246 100644 --- a/src/include/cynara-client.h +++ b/src/include/cynara-client.h @@ -16,6 +16,7 @@ /** * @file src/include/cynara-client.h * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 * @brief This file contains client APIs of Cynara available with libcynara-client. */ @@ -234,7 +235,56 @@ int cynara_finish(cynara *p_cynara); * or other error code on error. */ int cynara_check(cynara *p_cynara, const char *client, const char *client_session, const char *user, - const char *privilege); + const char *privilege); + +/** + * \par Description: + * Check for (potential) permission to take some action or access a resource. + * + * \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. + * + * \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_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. + * Similarly, like in cynara_check(), argument client_session can be used to distinguish client + * sessions and grant possibility to yield answer from cache. + * + * \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: + * 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_PERMISSION_DENIED or + * CYNARA_API_PERMISSION_ALLOWED without communicating with external application the API will return + * CYNARA_API_ACCESS_NOT_RESOLVED. + * Call to cynara_simple_check needs cynara structure to be created first with call to + * cynara_initialize. + * + * \param[in] p_cynara Cynara structure. + * \param[in] client Application or process identifier. + * \param[in] client_session Session of client (connection, launch). + * \param[in] user User running client. + * \param[in] privilege Privilege that is a subject of a check. + * + * \return CYNARA_API_ACCESS_ALLOWED on access allowed, CYNARA_API_ACCESS_DENIED on access denial, + * CYNARA_API_ACCESS_NOT_RESOLVED when decision is not known without usage of external plugins or + * agents or negative error code on error. + */ +int cynara_simple_check(cynara *p_cynara, const char *client, const char *client_session, + const char *user, const char *privilege); #ifdef __cplusplus } diff --git a/src/include/cynara-error.h b/src/include/cynara-error.h index 66d75f0..ac69412 100644 --- a/src/include/cynara-error.h +++ b/src/include/cynara-error.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. @@ -32,6 +32,8 @@ * result codes beginning with negative codes indicate an error. * @{ */ +/*! \brief indicating access that cannot be resolved without further actions*/ +#define CYNARA_API_ACCESS_NOT_RESOLVED 3 /*! \brief indicating access that was checked is allowed */ #define CYNARA_API_ACCESS_ALLOWED 2 -- 2.7.4 From cc65a1523566af45fb9e44c620e38b2fd480a99b Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Tue, 10 Feb 2015 16:21:42 +0100 Subject: [PATCH 02/16] Create request and response types for simple check client API call Create SimpleCheckResponse and SimpleCheckRequest. Change-Id: I75796fb035ac9dfd5ecbe1e8bfc68d37a55ba6f4 --- src/common/CMakeLists.txt | 2 + src/common/protocol/ProtocolOpCode.h | 7 +++- src/common/request/RequestTaker.cpp | 7 +++- src/common/request/RequestTaker.h | 4 +- src/common/request/SimpleCheckRequest.cpp | 34 ++++++++++++++++ src/common/request/SimpleCheckRequest.h | 54 +++++++++++++++++++++++++ src/common/request/pointers.h | 6 ++- src/common/response/ResponseTaker.cpp | 8 +++- src/common/response/ResponseTaker.h | 4 +- src/common/response/SimpleCheckResponse.cpp | 34 ++++++++++++++++ src/common/response/SimpleCheckResponse.h | 63 +++++++++++++++++++++++++++++ src/common/response/pointers.h | 6 ++- 12 files changed, 221 insertions(+), 8 deletions(-) create mode 100644 src/common/request/SimpleCheckRequest.cpp create mode 100644 src/common/request/SimpleCheckRequest.h create mode 100644 src/common/response/SimpleCheckResponse.cpp create mode 100644 src/common/response/SimpleCheckResponse.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 96b747c..885e325 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -52,6 +52,7 @@ SET(COMMON_SOURCES ${COMMON_PATH}/request/RequestTaker.cpp ${COMMON_PATH}/request/SetPoliciesRequest.cpp ${COMMON_PATH}/request/SignalRequest.cpp + ${COMMON_PATH}/request/SimpleCheckRequest.cpp ${COMMON_PATH}/response/AdminCheckResponse.cpp ${COMMON_PATH}/response/AgentActionResponse.cpp ${COMMON_PATH}/response/AgentRegisterResponse.cpp @@ -61,6 +62,7 @@ SET(COMMON_SOURCES ${COMMON_PATH}/response/DescriptionListResponse.cpp ${COMMON_PATH}/response/ListResponse.cpp ${COMMON_PATH}/response/ResponseTaker.cpp + ${COMMON_PATH}/response/SimpleCheckResponse.cpp ${COMMON_PATH}/sockets/Socket.cpp ${COMMON_PATH}/sockets/SocketClient.cpp ${COMMON_PATH}/types/PolicyBucket.cpp diff --git a/src/common/protocol/ProtocolOpCode.h b/src/common/protocol/ProtocolOpCode.h index 6aefb10..efd6a63 100644 --- a/src/common/protocol/ProtocolOpCode.h +++ b/src/common/protocol/ProtocolOpCode.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 * * Contact: Lukasz Wojciechowski * @@ -19,6 +19,7 @@ * @file src/common/protocol/ProtocolOpCode.h * @author Adam Malinowski * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 * @brief Declaration of protocol frame operation codes. */ @@ -36,8 +37,10 @@ enum ProtocolOpCode : uint8_t { OpCheckPolicyResponse, OpCancelRequest, OpCancelResponse, + OpSimpleCheckPolicyRequest, + OpSimpleCheckPolicyResponse, - /** Opcodes 4 - 19 are reserved for future use */ + /** Opcodes 6 - 19 are reserved for future use */ /** Admin operations */ OpInsertOrUpdateBucket = 20, diff --git a/src/common/request/RequestTaker.cpp b/src/common/request/RequestTaker.cpp index ea25f16..1f238fd 100644 --- a/src/common/request/RequestTaker.cpp +++ b/src/common/request/RequestTaker.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/request/RequestTaker.cpp * @author Lukasz Wojciechowski * @author Adam Malinowski + * @author Zofia Abramowska * @version 1.0 * @brief This file implements RequestTaker class */ @@ -81,6 +82,10 @@ void RequestTaker::execute(RequestContextPtr context UNUSED, SignalRequestPtr re throw NotImplementedException(); } +void RequestTaker::execute(RequestContextPtr context UNUSED, SimpleCheckRequestPtr request UNUSED) { + throw NotImplementedException(); +} + void RequestTaker::contextClosed(RequestContextPtr context UNUSED) { throw NotImplementedException(); } diff --git a/src/common/request/RequestTaker.h b/src/common/request/RequestTaker.h index e6e3f08..a38ab28 100644 --- a/src/common/request/RequestTaker.h +++ b/src/common/request/RequestTaker.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/request/RequestTaker.h * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 * @brief This file defines RequestTaker class */ @@ -44,6 +45,7 @@ public: virtual void execute(RequestContextPtr context, RemoveBucketRequestPtr request); virtual void execute(RequestContextPtr context, SetPoliciesRequestPtr request); virtual void execute(RequestContextPtr context, SignalRequestPtr request); + virtual void execute(RequestContextPtr context, SimpleCheckRequestPtr request); virtual void contextClosed(RequestContextPtr context); }; diff --git a/src/common/request/SimpleCheckRequest.cpp b/src/common/request/SimpleCheckRequest.cpp new file mode 100644 index 0000000..ecf8e06 --- /dev/null +++ b/src/common/request/SimpleCheckRequest.cpp @@ -0,0 +1,34 @@ +/* + * 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/request/SimpleCheckRequest.cpp + * @author Zofia Abramowska + * @version 1.0 + * @brief This file implements simple check request class + */ + +#include + +#include "SimpleCheckRequest.h" + +namespace Cynara { + +void SimpleCheckRequest::execute(RequestPtr self, RequestTakerPtr taker, + RequestContextPtr context) const { + taker->execute(context, std::dynamic_pointer_cast(self)); +} + +} // namespace Cynara diff --git a/src/common/request/SimpleCheckRequest.h b/src/common/request/SimpleCheckRequest.h new file mode 100644 index 0000000..2748b0e --- /dev/null +++ b/src/common/request/SimpleCheckRequest.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 src/common/request/SimpleCheckRequest.h + * @author Zofia Abramowska + * @version 1.0 + * @brief This file defines simple check request class + */ + +#ifndef SRC_COMMON_REQUEST_SIMPLECHECKREQUEST_H_ +#define SRC_COMMON_REQUEST_SIMPLECHECKREQUEST_H_ + +#include + +#include +#include +#include + +namespace Cynara { + +class SimpleCheckRequest : public Request { +private: + PolicyKey m_key; + +public: + SimpleCheckRequest(const PolicyKey &key, ProtocolFrameSequenceNumber sequenceNumber) : + Request(sequenceNumber), m_key(key) { + } + + virtual ~SimpleCheckRequest() {}; + + const PolicyKey &key(void) const { + return m_key; + } + + virtual void execute(RequestPtr self, RequestTakerPtr taker, RequestContextPtr context) const; +}; + +} // namespace Cynara + +#endif /* SRC_COMMON_REQUEST_SIMPLECHECKREQUEST_H_ */ diff --git a/src/common/request/pointers.h b/src/common/request/pointers.h index be1fdeb..227e8fc 100644 --- a/src/common/request/pointers.h +++ b/src/common/request/pointers.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/request/pointers.h * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 * @brief This file defines request classes pointers */ @@ -72,6 +73,9 @@ typedef std::shared_ptr SetPoliciesRequestPtr; class SignalRequest; typedef std::shared_ptr SignalRequestPtr; +class SimpleCheckRequest; +typedef std::shared_ptr SimpleCheckRequestPtr; + } // namespace Cynara #endif /* SRC_COMMON_REQUEST_POINTERS_H_ */ diff --git a/src/common/response/ResponseTaker.cpp b/src/common/response/ResponseTaker.cpp index 492af6e..410f8c9 100644 --- a/src/common/response/ResponseTaker.cpp +++ b/src/common/response/ResponseTaker.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 src/common/response/ResponseTaker.cpp * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 * @brief This file implements ResponseTaker class */ @@ -64,4 +65,9 @@ void ResponseTaker::execute(RequestContextPtr context UNUSED, ListResponsePtr re throw NotImplementedException(); } +void ResponseTaker::execute(RequestContextPtr context UNUSED, + SimpleCheckResponsePtr response UNUSED) { + throw NotImplementedException(); +} + } // namespace Cynara diff --git a/src/common/response/ResponseTaker.h b/src/common/response/ResponseTaker.h index c642b4f..31b7714 100644 --- a/src/common/response/ResponseTaker.h +++ b/src/common/response/ResponseTaker.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/ResponseTaker.h * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 * @brief This file defines ResponseTaker class */ @@ -41,6 +42,7 @@ public: virtual void execute(RequestContextPtr context, CodeResponsePtr response); virtual void execute(RequestContextPtr context, DescriptionListResponsePtr response); virtual void execute(RequestContextPtr context, ListResponsePtr response); + virtual void execute(RequestContextPtr context, SimpleCheckResponsePtr response); }; } // namespace Cynara diff --git a/src/common/response/SimpleCheckResponse.cpp b/src/common/response/SimpleCheckResponse.cpp new file mode 100644 index 0000000..52976fa --- /dev/null +++ b/src/common/response/SimpleCheckResponse.cpp @@ -0,0 +1,34 @@ +/* + * 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/response/SimpleCheckResponse.cpp + * @author Zofia Abramowska + * @version 1.0 + * @brief This file implements simple check response class + */ + +#include + +#include "SimpleCheckResponse.h" + +namespace Cynara { + +void SimpleCheckResponse::execute(ResponsePtr self, ResponseTakerPtr taker, + RequestContextPtr context) const { + taker->execute(context, std::dynamic_pointer_cast(self)); +} + +} // namespace Cynara diff --git a/src/common/response/SimpleCheckResponse.h b/src/common/response/SimpleCheckResponse.h new file mode 100644 index 0000000..8fe28e6 --- /dev/null +++ b/src/common/response/SimpleCheckResponse.h @@ -0,0 +1,63 @@ +/* + * 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/response/SimpleCheckResponse.h + * @author Zofia Abramowska + * @version 1.0 + * @brief This file defines response class for simple check request + */ + +#ifndef SRC_COMMON_RESPONSE_SIMPLECHECKRESPONSE_H_ +#define SRC_COMMON_RESPONSE_SIMPLECHECKRESPONSE_H_ + +#include + +#include + +#include +#include +#include + +namespace Cynara { + +class SimpleCheckResponse : public Response { +public: + SimpleCheckResponse(int32_t retValue, const PolicyResult &result, + ProtocolFrameSequenceNumber sequenceNumber) : + Response(sequenceNumber), m_resultRef(result), m_retValue(retValue) { + } + + SimpleCheckResponse(int retValue, ProtocolFrameSequenceNumber sequenceNumber); + + PolicyResult getResult(void) const { + return m_resultRef; + } + + int32_t getReturnValue(void) const { + return m_retValue; + } + virtual ~SimpleCheckResponse() {} + + virtual void execute(ResponsePtr self, ResponseTakerPtr taker, + RequestContextPtr context) const; +private: + const PolicyResult m_resultRef; + const int32_t m_retValue; +}; + +} // namespace Cynara + +#endif /* SRC_COMMON_RESPONSE_SIMPLECHECKRESPONSE_H_ */ diff --git a/src/common/response/pointers.h b/src/common/response/pointers.h index 5e90289..f30415f 100644 --- a/src/common/response/pointers.h +++ b/src/common/response/pointers.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/pointers.h * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 * @brief This file defines response classes pointers */ @@ -54,6 +55,9 @@ typedef std::shared_ptr ListResponsePtr; class Response; typedef std::shared_ptr ResponsePtr; +class SimpleCheckResponse; +typedef std::shared_ptr SimpleCheckResponsePtr; + class ResponseTaker; typedef std::shared_ptr ResponseTakerPtr; typedef std::weak_ptr ResponseTakerWeakPtr; -- 2.7.4 From 7acf06e3c1429405bbfdebd92b12a0fa06376862 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Mon, 9 Feb 2015 16:14:34 +0100 Subject: [PATCH 03/16] Add logic side implementation of simple check Add implementation of client and service logic side implementation of simple check API and request and response handling. Change-Id: Ie59fb86e20fae383196025580b164c15e855bc62 --- src/client/logic/Logic.cpp | 67 ++++++++++++++++++++++++++++++++++----------- src/client/logic/Logic.h | 3 ++ src/service/logic/Logic.cpp | 57 ++++++++++++++++++++++++++++++++++++++ src/service/logic/Logic.h | 2 ++ 4 files changed, 113 insertions(+), 16 deletions(-) diff --git a/src/client/logic/Logic.cpp b/src/client/logic/Logic.cpp index c171cce..9f738fb 100644 --- a/src/client/logic/Logic.cpp +++ b/src/client/logic/Logic.cpp @@ -35,8 +35,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -65,12 +67,10 @@ int Logic::check(const std::string &client, const ClientSession &session, const PolicyKey key(client, user, privilege); int ret = m_cache->get(session, key); - //Any other situation than cache miss if (ret != CYNARA_API_CACHE_MISS) { return ret; } - //No value in Cache PolicyResult result; ret = requestResult(key, result); if (ret != CYNARA_API_SUCCESS) { @@ -83,11 +83,24 @@ int Logic::check(const std::string &client, const ClientSession &session, const int Logic::simpleCheck(const std::string &client, const ClientSession &session, const std::string &user, const std::string &privilege) { - (void)client; - (void)session; - (void)user; - (void)privilege; - return CYNARA_API_ACCESS_NOT_RESOLVED; + if (!ensureConnection()) + return CYNARA_API_SERVICE_NOT_AVAILABLE; + + PolicyKey key(client, user, privilege); + int ret = m_cache->get(session, key); + if (ret != CYNARA_API_CACHE_MISS) { + return ret; + } + + PolicyResult result; + ret = requestSimpleResult(key, result); + if (ret != CYNARA_API_SUCCESS) { + if (ret != CYNARA_API_ACCESS_NOT_RESOLVED) + LOGE("Error fetching response for simpleCheck."); + return ret; + } + + return m_cache->update(session, key, result); } bool Logic::ensureConnection(void) { @@ -100,33 +113,55 @@ bool Logic::ensureConnection(void) { return false; } -int Logic::requestResult(const PolicyKey &key, PolicyResult &result) { +template +std::shared_ptr Logic::requestResponse(const PolicyKey &key) { ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber(); //Ask cynara service - CheckResponsePtr checkResponse; - RequestPtr request = std::make_shared(key, sequenceNumber); + std::shared_ptr reqResponse; + RequestPtr request = std::make_shared(key, sequenceNumber); ResponsePtr response; while (!(response = m_socket->askCynaraServer(request))) { onDisconnected(); if (!m_socket->connect()) - return CYNARA_API_SERVICE_NOT_AVAILABLE; + return nullptr; } - checkResponse = std::dynamic_pointer_cast(response); + reqResponse = std::dynamic_pointer_cast(response); + return reqResponse; +} + +int Logic::requestResult(const PolicyKey &key, PolicyResult &result) { + auto checkResponse = requestResponse(key); if (!checkResponse) { - LOGC("Critical error. Casting Response to CheckResponse failed."); - return CYNARA_API_ACCESS_DENIED; + LOGC("Critical error. Requesting CheckResponse failed."); + return CYNARA_API_SERVICE_NOT_AVAILABLE; } - LOGD("checkResponse: policyType = %" PRIu16 ", metadata = %s", checkResponse->m_resultRef.policyType(), checkResponse->m_resultRef.metadata().c_str()); - result = checkResponse->m_resultRef; return CYNARA_API_SUCCESS; } +int Logic::requestSimpleResult(const PolicyKey &key, PolicyResult &result) { + auto simpleCheckResponse = requestResponse(key); + if (!simpleCheckResponse) { + LOGC("Critical error. Requesting SimpleCheckResponse failed."); + return CYNARA_API_SERVICE_NOT_AVAILABLE; + } + + if (simpleCheckResponse->getReturnValue() != CYNARA_API_SUCCESS) + return simpleCheckResponse->getReturnValue(); + + LOGD("SimpleCheckResponse: policyType = %" PRIu16 ", metadata = %s", + simpleCheckResponse->getResult().policyType(), + simpleCheckResponse->getResult().metadata().c_str()); + + result = simpleCheckResponse->getResult(); + return CYNARA_API_SUCCESS; +} + void Logic::onDisconnected(void) { m_cache->clear(); } diff --git a/src/client/logic/Logic.h b/src/client/logic/Logic.h index 695f7cd..e98f950 100644 --- a/src/client/logic/Logic.h +++ b/src/client/logic/Logic.h @@ -56,7 +56,10 @@ private: void onDisconnected(void); bool ensureConnection(void); + template + std::shared_ptr requestResponse(const PolicyKey &key); int requestResult(const PolicyKey &key, PolicyResult &result); + int requestSimpleResult(const PolicyKey &key, PolicyResult &result); }; } // namespace Cynara diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index 5e3f82a..95656e5 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -16,6 +16,7 @@ /** * @file src/service/logic/Logic.cpp * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 * @brief This file implements main class of logic layer in cynara service */ @@ -51,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +60,7 @@ #include #include #include +#include #include #include
@@ -367,6 +370,60 @@ void Logic::execute(RequestContextPtr context, SetPoliciesRequestPtr request) { request->sequenceNumber())); } +void Logic::execute(RequestContextPtr context, SimpleCheckRequestPtr request) { + int retValue = CYNARA_API_SUCCESS; + PolicyResult result; + PolicyKey key = request->key(); + result = m_storage->checkPolicy(key); + + switch (result.policyType()) { + case PredefinedPolicyType::ALLOW: + LOGD("simple check of policy key <%s> returned ALLOW", key.toString().c_str()); + break; + case PredefinedPolicyType::DENY: + LOGD("simple check of policy key <%s> returned DENY", key.toString().c_str()); + break; + default: { + ExternalPluginPtr plugin = m_pluginManager->getPlugin(result.policyType()); + if (!plugin) { + LOGE("Plugin not found for policy: [0x%x]", result.policyType()); + result = PolicyResult(PredefinedPolicyType::DENY); + retValue = CYNARA_API_SUCCESS; + break; + } + + ServicePluginInterfacePtr servicePlugin = + std::dynamic_pointer_cast(plugin); + if (!servicePlugin) { + LOGE("Couldn't cast plugin pointer to ServicePluginInterface"); + result = PolicyResult(PredefinedPolicyType::DENY); + retValue = CYNARA_API_SUCCESS; + break; + } + + AgentType requiredAgent; + PluginData pluginData; + auto ret = servicePlugin->check(key.client().toString(), key.user().toString(), + key.privilege().toString(), result, requiredAgent, + pluginData); + switch (ret) { + case ServicePluginInterface::PluginStatus::ANSWER_READY: + LOGD("simple check of policy key <%s> in plugin returned [" PRIu16 "]", + key.toString().c_str(), result.policyType()); + break; + case ServicePluginInterface::PluginStatus::ANSWER_NOTREADY: + retValue = CYNARA_API_ACCESS_NOT_RESOLVED; + break; + default: + result = PolicyResult(PredefinedPolicyType::DENY); + retValue = CYNARA_API_SUCCESS; + } + } + } + context->returnResponse(context, std::make_shared(retValue, result, + request->sequenceNumber())); +} + void Logic::checkPoliciesTypes(const std::map> &policies, bool allowBucket, bool allowNone) { for (const auto &group : policies) { diff --git a/src/service/logic/Logic.h b/src/service/logic/Logic.h index fc577bd..444f734 100644 --- a/src/service/logic/Logic.h +++ b/src/service/logic/Logic.h @@ -16,6 +16,7 @@ /** * @file src/service/logic/Logic.h * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 * @brief This file defines main class of logic layer in cynara service */ @@ -82,6 +83,7 @@ public: virtual void execute(RequestContextPtr context, RemoveBucketRequestPtr request); virtual void execute(RequestContextPtr context, SetPoliciesRequestPtr request); virtual void execute(RequestContextPtr context, SignalRequestPtr request); + virtual void execute(RequestContextPtr context, SimpleCheckRequestPtr request); virtual void contextClosed(RequestContextPtr context); -- 2.7.4 From be6cd08e0ba56f50c792a27961c9df2b55f3a0b3 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Tue, 10 Feb 2015 16:53:39 +0100 Subject: [PATCH 04/16] Add client protocol side implementation of simple check Change-Id: I379bf96ac664827d89379b1df36d903864749a4b --- src/common/protocol/ProtocolClient.cpp | 73 +++++++++++++++++++++++++++++++++- src/common/protocol/ProtocolClient.h | 6 ++- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/common/protocol/ProtocolClient.cpp b/src/common/protocol/ProtocolClient.cpp index 3f13653..05aac89 100644 --- a/src/common/protocol/ProtocolClient.cpp +++ b/src/common/protocol/ProtocolClient.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/ProtocolClient.cpp * @author Lukasz Wojciechowski * @author Adam Malinowski + * @author Zofia Abramowska * @version 1.0 * @brief This file implements protocol class for communication with client */ @@ -34,8 +35,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -73,6 +76,20 @@ RequestPtr ProtocolClient::deserializeCheckRequest(void) { m_frameHeader.sequenceNumber()); } +RequestPtr ProtocolClient::deserializeSimpleCheckRequest(void) { + std::string clientId, userId, privilegeId; + + ProtocolDeserialization::deserialize(m_frameHeader, clientId); + ProtocolDeserialization::deserialize(m_frameHeader, userId); + ProtocolDeserialization::deserialize(m_frameHeader, privilegeId); + + LOGD("Deserialized SimpleCheckRequest: client <%s>, user <%s>, privilege <%s>", + clientId.c_str(), userId.c_str(), privilegeId.c_str()); + + return std::make_shared(PolicyKey(clientId, userId, privilegeId), + m_frameHeader.sequenceNumber()); +} + RequestPtr ProtocolClient::extractRequestFromBuffer(BinaryQueuePtr bufferQueue) { ProtocolFrameSerializer::deserializeHeader(m_frameHeader, bufferQueue); @@ -88,6 +105,8 @@ RequestPtr ProtocolClient::extractRequestFromBuffer(BinaryQueuePtr bufferQueue) return deserializeCheckRequest(); case OpCancelRequest: return deserializeCancelRequest(); + case OpSimpleCheckPolicyRequest: + return deserializeSimpleCheckRequest(); default: throw InvalidProtocolException(InvalidProtocolException::WrongOpCode); break; @@ -117,6 +136,24 @@ ResponsePtr ProtocolClient::deserializeCheckResponse(void) { return std::make_shared(policyResult, m_frameHeader.sequenceNumber()); } +ResponsePtr ProtocolClient::deserializeSimpleCheckResponse() { + int32_t retValue; + PolicyType result; + PolicyResult::PolicyMetadata additionalInfo; + + ProtocolDeserialization::deserialize(m_frameHeader, retValue); + ProtocolDeserialization::deserialize(m_frameHeader, result); + ProtocolDeserialization::deserialize(m_frameHeader, additionalInfo); + + const PolicyResult policyResult(result, additionalInfo); + + LOGD("Deserialized SimpleCheckResponse: retVal [%" PRIi32 "%] result [%" PRIu16 "]," + " metadata <%s>", retValue, policyResult.policyType(), policyResult.metadata().c_str()); + + return std::make_shared(retValue, policyResult, + m_frameHeader.sequenceNumber()); +} + ResponsePtr ProtocolClient::extractResponseFromBuffer(BinaryQueuePtr bufferQueue) { ProtocolFrameSerializer::deserializeHeader(m_frameHeader, bufferQueue); @@ -131,6 +168,8 @@ ResponsePtr ProtocolClient::extractResponseFromBuffer(BinaryQueuePtr bufferQueue return deserializeCheckResponse(); case OpCancelResponse: return deserializeCancelResponse(); + case OpSimpleCheckPolicyResponse: + return deserializeSimpleCheckResponse(); default: throw InvalidProtocolException(InvalidProtocolException::WrongOpCode); break; @@ -165,6 +204,21 @@ void ProtocolClient::execute(RequestContextPtr context, CheckRequestPtr request) ProtocolFrameSerializer::finishSerialization(frame, *(context->responseQueue())); } +void ProtocolClient::execute(RequestContextPtr context, SimpleCheckRequestPtr request) { + ProtocolFrame frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber()); + + LOGD("Serializing SimpleCheckRequest: client <%s>, user <%s>, privilege <%s>", + request->key().client().value().c_str(), request->key().user().value().c_str(), + request->key().privilege().value().c_str()); + + ProtocolSerialization::serialize(frame, OpSimpleCheckPolicyRequest); + ProtocolSerialization::serialize(frame, request->key().client().value()); + ProtocolSerialization::serialize(frame, request->key().user().value()); + ProtocolSerialization::serialize(frame, request->key().privilege().value()); + + ProtocolFrameSerializer::finishSerialization(frame, *(context->responseQueue())); +} + void ProtocolClient::execute(RequestContextPtr context, CancelResponsePtr response) { ProtocolFrame frame = ProtocolFrameSerializer::startSerialization( response->sequenceNumber()); @@ -191,4 +245,21 @@ void ProtocolClient::execute(RequestContextPtr context, CheckResponsePtr respons ProtocolFrameSerializer::finishSerialization(frame, *(context->responseQueue())); } +void ProtocolClient::execute(RequestContextPtr context, SimpleCheckResponsePtr response) { + ProtocolFrame frame = ProtocolFrameSerializer::startSerialization( + response->sequenceNumber()); + + LOGD("Serializing SimpleCheckResponse: op [%" PRIu8 "], retVal [%" PRIi32 "]," + " policyType [%" PRIu16 "], metadata <%s>", OpCheckPolicyResponse, + response->getReturnValue(), response->getResult().policyType(), + response->getResult().metadata().c_str()); + + ProtocolSerialization::serialize(frame, OpSimpleCheckPolicyResponse); + ProtocolSerialization::serialize(frame, response->getReturnValue()); + ProtocolSerialization::serialize(frame, response->getResult().policyType()); + ProtocolSerialization::serialize(frame, response->getResult().metadata()); + + ProtocolFrameSerializer::finishSerialization(frame, *(context->responseQueue())); +} + } // namespace Cynara diff --git a/src/common/protocol/ProtocolClient.h b/src/common/protocol/ProtocolClient.h index a1c5110..7ed41b1 100644 --- a/src/common/protocol/ProtocolClient.h +++ b/src/common/protocol/ProtocolClient.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. @@ -43,16 +43,20 @@ public: virtual void execute(RequestContextPtr context, CancelRequestPtr request); virtual void execute(RequestContextPtr context, CheckRequestPtr request); + virtual void execute(RequestContextPtr context, SimpleCheckRequestPtr request); virtual void execute(RequestContextPtr context, CancelResponsePtr response); virtual void execute(RequestContextPtr context, CheckResponsePtr response); + virtual void execute(RequestContextPtr context, SimpleCheckResponsePtr request); private: RequestPtr deserializeCancelRequest(void); RequestPtr deserializeCheckRequest(void); + RequestPtr deserializeSimpleCheckRequest(void); ResponsePtr deserializeCancelResponse(void); ResponsePtr deserializeCheckResponse(void); + ResponsePtr deserializeSimpleCheckResponse(void); }; } // namespace Cynara -- 2.7.4 From 66b5ad8e0b0906e7b3919d45d8f3f403cb1052f1 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Thu, 12 Feb 2015 17:39:21 +0100 Subject: [PATCH 05/16] Fix pluginCheck in service logic Change-Id: I835c471b38756a9d3cee1ddfe4c4b90591744aa4 --- src/service/logic/Logic.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index 95656e5..e92808e 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -210,8 +210,9 @@ bool Logic::pluginCheck(const RequestContextPtr &context, const PolicyKey &key, ServicePluginInterfacePtr servicePlugin = std::dynamic_pointer_cast(plugin); - if (!plugin) { - throw PluginNotFoundException(result); + if (!servicePlugin) { + result = PolicyResult(PredefinedPolicyType::DENY); + return true; } AgentType requiredAgent; @@ -243,7 +244,8 @@ bool Logic::pluginCheck(const RequestContextPtr &context, const PolicyKey &key, } return false; default: - throw PluginErrorException(key); // This 'throw' should be removed or handled properly. + result = PolicyResult(PredefinedPolicyType::DENY); + return true; } } -- 2.7.4 From 56ffb7914c4f8410a8bc71a7f9d8a06c5117510d Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Thu, 22 Jan 2015 11:25:00 +0100 Subject: [PATCH 06/16] Add API description of cynara_strerror() Introduce new API call of cynara_strerror() used to obtain error message from error number. Change-Id: Ibd5b5a2af700a04fe8b3bfea8fde715b17db3a61 --- src/common/CMakeLists.txt | 1 + src/common/error/api.cpp | 96 ++++++++++++++++++++++++++++++++++++++++++++++ src/include/cynara-error.h | 55 ++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 src/common/error/api.cpp diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 885e325..07167bc 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -28,6 +28,7 @@ INCLUDE_DIRECTORIES( SET(COMMON_SOURCES ${COMMON_PATH}/config/PathConfig.cpp ${COMMON_PATH}/containers/BinaryQueue.cpp + ${COMMON_PATH}/error/api.cpp ${COMMON_PATH}/lock/FileLock.cpp ${COMMON_PATH}/log/log.cpp ${COMMON_PATH}/plugin/PluginManager.cpp diff --git a/src/common/error/api.cpp b/src/common/error/api.cpp new file mode 100644 index 0000000..d8243b4 --- /dev/null +++ b/src/common/error/api.cpp @@ -0,0 +1,96 @@ +/* + * 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/error/api.cpp + * @author Aleksander Zdyb + * @version 1.0 + * @brief Implementation of cynara_strerror + */ + +#include + +#include + +int cynara_strerror(int errnum, char *buf, size_t buflen) { + if (buf == nullptr) + return CYNARA_API_INVALID_PARAM; + + const char *message = nullptr; + + switch (errnum) { + case CYNARA_API_ACCESS_NOT_RESOLVED: + message = "Access not resolved"; + break; + case CYNARA_API_ACCESS_ALLOWED: + message = "Access granted"; + break; + case CYNARA_API_ACCESS_DENIED: + message = "Access denied"; + break; + case CYNARA_API_SUCCESS: + message = "Operation successful"; + break; + case CYNARA_API_CACHE_MISS: + message = "Value not in cache"; + break; + case CYNARA_API_MAX_PENDING_REQUESTS: + message = "Pending requests exceeded maximum"; + break; + case CYNARA_API_OUT_OF_MEMORY: + message = "Out of memory"; + break; + case CYNARA_API_INVALID_PARAM: + message = "Invalid param"; + break; + case CYNARA_API_SERVICE_NOT_AVAILABLE: + message = "Service not available"; + break; + case CYNARA_API_METHOD_NOT_SUPPORTED: + message = "Method not supported"; + break; + case CYNARA_API_OPERATION_NOT_ALLOWED: + message = "Operation not allowed"; + break; + case CYNARA_API_OPERATION_FAILED: + message = "Operation failed"; + break; + case CYNARA_API_BUCKET_NOT_FOUND: + message = "Bucket not found"; + break; + case CYNARA_API_UNKNOWN_ERROR: + message = "Unknown error"; + break; + case CYNARA_API_CONFIGURATION_ERROR: + message = "Configuration error"; + break; + case CYNARA_API_INVALID_COMMANDLINE_PARAM: + message = "Invalid parameter in command-line"; + break; + case CYNARA_API_BUFFER_TOO_SHORT: + message = "Buffer too short"; + break; + } + + if (message == nullptr) + return CYNARA_API_INVALID_PARAM; + + if (buflen < strlen(message) + 1) + return CYNARA_API_BUFFER_TOO_SHORT; + + strcpy(buf, message); + + return CYNARA_API_SUCCESS; +} diff --git a/src/include/cynara-error.h b/src/include/cynara-error.h index ac69412..875d877 100644 --- a/src/include/cynara-error.h +++ b/src/include/cynara-error.h @@ -26,6 +26,8 @@ #ifndef CYNARA_ERROR_H #define CYNARA_ERROR_H +#include + /** * \name Return Codes * exported by the foundation API. @@ -79,6 +81,59 @@ /*! \brief indicating invalid parameter in command-line */ #define CYNARA_API_INVALID_COMMANDLINE_PARAM -12 + +/*! \brief indicating that provided buffer is too short */ +#define CYNARA_API_BUFFER_TOO_SHORT -13 /** @}*/ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \par Description: + * Returns the error string in the user-supplied buffer buf of length buflen. + * + * \par Purpose: + * This function populates passed argument buf with a string that describes the error code + * passed in the argument errnum, possibly using the LC_MESSAGES part of the current locale + * to select the appropriate language. + * + * \par Typical use case: + * Once after any of API functions returns negative value (if the error message is to be presented + * to the user). + * + * \par Method of function operation: + * This function copies error string to memory pointed by argument buf along with termination + * character ('\0'). + * + * \par Sync (or) async: + * This is a synchronous API. + * + * \par Thread-safety: + * This function is thread-safe as long as setlocale() is not invoked concurrently. + * + * \par Important notes: + * This function copies error string to memory pointed by argument buf only if the buffer is + * of sufficient size (indicated by argument buflen). User is responsible for allocating sufficient + * memory for both error string and termination character ('\0'). + * Moreover, the user must not invoke setlocale() concurrently with this function, because results + * are unspecified. + * + * \param[in] errnum error number + * \param[out] buf buffer for error message + * \param[in] buflen buffer size + * + * \return CYNARA_API_SUCCESS on success, CYNARA_API_BUFFER_TOO_SHORT, if error message couldn't fit + * into allocated buffer, or CYNARA_API_INVALID_PARAM if errnum is not a valid error number + * or argument buf is NULL. + * + * \brief Obtain error message from error number. + */ +int cynara_strerror(int errnum, char *buf, size_t buflen); + +#ifdef __cplusplus +} +#endif + #endif /* CYNARA_ERROR_H */ -- 2.7.4 From ba91952220726c7e51f98e3c1e95b6c9dc040f0c Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Mon, 2 Feb 2015 14:11:47 +0100 Subject: [PATCH 07/16] Print error messages to stderr in Cyad Every dispatched command checks return value from Cynara API and prints possible error message using cynara_strerror() function. Call to cynara_strerror() is not of course subject to above check & print routine. Change-Id: I008d1fbd592061646478b47be8ae53bbc408cb1b --- src/cyad/BaseErrorApiWrapper.h | 38 +++++++++++++++++ src/cyad/CMakeLists.txt | 1 + src/cyad/CommandsDispatcher.cpp | 86 +++++++++++++++++++++++++++++++-------- src/cyad/CommandsDispatcher.h | 8 +++- src/cyad/Cyad.cpp | 4 +- src/cyad/Cyad.h | 4 +- src/cyad/ErrorApiWrapper.cpp | 37 +++++++++++++++++ src/cyad/ErrorApiWrapper.h | 39 ++++++++++++++++++ test/cyad/FakeErrorApiWrapper.h | 39 ++++++++++++++++++ test/cyad/commands_dispatcher.cpp | 60 +++++++++++++++++++-------- 10 files changed, 279 insertions(+), 37 deletions(-) create mode 100644 src/cyad/BaseErrorApiWrapper.h create mode 100644 src/cyad/ErrorApiWrapper.cpp create mode 100644 src/cyad/ErrorApiWrapper.h create mode 100644 test/cyad/FakeErrorApiWrapper.h diff --git a/src/cyad/BaseErrorApiWrapper.h b/src/cyad/BaseErrorApiWrapper.h new file mode 100644 index 0000000..721edef --- /dev/null +++ b/src/cyad/BaseErrorApiWrapper.h @@ -0,0 +1,38 @@ +/* + * 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/cyad/BaseErrorApiWrapper.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief Wrapper around cynara-error API (base) + */ + +#ifndef SRC_CYAD_BASEERRORAPIWRAPPER_H_ +#define SRC_CYAD_BASEERRORAPIWRAPPER_H_ + +#include + +namespace Cynara { + +class BaseErrorApiWrapper { +public: + virtual ~BaseErrorApiWrapper() {}; + virtual int cynara_strerror(int errnum, char *buf, size_t buflen) = 0; +}; + +} /* namespace Cynara */ + +#endif /* SRC_CYAD_BASEERRORAPIWRAPPER_H_ */ diff --git a/src/cyad/CMakeLists.txt b/src/cyad/CMakeLists.txt index 1415f6d..1873046 100644 --- a/src/cyad/CMakeLists.txt +++ b/src/cyad/CMakeLists.txt @@ -30,6 +30,7 @@ SET(CYAD_SOURCES ${CYAD_PATH}/CommandlineParser/HumanReadableParser.cpp ${CYAD_PATH}/CommandsDispatcher.cpp ${CYAD_PATH}/DispatcherIO.cpp + ${CYAD_PATH}/ErrorApiWrapper.cpp ${CYAD_PATH}/main.cpp ) diff --git a/src/cyad/CommandsDispatcher.cpp b/src/cyad/CommandsDispatcher.cpp index 0b8f0c0..6862a42 100644 --- a/src/cyad/CommandsDispatcher.cpp +++ b/src/cyad/CommandsDispatcher.cpp @@ -35,20 +35,26 @@ namespace Cynara { -CommandsDispatcher::CommandsDispatcher(BaseDispatcherIO &io, BaseAdminApiWrapper &adminApiWrapper) - : m_io(io), m_adminApiWrapper(adminApiWrapper), m_cynaraAdmin(nullptr) +CommandsDispatcher::CommandsDispatcher(BaseDispatcherIO &io, BaseAdminApiWrapper &adminApiWrapper, + BaseErrorApiWrapper &errorApiWrapper) + : m_io(io), m_adminApiWrapper(adminApiWrapper), m_errorApiWrapper(errorApiWrapper), + m_cynaraAdmin(nullptr) { auto ret = m_adminApiWrapper.cynara_admin_initialize(&m_cynaraAdmin); - if (ret != CYNARA_API_SUCCESS) + if (ret != CYNARA_API_SUCCESS) { + printAdminApiError(ret); throw AdminLibraryInitializationFailedException(ret); + } } CommandsDispatcher::~CommandsDispatcher() { - m_adminApiWrapper.cynara_admin_finish(m_cynaraAdmin); + auto ret = m_adminApiWrapper.cynara_admin_finish(m_cynaraAdmin); + if (ret != CYNARA_API_SUCCESS) + printAdminApiError(ret); } int CommandsDispatcher::execute(CyadCommand &) { - m_io.cout() << "Whatever you wanted, it's not implemented" << std::endl; + m_io.cerr() << "Whatever you wanted, it's not implemented" << std::endl; return CYNARA_API_UNKNOWN_ERROR; } @@ -58,25 +64,35 @@ int CommandsDispatcher::execute(HelpCyadCommand &) { } int CommandsDispatcher::execute(ErrorCyadCommand &result) { - m_io.cout() << "There was an error in command-line options:" << std::endl; - m_io.cout() << result.message() << std::endl; + m_io.cerr() << "There was an error in command-line options:" << std::endl; + m_io.cerr() << result.message() << std::endl; - m_io.cout() << std::endl << CmdlineOpts::makeHelp() << std::endl; + m_io.cerr() << std::endl << CmdlineOpts::makeHelp() << std::endl; return CYNARA_API_INVALID_COMMANDLINE_PARAM; } int CommandsDispatcher::execute(DeleteBucketCyadCommand &result) { - return m_adminApiWrapper.cynara_admin_set_bucket(m_cynaraAdmin, result.bucketId().c_str(), - CYNARA_ADMIN_DELETE, nullptr); + auto ret = m_adminApiWrapper.cynara_admin_set_bucket(m_cynaraAdmin, result.bucketId().c_str(), + CYNARA_ADMIN_DELETE, nullptr); + + if (ret != CYNARA_API_SUCCESS) + printAdminApiError(ret); + + return ret; } int CommandsDispatcher::execute(SetBucketCyadCommand &result) { const auto &policyResult = result.policyResult(); const char *metadata = policyResult.metadata().empty() ? nullptr : policyResult.metadata().c_str(); - return m_adminApiWrapper.cynara_admin_set_bucket(m_cynaraAdmin, - result.bucketId().c_str(), - policyResult.policyType(), metadata); + auto ret = m_adminApiWrapper.cynara_admin_set_bucket(m_cynaraAdmin, + result.bucketId().c_str(), + policyResult.policyType(), metadata); + + if (ret != CYNARA_API_SUCCESS) + printAdminApiError(ret); + + return ret; } int CommandsDispatcher::execute(SetPolicyCyadCommand &result) { @@ -85,7 +101,12 @@ int CommandsDispatcher::execute(SetPolicyCyadCommand &result) { policies.add(result.bucketId(), result.policyResult(), result.policyKey()); policies.seal(); - return m_adminApiWrapper.cynara_admin_set_policies(m_cynaraAdmin, policies.data()); + auto ret = m_adminApiWrapper.cynara_admin_set_policies(m_cynaraAdmin, policies.data()); + + if (ret != CYNARA_API_SUCCESS) + printAdminApiError(ret); + + return ret; } int CommandsDispatcher::execute(SetPolicyBulkCyadCommand &result) { @@ -93,7 +114,10 @@ int CommandsDispatcher::execute(SetPolicyBulkCyadCommand &result) { try { auto policies = Cynara::AdminPolicyParser::parse(input); - return m_adminApiWrapper.cynara_admin_set_policies(m_cynaraAdmin, policies.data()); + auto ret = m_adminApiWrapper.cynara_admin_set_policies(m_cynaraAdmin, policies.data()); + if (ret != CYNARA_API_SUCCESS) + printAdminApiError(ret); + return ret; } catch (const BucketRecordCorruptedException &ex) { m_io.cerr() << ex.message(); return CYNARA_API_INVALID_COMMANDLINE_PARAM; @@ -106,8 +130,13 @@ int CommandsDispatcher::execute(EraseCyadCommand &result) { auto user = key.user().toString().c_str(); auto privilege = key.privilege().toString().c_str(); - return m_adminApiWrapper.cynara_admin_erase(m_cynaraAdmin, result.bucketId().c_str(), - result.recursive(), client, user, privilege); + auto ret = m_adminApiWrapper.cynara_admin_erase(m_cynaraAdmin, result.bucketId().c_str(), + result.recursive(), client, user, privilege); + + if (ret != CYNARA_API_SUCCESS) + printAdminApiError(ret); + + return ret; } int CommandsDispatcher::execute(CheckCyadCommand &command) { @@ -133,6 +162,8 @@ int CommandsDispatcher::execute(CheckCyadCommand &command) { } m_io.cout() << std::endl; + } else { + printAdminApiError(ret); } return ret; @@ -180,6 +211,8 @@ int CommandsDispatcher::execute(ListPoliciesCyadCommand &command) { freePolicy(p); } free(policies); + } else { + printAdminApiError(ret); } return ret; @@ -208,9 +241,28 @@ int CommandsDispatcher::execute(ListPoliciesDescCyadCommand &) { freePolicyDesc(p); } free(descs); + } else { + printAdminApiError(ret); } return ret; } +void CommandsDispatcher::printAdminApiError(int errnum) { + const std::size_t buffSize = 256; + char buf[buffSize]; + auto ret = m_errorApiWrapper.cynara_strerror(errnum, buf, buffSize); + + m_io.cerr() << "Cynara: [" << errnum << "] "; + + if (ret == CYNARA_API_SUCCESS) + m_io.cerr() << buf << std::endl; + else if (ret == CYNARA_API_INVALID_PARAM) + m_io.cerr() << "Unknown error (sic!)" << std::endl; + else if (ret == CYNARA_API_BUFFER_TOO_SHORT) + m_io.cerr() << "Error message too long" << std::endl; + else + m_io.cerr() << "Unknown error (sic! sic!)" << std::endl; +} + } /* namespace Cynara */ diff --git a/src/cyad/CommandsDispatcher.h b/src/cyad/CommandsDispatcher.h index b8b7f29..a025303 100644 --- a/src/cyad/CommandsDispatcher.h +++ b/src/cyad/CommandsDispatcher.h @@ -24,6 +24,7 @@ #define SRC_CYAD_COMMANDSDISPATCHER_H_ #include +#include #include #include @@ -34,7 +35,8 @@ namespace Cynara { class CommandsDispatcher { public: - CommandsDispatcher(BaseDispatcherIO &io, BaseAdminApiWrapper &adminApiWrapper); + CommandsDispatcher(BaseDispatcherIO &io, BaseAdminApiWrapper &adminApiWrapper, + BaseErrorApiWrapper &errorApiWrapper); virtual ~CommandsDispatcher(); virtual int execute(CyadCommand &); @@ -49,9 +51,13 @@ public: virtual int execute(ListPoliciesCyadCommand &); virtual int execute(ListPoliciesDescCyadCommand &); +protected: + void printAdminApiError(int errnum); + private: BaseDispatcherIO &m_io; BaseAdminApiWrapper &m_adminApiWrapper; + BaseErrorApiWrapper &m_errorApiWrapper; struct cynara_admin *m_cynaraAdmin; }; diff --git a/src/cyad/Cyad.cpp b/src/cyad/Cyad.cpp index 092d9a7..1589d14 100644 --- a/src/cyad/Cyad.cpp +++ b/src/cyad/Cyad.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. @@ -33,7 +33,7 @@ namespace Cynara { Cyad::Cyad(int argc, char **argv) : m_parser(argc, argv), m_cynaraInitError(CYNARA_API_SUCCESS) { try { - m_dispatcher.reset(new CommandsDispatcher(m_io, m_adminApiWrapper)); + m_dispatcher.reset(new CommandsDispatcher(m_io, m_adminApiWrapper, m_errorApiWrapper)); } catch (const Cynara::AdminLibraryInitializationFailedException &ex) { m_cynaraInitError = ex.errorCode(); } diff --git a/src/cyad/Cyad.h b/src/cyad/Cyad.h index ba98fd8..dbb54b8 100644 --- a/src/cyad/Cyad.h +++ b/src/cyad/Cyad.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. @@ -29,6 +29,7 @@ #include #include #include +#include namespace Cynara { @@ -42,6 +43,7 @@ public: private: AdminApiWrapper m_adminApiWrapper; + ErrorApiWrapper m_errorApiWrapper; DispatcherIO m_io; std::unique_ptr m_dispatcher; CyadCommandlineParser m_parser; diff --git a/src/cyad/ErrorApiWrapper.cpp b/src/cyad/ErrorApiWrapper.cpp new file mode 100644 index 0000000..510e43a --- /dev/null +++ b/src/cyad/ErrorApiWrapper.cpp @@ -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 src/cyad/ErrorApiWrapper.cpp + * @author Aleksander Zdyb + * @version 1.0 + * @brief Wrapper around cynara-error API + */ + +#include + +#include "ErrorApiWrapper.h" + +namespace Cynara { + +ErrorApiWrapper::ErrorApiWrapper() {} + +ErrorApiWrapper::~ErrorApiWrapper() {} + +int ErrorApiWrapper::cynara_strerror(int errnum, char *buf, size_t buflen) { + return ::cynara_strerror(errnum, buf, buflen); +} + +} /* namespace Cynara */ diff --git a/src/cyad/ErrorApiWrapper.h b/src/cyad/ErrorApiWrapper.h new file mode 100644 index 0000000..472630f --- /dev/null +++ b/src/cyad/ErrorApiWrapper.h @@ -0,0 +1,39 @@ +/* + * 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/cyad/ErrorApiWrapper.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief Wrapper around cynara-error API + */ + +#ifndef SRC_CYAD_ERRORAPIWRAPPER_H_ +#define SRC_CYAD_ERRORAPIWRAPPER_H_ + +#include "BaseErrorApiWrapper.h" + +namespace Cynara { + +class ErrorApiWrapper : public BaseErrorApiWrapper { +public: + ErrorApiWrapper(); + virtual ~ErrorApiWrapper(); + virtual int cynara_strerror(int errnum, char *buf, size_t buflen); +}; + +} /* namespace Cynara */ + +#endif /* SRC_CYAD_ERRORAPIWRAPPER_H_ */ diff --git a/test/cyad/FakeErrorApiWrapper.h b/test/cyad/FakeErrorApiWrapper.h new file mode 100644 index 0000000..f1cc51a --- /dev/null +++ b/test/cyad/FakeErrorApiWrapper.h @@ -0,0 +1,39 @@ +/* + * 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 test/cyad/FakeErrorApiWrapper.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief Wrapper around cynara-error API (mock) + */ + +#ifndef TEST_CYAD_FAKEERRORAPIWRAPPER_H_ +#define TEST_CYAD_FAKEERRORAPIWRAPPER_H_ + +#include +#include + +#include + +class FakeErrorApiWrapper : public Cynara::BaseErrorApiWrapper { +public: + using BaseErrorApiWrapper::BaseErrorApiWrapper; + + MOCK_METHOD3(cynara_strerror, + int((int errnum, char *buf, size_t buflen))); +}; + +#endif /* TEST_CYAD_FAKEERRORAPIWRAPPER_H_ */ diff --git a/test/cyad/commands_dispatcher.cpp b/test/cyad/commands_dispatcher.cpp index 471997e..35a0ab8 100644 --- a/test/cyad/commands_dispatcher.cpp +++ b/test/cyad/commands_dispatcher.cpp @@ -20,6 +20,7 @@ * @brief Tests for CommandsDispatcher */ +#include #include #include #include @@ -39,6 +40,7 @@ #include "CyadCommandlineDispatcherTest.h" #include "FakeAdminApiWrapper.h" +#include "FakeErrorApiWrapper.h" #include "helpers.h" /** @@ -52,11 +54,12 @@ TEST_F(CyadCommandlineDispatcherTest, noApi) { using ::testing::Return; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::CyadCommand result; Cynara::HelpCyadCommand helpResult; @@ -74,11 +77,12 @@ TEST_F(CyadCommandlineDispatcherTest, deleteBucket) { using ::testing::IsNull; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::DeleteBucketCyadCommand result("test-bucket"); EXPECT_CALL(adminApi, @@ -98,11 +102,12 @@ TEST_F(CyadCommandlineDispatcherTest, setBucket) { using Cynara::PolicyResult; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); typedef std::tuple BucketData; typedef std::vector Buckets; @@ -141,11 +146,12 @@ TEST_F(CyadCommandlineDispatcherTest, setPolicy) { using ::testing::Return; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::SetPolicyCyadCommand result("test-bucket", { CYNARA_ADMIN_ALLOW, "" }, { "client", "user", "privilege" }); @@ -165,11 +171,12 @@ TEST_F(CyadCommandlineDispatcherTest, setPolicyWithMetadata) { using ::testing::Return; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::SetPolicyCyadCommand result("test-bucket", { CYNARA_ADMIN_ALLOW, "metadata" }, Cynara::PolicyKey("client", "user", "privilege")); @@ -189,11 +196,12 @@ TEST_F(CyadCommandlineDispatcherTest, setPoliciesBulk) { using ::testing::Return; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::SetPolicyBulkCyadCommand result("-"); // fake stdin ;) @@ -216,11 +224,12 @@ TEST_F(CyadCommandlineDispatcherTest, setPoliciesBulkInputError) { using ::testing::Return; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::SetPolicyBulkCyadCommand result("-"); // fake stdin ;) @@ -237,11 +246,12 @@ TEST_F(CyadCommandlineDispatcherTest, erase) { using ::testing::StrEq; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::EraseCyadCommand command("", true, { "client", "user", "privilege" }); @@ -261,11 +271,12 @@ TEST_F(CyadCommandlineDispatcherTest, check) { using ::testing::StrEq; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::CheckCyadCommand command("", true, { "client", "user", "privilege" }); int result = 42; @@ -289,11 +300,12 @@ TEST_F(CyadCommandlineDispatcherTest, checkWithMetadata) { using ::testing::StrEq; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::CheckCyadCommand command("", true, { "client", "user", "privilege" }); int result = 42; @@ -311,26 +323,38 @@ TEST_F(CyadCommandlineDispatcherTest, checkWithMetadata) { TEST_F(CyadCommandlineDispatcherTest, checkWithError) { using ::testing::_; + using ::testing::HasSubstr; + using ::testing::Invoke; using ::testing::NotNull; using ::testing::Return; using ::testing::StrEq; + using ::testing::Unused; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::CheckCyadCommand command("", true, { "client", "user", "privilege" }); + auto setErrorMessage = [] (Unused, char *buf, std::size_t buflen) { + strncpy(buf, "Test error message", buflen); + }; + EXPECT_CALL(adminApi, cynara_admin_check(_, StrEq(""), true, StrEq("client"), StrEq("user"), StrEq("privilege"), NotNull(), NotNull())) .WillOnce(Return(CYNARA_API_UNKNOWN_ERROR)); + // Should we expect some minimal buflen here? + EXPECT_CALL(errorApi, cynara_strerror(CYNARA_API_UNKNOWN_ERROR, NotNull(), _)) + .WillOnce(DoAll(Invoke(setErrorMessage), Return(CYNARA_API_SUCCESS))); + dispatcher.execute(command); - ASSERT_TRUE(m_io.coutRaw().str().empty()); + ASSERT_THAT(m_io.cerrRaw().str(), HasSubstr("Test error message")); } TEST_F(CyadCommandlineDispatcherTest, listPoliciesNone) { @@ -342,11 +366,12 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesNone) { using ::testing::StrEq; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::ListPoliciesCyadCommand command("", { "client", "user", "privilege" }); @@ -372,11 +397,12 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesTwo) { using ::testing::StrEq; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::ListPoliciesCyadCommand command("", { "client", "user", "privilege" }); @@ -404,11 +430,12 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesDescNone) { using ::testing::SetArgPointee; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::ListPoliciesDescCyadCommand command; @@ -432,11 +459,12 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesDescOne) { using ::testing::SetArgPointee; FakeAdminApiWrapper adminApi; + FakeErrorApiWrapper errorApi; EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi); + Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); Cynara::ListPoliciesDescCyadCommand command; -- 2.7.4 From 72e9332b407370471f0688e436e5d524a1e1b69b Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Mon, 9 Feb 2015 13:30:26 +0100 Subject: [PATCH 08/16] Support human-readable policy type names Policy type is no longer parsed in CyadCommandlineParser, but rather forwarded to CommandsDispatcher in raw form. Apparent small feature, but required changes across many layers. Refactoring of CyadCommandlineDispatcherTest was needed in order to apply fixes to tests. Change-Id: I9528554afdb5c0747c3f9ef550bf3362cd8c8084 --- src/cyad/AdminPolicyParser.cpp | 32 ++- src/cyad/AdminPolicyParser.h | 5 +- src/cyad/CMakeLists.txt | 1 + src/cyad/CommandlineParser/CyadCommand.h | 14 +- .../CommandlineParser/CyadCommandlineParser.cpp | 24 +-- src/cyad/CommandlineParser/RawPolicyResult.h | 49 +++++ src/cyad/CommandsDispatcher.cpp | 95 ++++++--- src/cyad/CommandsDispatcher.h | 3 + src/cyad/PolicyTypeTranslator.cpp | 72 +++++++ src/cyad/PolicyTypeTranslator.h | 57 ++++++ test/CMakeLists.txt | 1 + test/cyad/CyadCommandlineDispatcherTest.h | 98 ++++++++- test/cyad/commandline.cpp | 12 +- test/cyad/commandline_errors.cpp | 6 - test/cyad/commands_dispatcher.cpp | 226 +++++---------------- test/cyad/policy_parser.cpp | 17 +- 16 files changed, 459 insertions(+), 253 deletions(-) create mode 100644 src/cyad/CommandlineParser/RawPolicyResult.h create mode 100644 src/cyad/PolicyTypeTranslator.cpp create mode 100644 src/cyad/PolicyTypeTranslator.h diff --git a/src/cyad/AdminPolicyParser.cpp b/src/cyad/AdminPolicyParser.cpp index 517dc04..530ca90 100644 --- a/src/cyad/AdminPolicyParser.cpp +++ b/src/cyad/AdminPolicyParser.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. @@ -30,9 +30,31 @@ namespace Cynara { namespace AdminPolicyParser { -CynaraAdminPolicies parse(const std::shared_ptr &input) { +CynaraAdminPolicies parse(const std::shared_ptr &input, + std::function translatePolicy) { CynaraAdminPolicies policies; + auto nextToken = [] (const std::string &line, std::size_t &beginToken) -> std::string { + auto endToken = line.find(StorageSerializer::fieldSeparator(), beginToken); + if (endToken != std::string::npos) { + auto token = line.substr(beginToken, endToken - beginToken); + beginToken = endToken + 1; + return token; + } + + throw BucketRecordCorruptedException(line); + }; + + auto lastToken = [] (const std::string &line, std::size_t &beginToken) -> std::string { + if (beginToken < line.size()) { + auto ret = line.substr(beginToken); + beginToken = line.size(); + return ret; + } + + return std::string(); + }; + for (std::size_t lineNum = 1; !input->eof(); ++lineNum) { std::string line; std::getline(*input, line, StorageSerializer::recordSeparator()); @@ -42,10 +64,10 @@ CynaraAdminPolicies parse(const std::shared_ptr &input) { try { std::size_t beginToken = 0; - auto bucketId = StorageDeserializer::parseBucketId(line, beginToken); + auto bucketId = nextToken(line, beginToken); auto policyKey = BucketDeserializer::parseKey(line, beginToken); - auto policyType = StorageDeserializer::parsePolicyType(line, beginToken); - auto metadata = StorageDeserializer::parseMetadata(line, beginToken); + auto policyType = translatePolicy(nextToken(line, beginToken)); + auto metadata = lastToken(line, beginToken); policies.add(bucketId, PolicyResult(policyType, metadata), policyKey); } catch (const BucketRecordCorruptedException &ex) { diff --git a/src/cyad/AdminPolicyParser.h b/src/cyad/AdminPolicyParser.h index f448408..0fb1b93 100644 --- a/src/cyad/AdminPolicyParser.h +++ b/src/cyad/AdminPolicyParser.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. @@ -32,7 +32,8 @@ namespace Cynara { namespace AdminPolicyParser { -CynaraAdminPolicies parse(const std::shared_ptr &input); +CynaraAdminPolicies parse(const std::shared_ptr &input, + std::function); } /* namespace AdminPolicyParser */ diff --git a/src/cyad/CMakeLists.txt b/src/cyad/CMakeLists.txt index 1873046..3cb32bf 100644 --- a/src/cyad/CMakeLists.txt +++ b/src/cyad/CMakeLists.txt @@ -31,6 +31,7 @@ SET(CYAD_SOURCES ${CYAD_PATH}/CommandsDispatcher.cpp ${CYAD_PATH}/DispatcherIO.cpp ${CYAD_PATH}/ErrorApiWrapper.cpp + ${CYAD_PATH}/PolicyTypeTranslator.cpp ${CYAD_PATH}/main.cpp ) diff --git a/src/cyad/CommandlineParser/CyadCommand.h b/src/cyad/CommandlineParser/CyadCommand.h index 2133e2b..d77c378 100644 --- a/src/cyad/CommandlineParser/CyadCommand.h +++ b/src/cyad/CommandlineParser/CyadCommand.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace Cynara { @@ -73,7 +73,7 @@ public: class SetBucketCyadCommand : public CyadCommand { public: - SetBucketCyadCommand(const PolicyBucketId &bucketId, const PolicyResult &policyResult) + SetBucketCyadCommand(const PolicyBucketId &bucketId, const RawPolicyResult &policyResult) : m_bucketId(bucketId), m_policyResult(policyResult) {} virtual ~SetBucketCyadCommand() {} @@ -84,13 +84,13 @@ public: return m_bucketId; } - const PolicyResult &policyResult(void) const { + const RawPolicyResult &policyResult(void) const { return m_policyResult; } private: PolicyBucketId m_bucketId; - PolicyResult m_policyResult; + RawPolicyResult m_policyResult; }; class DeleteBucketCyadCommand : public CyadCommand { @@ -111,7 +111,7 @@ private: class SetPolicyCyadCommand : public CyadCommand { public: - SetPolicyCyadCommand(const PolicyBucketId &bucketId, const PolicyResult &policyResult, + SetPolicyCyadCommand(const PolicyBucketId &bucketId, const RawPolicyResult &policyResult, const PolicyKey &policyKey) : m_bucketId(bucketId), m_policyResult(policyResult), m_policyKey(policyKey) {} @@ -123,7 +123,7 @@ public: return m_bucketId; } - const PolicyResult &policyResult(void) const { + const RawPolicyResult &policyResult(void) const { return m_policyResult; } @@ -133,7 +133,7 @@ public: private: PolicyBucketId m_bucketId; - PolicyResult m_policyResult; + RawPolicyResult m_policyResult; PolicyKey m_policyKey; }; diff --git a/src/cyad/CommandlineParser/CyadCommandlineParser.cpp b/src/cyad/CommandlineParser/CyadCommandlineParser.cpp index a775be1..fc7f2eb 100644 --- a/src/cyad/CommandlineParser/CyadCommandlineParser.cpp +++ b/src/cyad/CommandlineParser/CyadCommandlineParser.cpp @@ -149,12 +149,7 @@ std::shared_ptr CyadCommandlineParser::parseSetBucket(const std::st if (policy.empty()) return sharedError(Err::noType()); - try { - auto policyType = HumanReadableParser::policyType(policy); - return std::make_shared(bucketId, PolicyResult(policyType, metadata)); - } catch (const PolicyParsingException &) { - return sharedError(Err::invalidType()); - } + return std::make_shared(bucketId, RawPolicyResult(policy, metadata)); } std::shared_ptr CyadCommandlineParser::parseDeleteBucket(const std::string &bucketId) { @@ -232,18 +227,11 @@ std::shared_ptr CyadCommandlineParser::parseSetPolicy(void) { } } - try { - auto policyType = HumanReadableParser::policyType(values[CmdlineOpt::Type]); - auto policyResult = PolicyResult(policyType, metadata); - return std::make_shared(bucket, policyResult, - PolicyKey(values[CmdlineOpt::Client], - values[CmdlineOpt::User], - values[CmdlineOpt::Privilege])); - } catch (const PolicyParsingException &) { - return sharedError(Err::invalidType()); - } - - return sharedError(Err::unknownError()); + auto policyResult = RawPolicyResult(values[CmdlineOpt::Type], metadata); + return std::make_shared(bucket, policyResult, + PolicyKey(values[CmdlineOpt::Client], + values[CmdlineOpt::User], + values[CmdlineOpt::Privilege])); } std::shared_ptr CyadCommandlineParser::parseErase(const std::string &bucketId) { diff --git a/src/cyad/CommandlineParser/RawPolicyResult.h b/src/cyad/CommandlineParser/RawPolicyResult.h new file mode 100644 index 0000000..08b84ad --- /dev/null +++ b/src/cyad/CommandlineParser/RawPolicyResult.h @@ -0,0 +1,49 @@ +/* + * 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/cyad/CommandlineParser/RawPolicyResult.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief An abstraction of raw PolicyType + */ + +#ifndef SRC_CYAD_COMMANDLINEPARSER_RAWPOLICYRESULT_H_ +#define SRC_CYAD_COMMANDLINEPARSER_RAWPOLICYRESULT_H_ + +namespace Cynara { + +class RawPolicyResult { +public: + RawPolicyResult(const std::string &type, const std::string &metadata) + : m_type(type), m_metadata(metadata) {} + ~RawPolicyResult() {} + + const std::string &policyType(void) const { + return m_type; + } + const std::string &metadata(void) const { + return m_metadata; + } + +private: + std::string m_type; + std::string m_metadata; + +}; + +} /* namespace Cynara */ + +#endif /* SRC_CYAD_COMMANDLINEPARSER_RAWPOLICYRESULT_H_ */ diff --git a/src/cyad/CommandsDispatcher.cpp b/src/cyad/CommandsDispatcher.cpp index 6862a42..ef36654 100644 --- a/src/cyad/CommandsDispatcher.cpp +++ b/src/cyad/CommandsDispatcher.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "CommandsDispatcher.h" @@ -45,6 +46,14 @@ CommandsDispatcher::CommandsDispatcher(BaseDispatcherIO &io, BaseAdminApiWrapper printAdminApiError(ret); throw AdminLibraryInitializationFailedException(ret); } + + try { + initPolicyTranslator(); + } catch (int ret) { + printAdminApiError(ret); + // It's not really initialization error, but still nothing depends on user input + throw AdminLibraryInitializationFailedException(ret); + } } CommandsDispatcher::~CommandsDispatcher() { @@ -85,21 +94,35 @@ int CommandsDispatcher::execute(SetBucketCyadCommand &result) { const auto &policyResult = result.policyResult(); const char *metadata = policyResult.metadata().empty() ? nullptr : policyResult.metadata().c_str(); - auto ret = m_adminApiWrapper.cynara_admin_set_bucket(m_cynaraAdmin, - result.bucketId().c_str(), - policyResult.policyType(), metadata); - if (ret != CYNARA_API_SUCCESS) - printAdminApiError(ret); + try { + int policyType = m_policyTranslator.translate(result.policyResult().policyType()); + auto ret = m_adminApiWrapper.cynara_admin_set_bucket(m_cynaraAdmin, + result.bucketId().c_str(), + policyType, metadata); - return ret; + if (ret != CYNARA_API_SUCCESS) + printAdminApiError(ret); + + return ret; + } catch (const PolicyParsingException &) { + m_io.cerr() << "Invalid policy" << std::endl; + return CYNARA_API_INVALID_COMMANDLINE_PARAM; + } } int CommandsDispatcher::execute(SetPolicyCyadCommand &result) { CynaraAdminPolicies policies; - policies.add(result.bucketId(), result.policyResult(), result.policyKey()); - policies.seal(); + try { + int policyType = m_policyTranslator.translate(result.policyResult().policyType()); + policies.add(result.bucketId(), PolicyResult(policyType, result.policyResult().metadata()), + result.policyKey()); + policies.seal(); + } catch (const PolicyParsingException &) { + m_io.cerr() << "Invalid policy" << std::endl; + return CYNARA_API_INVALID_COMMANDLINE_PARAM; + } auto ret = m_adminApiWrapper.cynara_admin_set_policies(m_cynaraAdmin, policies.data()); @@ -113,7 +136,9 @@ int CommandsDispatcher::execute(SetPolicyBulkCyadCommand &result) { auto input = m_io.openFile(result.filename()); try { - auto policies = Cynara::AdminPolicyParser::parse(input); + using Cynara::AdminPolicyParser::parse; + auto policies = parse(input, std::bind(&PolicyTypeTranslator::translate, + &m_policyTranslator, std::placeholders::_1)); auto ret = m_adminApiWrapper.cynara_admin_set_policies(m_cynaraAdmin, policies.data()); if (ret != CYNARA_API_SUCCESS) printAdminApiError(ret); @@ -121,6 +146,9 @@ int CommandsDispatcher::execute(SetPolicyBulkCyadCommand &result) { } catch (const BucketRecordCorruptedException &ex) { m_io.cerr() << ex.message(); return CYNARA_API_INVALID_COMMANDLINE_PARAM; + } catch (const PolicyParsingException &) { + m_io.cerr() << "Invalid policy" << std::endl; + return CYNARA_API_INVALID_COMMANDLINE_PARAM; } } @@ -219,33 +247,12 @@ int CommandsDispatcher::execute(ListPoliciesCyadCommand &command) { } int CommandsDispatcher::execute(ListPoliciesDescCyadCommand &) { - // Initialization is needed to make compiler happy (-Werror=maybe-uninitialized, FTW) - cynara_admin_policy_descr **descs = nullptr; - - auto ret = m_adminApiWrapper.cynara_admin_list_policies_descriptions(m_cynaraAdmin, &descs); - - auto printPolicyDesc = [this] (cynara_admin_policy_descr *pd) { - m_io.cout() << pd->result << ";" - << pd->name << std::endl; - }; - - auto freePolicyDesc = [] (cynara_admin_policy_descr *pd) { - free(pd->name); - free(pd); - }; - if (ret == CYNARA_API_SUCCESS) { - for (int i = 0; descs[i]; ++i) { - auto p = descs[i]; - printPolicyDesc(p); - freePolicyDesc(p); - } - free(descs); - } else { - printAdminApiError(ret); + for (const auto desc : m_policyTranslator.descriptions()) { + m_io.cout() << desc.first << ";" << desc.second << std::endl; } - return ret; + return CYNARA_API_SUCCESS; } void CommandsDispatcher::printAdminApiError(int errnum) { @@ -265,4 +272,26 @@ void CommandsDispatcher::printAdminApiError(int errnum) { m_io.cerr() << "Unknown error (sic! sic!)" << std::endl; } +void CommandsDispatcher::initPolicyTranslator(void) { + // Initialization is needed to make compiler happy (-Werror=maybe-uninitialized, FTW) + cynara_admin_policy_descr **descs = nullptr; + + auto ret = m_adminApiWrapper.cynara_admin_list_policies_descriptions(m_cynaraAdmin, &descs); + + auto freePolicyDesc = [] (cynara_admin_policy_descr *pd) { + free(pd->name); + free(pd); + }; + + if (ret == CYNARA_API_SUCCESS) { + m_policyTranslator.setDescriptions(descs); + for (int i = 0; descs[i] != nullptr; ++i) { + freePolicyDesc(descs[i]); + } + free(descs); + } else { + throw ret; + } +} + } /* namespace Cynara */ diff --git a/src/cyad/CommandsDispatcher.h b/src/cyad/CommandsDispatcher.h index a025303..ab4672b 100644 --- a/src/cyad/CommandsDispatcher.h +++ b/src/cyad/CommandsDispatcher.h @@ -27,6 +27,7 @@ #include #include #include +#include struct cynara_admin; struct cynara_admin_policy; @@ -53,8 +54,10 @@ public: protected: void printAdminApiError(int errnum); + void initPolicyTranslator(void); private: + PolicyTypeTranslator m_policyTranslator; BaseDispatcherIO &m_io; BaseAdminApiWrapper &m_adminApiWrapper; BaseErrorApiWrapper &m_errorApiWrapper; diff --git a/src/cyad/PolicyTypeTranslator.cpp b/src/cyad/PolicyTypeTranslator.cpp new file mode 100644 index 0000000..724cebd --- /dev/null +++ b/src/cyad/PolicyTypeTranslator.cpp @@ -0,0 +1,72 @@ +/* + * 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/cyad/PolicyTypeTranslator.cpp + * @author Aleksander Zdyb + * @version 1.0 + * @brief A helper class to translate strings to PolicyType + */ + +#include +#include + +#include + +#include + +#include "PolicyTypeTranslator.h" + +namespace Cynara { + +PolicyTypeTranslator::PolicyTypeTranslator() {} + +PolicyTypeTranslator::~PolicyTypeTranslator() {} + +void PolicyTypeTranslator::setDescriptions(cynara_admin_policy_descr **descs) { + for (int i = 0; descs[i]; ++i) { + std::string name(descs[i]->name); + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + m_descs.push_back(std::make_pair(descs[i]->result, name)); + } +} + +PolicyType PolicyTypeTranslator::translate(const std::string &rawPolicy) { + + std::string policy(rawPolicy); + std::transform(policy.begin(), policy.end(), policy.begin(), ::tolower); + + auto descComp = [policy] (const PolicyDescriptions::value_type &it) -> bool { + return it.second == policy; + }; + + const auto it = std::find_if(m_descs.begin(), m_descs.end(), descComp); + + if (it != m_descs.end()) + return it->first; + + if (policy == "none") + return CYNARA_ADMIN_NONE; + if (policy == "bucket") + return CYNARA_ADMIN_BUCKET; + + try { + return std::stoi(policy, nullptr, 0); + } catch (const std::logic_error &) { + throw PolicyParsingException(); + } +} + +} /* namespace Cynara */ diff --git a/src/cyad/PolicyTypeTranslator.h b/src/cyad/PolicyTypeTranslator.h new file mode 100644 index 0000000..1002866 --- /dev/null +++ b/src/cyad/PolicyTypeTranslator.h @@ -0,0 +1,57 @@ +/* + * 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/cyad/PolicyTypeTranslator.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief A helper class to translate strings to PolicyType + */ + +#ifndef SRC_CYAD_POLICYTYPETRANSLATOR_H_ +#define SRC_CYAD_POLICYTYPETRANSLATOR_H_ + +#include + +#include + +#include + +namespace Cynara { + +class PolicyTypeTranslator { +private: + typedef std::vector> PolicyDescriptions; + +public: + PolicyTypeTranslator(); + + ~PolicyTypeTranslator(); + + PolicyType translate(const std::string &rawPolicy); + + void setDescriptions(cynara_admin_policy_descr **descs); + + const PolicyDescriptions &descriptions(void) const { + return m_descs; + } + +private: + PolicyDescriptions m_descs; +}; + +} /* namespace Cynara */ + +#endif /* SRC_CYAD_POLICYTYPETRANSLATOR_H_ */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b7a1c2f..806ceb6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -56,6 +56,7 @@ SET(CYNARA_SOURCES_FOR_TESTS ${CYNARA_SRC}/cyad/CommandlineParser/HumanReadableParser.cpp ${CYNARA_SRC}/cyad/CommandsDispatcher.cpp ${CYNARA_SRC}/cyad/CynaraAdminPolicies.cpp + ${CYNARA_SRC}/cyad/PolicyTypeTranslator.cpp ${CYNARA_SRC}/helpers/creds-commons/CredsCommonsInner.cpp ${CYNARA_SRC}/helpers/creds-commons/creds-commons.cpp ${CYNARA_SRC}/storage/BucketDeserializer.cpp diff --git a/test/cyad/CyadCommandlineDispatcherTest.h b/test/cyad/CyadCommandlineDispatcherTest.h index 504af80..1825045 100644 --- a/test/cyad/CyadCommandlineDispatcherTest.h +++ b/test/cyad/CyadCommandlineDispatcherTest.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. @@ -23,14 +23,110 @@ #ifndef TEST_CYAD_CYADCOMMANDLINEDISPATCHERTEST_H_ #define TEST_CYAD_CYADCOMMANDLINEDISPATCHERTEST_H_ +#include +#include + #include #include +#include +#include + +#include "FakeAdminApiWrapper.h" #include "FakeDispatcherIO.h" +#include "FakeErrorApiWrapper.h" + +#define MAX_POLICY_DESCRIPTIONS 15 class CyadCommandlineDispatcherTest : public ::testing::Test { +private: + typedef cynara_admin_policy_descr DescrType; + +public: + void SetUp(void) { + auto arrSize = sizeof(DescrType *) * (MAX_POLICY_DESCRIPTIONS + 1); + m_policyDescs = static_cast(malloc(arrSize)); + + if (m_policyDescs == nullptr) + throw std::bad_alloc(); + + m_policyDescs[0] = nullptr; + setupInitFinishExpectations(); + setupDescriptionsExpectation(); + } + + void TearDown(void) { + if (m_policyDescs != nullptr) + freeDescriptions(); + } + + void addDescriptions(std::vector> toAdd) { + if (m_descCount + toAdd.size() > MAX_POLICY_DESCRIPTIONS) { + throw std::length_error("Descriptions count would exceed " + + std::to_string(MAX_POLICY_DESCRIPTIONS)); + } + + auto addDesc = [] (DescrType **desc, int result, const std::string &name) { + (*desc) = static_cast(malloc(sizeof(DescrType))); + (*desc)->result = result; + (*desc)->name = strdup(name.data()); + }; + + for (const auto &it : toAdd) { + addDesc(m_policyDescs + m_descCount, it.first, it.second); + ++m_descCount; + } + + m_policyDescs[m_descCount] = nullptr; + } + protected: + void setupInitFinishExpectations() { + using ::testing::_; + using ::testing::Return; + + EXPECT_CALL(m_adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); + EXPECT_CALL(m_adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); + } + + void setupDescriptionsExpectation() { + using ::testing::_; + using ::testing::Return; + using ::testing::NotNull; + using ::testing::DoAll; + using ::testing::SetArgPointee; + using ::testing::Assign; + + addDescriptions({ + { 0, "DENY" }, + { 0xFFFF, "ALLOW" }, + }); + + EXPECT_CALL(m_adminApi, cynara_admin_list_policies_descriptions(_, NotNull())) + .WillOnce(DoAll(SetArgPointee<1>(m_policyDescs), + Assign(&m_policyDescs, nullptr), + Return(CYNARA_API_SUCCESS))); + } + FakeDispatcherIO m_io; + FakeAdminApiWrapper m_adminApi; + FakeErrorApiWrapper m_errorApi; + +private: + void freeDescriptions() { + auto freePolicyDesc = [] (DescrType *pd) { + free(pd->name); + free(pd); + }; + + for (int i = 0; m_policyDescs[i] != nullptr; ++i) { + freePolicyDesc(m_policyDescs[i]); + } + free(m_policyDescs); + } + + DescrType **m_policyDescs = nullptr; + std::size_t m_descCount = 0; }; #endif /* TEST_CYAD_CYADCOMMANDLINEDISPATCHERTEST_H_ */ diff --git a/test/cyad/commandline.cpp b/test/cyad/commandline.cpp index b935685..ac5e28e 100644 --- a/test/cyad/commandline.cpp +++ b/test/cyad/commandline.cpp @@ -58,7 +58,7 @@ TEST_F(CyadCommandlineTest, setBucket) { auto result = std::dynamic_pointer_cast(parser.parseMain()); ASSERT_NE(nullptr, result); ASSERT_EQ("bucket", result->bucketId()); - ASSERT_EQ(42, result->policyResult().policyType()); + ASSERT_EQ("42", result->policyResult().policyType()); ASSERT_TRUE(result->policyResult().metadata().empty()); } @@ -72,7 +72,7 @@ TEST_F(CyadCommandlineTest, setBucketWithMetadata) { 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("42", result->policyResult().policyType()); ASSERT_EQ(ultimateAnswer, result->policyResult().metadata()); } @@ -87,7 +87,7 @@ TEST_F(CyadCommandlineTest, setPolicy) { ASSERT_EQ("some-bucket", result->bucketId()); ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); - ASSERT_EQ(42, result->policyResult().policyType()); + ASSERT_EQ("42", result->policyResult().policyType()); ASSERT_TRUE(result->policyResult().metadata().empty()); } @@ -102,7 +102,7 @@ TEST_F(CyadCommandlineTest, setPolicyWithMetadata) { ASSERT_EQ("some-bucket", result->bucketId()); ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); - ASSERT_EQ(42, result->policyResult().policyType()); + ASSERT_EQ("42", result->policyResult().policyType()); ASSERT_EQ("some-metadata", result->policyResult().metadata()); } @@ -116,7 +116,7 @@ TEST_F(CyadCommandlineTest, setPolicyInDefaultBucket) { ASSERT_NE(nullptr, result); ASSERT_EQ("", result->bucketId()); ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); - ASSERT_EQ(CYNARA_ADMIN_ALLOW, result->policyResult().policyType()); + ASSERT_EQ("ALLOW", result->policyResult().policyType()); ASSERT_EQ("some-metadata", result->policyResult().metadata()); } @@ -130,7 +130,7 @@ TEST_F(CyadCommandlineTest, setPolicyInDefaultBucketNoOption) { ASSERT_NE(nullptr, result); ASSERT_EQ("", result->bucketId()); ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); - ASSERT_EQ(CYNARA_ADMIN_ALLOW, result->policyResult().policyType()); + ASSERT_EQ("ALLOW", result->policyResult().policyType()); ASSERT_EQ("some-metadata", result->policyResult().metadata()); } diff --git a/test/cyad/commandline_errors.cpp b/test/cyad/commandline_errors.cpp index 7c56ab5..abe535f 100644 --- a/test/cyad/commandline_errors.cpp +++ b/test/cyad/commandline_errors.cpp @@ -78,12 +78,6 @@ TEST_F(CyadCommandlineTest, setBucketNoPolicy) { ASSERT_ERROR_MSG(Cynara::CmdlineErrors::noType(), parser.parseMain()); } -TEST_F(CyadCommandlineTest, setBucketInvalidPolicy) { - prepare_argv({ "./cyad", "--set-bucket=bucket", "--type=NaN" }); - Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); - ASSERT_ERROR_MSG(Errors::invalidType(), parser.parseMain()); -} - TEST_F(CyadCommandlineTest, setBucketUnknownOption) { prepare_argv({ "./cyad", "--set-bucket=bucket", "--unknown", "--type=42" }); Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); diff --git a/test/cyad/commands_dispatcher.cpp b/test/cyad/commands_dispatcher.cpp index 35a0ab8..a117e68 100644 --- a/test/cyad/commands_dispatcher.cpp +++ b/test/cyad/commands_dispatcher.cpp @@ -34,13 +34,12 @@ #include #include +#include #include #include #include #include "CyadCommandlineDispatcherTest.h" -#include "FakeAdminApiWrapper.h" -#include "FakeErrorApiWrapper.h" #include "helpers.h" /** @@ -53,13 +52,7 @@ TEST_F(CyadCommandlineDispatcherTest, noApi) { using ::testing::_; using ::testing::Return; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::CyadCommand result; Cynara::HelpCyadCommand helpResult; @@ -76,16 +69,10 @@ TEST_F(CyadCommandlineDispatcherTest, deleteBucket) { using ::testing::StrEq; using ::testing::IsNull; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::DeleteBucketCyadCommand result("test-bucket"); - EXPECT_CALL(adminApi, + EXPECT_CALL(m_adminApi, cynara_admin_set_bucket(_, StrEq("test-bucket"), CYNARA_ADMIN_DELETE, IsNull())) .WillOnce(Return(CYNARA_API_SUCCESS)); @@ -97,43 +84,44 @@ TEST_F(CyadCommandlineDispatcherTest, setBucket) { using ::testing::Return; using ::testing::StrEq; using ::testing::IsNull; + using ::testing::NotNull; using Cynara::PolicyBucketId; using Cynara::PolicyType; using Cynara::PolicyResult; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); + addDescriptions({ { 42, "hitchhiker" } }); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); - typedef std::tuple BucketData; + typedef std::string RawPolicyType; + typedef std::string Metadata; + typedef std::tuple BucketData; typedef std::vector Buckets; - const Buckets buckets = { BucketData("test-bucket-1", { CYNARA_ADMIN_ALLOW, "" }), - BucketData("test-bucket-2", { CYNARA_ADMIN_DENY, "" }), - BucketData("test-bucket-3", { CYNARA_ADMIN_BUCKET, "other-bucket" }), - BucketData("test-bucket-2", { CYNARA_ADMIN_NONE, "" }), - BucketData("test-bucket-4", { 42, "douglas-noel-adams" }) }; + const Buckets buckets = { + BucketData("test-bucket-1", CYNARA_ADMIN_ALLOW, "ALLOW", ""), + BucketData("test-bucket-2", CYNARA_ADMIN_DENY, "DENY", ""), + BucketData("test-bucket-3", CYNARA_ADMIN_BUCKET, "BUCKET", "other-bucket"), + BucketData("test-bucket-2", CYNARA_ADMIN_NONE, "NONE", ""), + BucketData("test-bucket-4", 42, "hitchhiker", "douglas-noel-adams") }; for (const auto &bucket : buckets) { const auto &bucketId = std::get<0>(bucket); - const auto &policyResult = std::get<1>(bucket); + const auto &policyType = std::get<1>(bucket); + const auto &rawPolicyType = std::get<2>(bucket); + const auto &metadata = std::get<3>(bucket); SCOPED_TRACE(bucketId); - Cynara::SetBucketCyadCommand result(bucketId, policyResult); + Cynara::SetBucketCyadCommand result(bucketId, { rawPolicyType, metadata }); - if (policyResult.metadata().empty() == false) { - EXPECT_CALL(adminApi, - cynara_admin_set_bucket(_, StrEq(bucketId.c_str()), policyResult.policyType(), - StrEq(policyResult.metadata().c_str()))) + if (metadata.empty() == false) { + EXPECT_CALL(m_adminApi, + cynara_admin_set_bucket(_, StrEq(bucketId.c_str()), policyType, + StrEq(metadata.c_str()))) .WillOnce(Return(CYNARA_API_SUCCESS)); } else { - EXPECT_CALL(adminApi, - cynara_admin_set_bucket(_, StrEq(bucketId.c_str()), policyResult.policyType(), - IsNull())) + EXPECT_CALL(m_adminApi, + cynara_admin_set_bucket(_, StrEq(bucketId.c_str()), policyType, IsNull())) .WillOnce(Return(CYNARA_API_SUCCESS)); } @@ -145,14 +133,8 @@ TEST_F(CyadCommandlineDispatcherTest, setPolicy) { using ::testing::_; using ::testing::Return; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); - Cynara::SetPolicyCyadCommand result("test-bucket", { CYNARA_ADMIN_ALLOW, "" }, + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); + Cynara::SetPolicyCyadCommand result("test-bucket", { "allow", "" }, { "client", "user", "privilege" }); Cynara::CynaraAdminPolicies expectedPolicies; @@ -160,7 +142,7 @@ TEST_F(CyadCommandlineDispatcherTest, setPolicy) { { "client", "user", "privilege"} ); expectedPolicies.seal(); - EXPECT_CALL(adminApi, cynara_admin_set_policies(_, AdmPolicyListEq(expectedPolicies.data()))) + EXPECT_CALL(m_adminApi, cynara_admin_set_policies(_, AdmPolicyListEq(expectedPolicies.data()))) .WillOnce(Return(CYNARA_API_SUCCESS)); dispatcher.execute(result); @@ -170,14 +152,8 @@ TEST_F(CyadCommandlineDispatcherTest, setPolicyWithMetadata) { using ::testing::_; using ::testing::Return; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); - Cynara::SetPolicyCyadCommand result("test-bucket", { CYNARA_ADMIN_ALLOW, "metadata" }, + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); + Cynara::SetPolicyCyadCommand result("test-bucket", { "allow", "metadata" }, Cynara::PolicyKey("client", "user", "privilege")); Cynara::CynaraAdminPolicies expectedPolicies; @@ -185,7 +161,7 @@ TEST_F(CyadCommandlineDispatcherTest, setPolicyWithMetadata) { { "client", "user", "privilege"} ); expectedPolicies.seal(); - EXPECT_CALL(adminApi, cynara_admin_set_policies(_, AdmPolicyListEq(expectedPolicies.data()))) + EXPECT_CALL(m_adminApi, cynara_admin_set_policies(_, AdmPolicyListEq(expectedPolicies.data()))) .WillOnce(Return(CYNARA_API_SUCCESS)); dispatcher.execute(result); @@ -195,25 +171,21 @@ TEST_F(CyadCommandlineDispatcherTest, setPoliciesBulk) { using ::testing::_; using ::testing::Return; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::SetPolicyBulkCyadCommand result("-"); // fake stdin ;) m_io.file() << "bucket;cli;usr;privilege;0;metadata" << std::endl; - m_io.file() << "bucket-2;cli;usr;privilege;0xFFFF"; + m_io.file() << "bucket-2;cli;usr;privilege;0xFFFF;" << std::endl; + m_io.file() << "bucket-3;cli;usr;priv;bucket;bucket-2"; Cynara::CynaraAdminPolicies expectedPolicies; expectedPolicies.add("bucket", { CYNARA_ADMIN_DENY, "metadata" }, {"cli", "usr", "privilege"} ); expectedPolicies.add("bucket-2", { CYNARA_ADMIN_ALLOW, "" }, {"cli", "usr", "privilege"} ); + expectedPolicies.add("bucket-3", { CYNARA_ADMIN_BUCKET, "bucket-2" }, {"cli", "usr", "priv"} ); expectedPolicies.seal(); - EXPECT_CALL(adminApi, cynara_admin_set_policies(_, AdmPolicyListEq(expectedPolicies.data()))) + EXPECT_CALL(m_adminApi, cynara_admin_set_policies(_, AdmPolicyListEq(expectedPolicies.data()))) .WillOnce(Return(CYNARA_API_SUCCESS)); dispatcher.execute(result); @@ -223,13 +195,7 @@ TEST_F(CyadCommandlineDispatcherTest, setPoliciesBulkInputError) { using ::testing::_; using ::testing::Return; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::SetPolicyBulkCyadCommand result("-"); // fake stdin ;) @@ -245,17 +211,11 @@ TEST_F(CyadCommandlineDispatcherTest, erase) { using ::testing::Return; using ::testing::StrEq; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::EraseCyadCommand command("", true, { "client", "user", "privilege" }); - EXPECT_CALL(adminApi, cynara_admin_erase(_, StrEq(""), true, StrEq("client"), StrEq("user"), + EXPECT_CALL(m_adminApi, cynara_admin_erase(_, StrEq(""), true, StrEq("client"), StrEq("user"), StrEq("privilege"))) .WillOnce(Return(CYNARA_API_SUCCESS)); @@ -270,18 +230,12 @@ TEST_F(CyadCommandlineDispatcherTest, check) { using ::testing::SetArgPointee; using ::testing::StrEq; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::CheckCyadCommand command("", true, { "client", "user", "privilege" }); int result = 42; - EXPECT_CALL(adminApi, cynara_admin_check(_, StrEq(""), true, StrEq("client"), StrEq("user"), + EXPECT_CALL(m_adminApi, cynara_admin_check(_, StrEq(""), true, StrEq("client"), StrEq("user"), StrEq("privilege"), NotNull(), NotNull())) .WillOnce(DoAll(SetArgPointee<6>(result), SetArgPointee<7>(nullptr), Return(CYNARA_API_SUCCESS))); @@ -299,19 +253,13 @@ TEST_F(CyadCommandlineDispatcherTest, checkWithMetadata) { using ::testing::SetArgPointee; using ::testing::StrEq; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::CheckCyadCommand command("", true, { "client", "user", "privilege" }); int result = 42; char *resultExtra = strdup("adams"); - EXPECT_CALL(adminApi, cynara_admin_check(_, StrEq(""), true, StrEq("client"), StrEq("user"), + EXPECT_CALL(m_adminApi, cynara_admin_check(_, StrEq(""), true, StrEq("client"), StrEq("user"), StrEq("privilege"), NotNull(), NotNull())) .WillOnce(DoAll(SetArgPointee<6>(result), SetArgPointee<7>(resultExtra), Return(CYNARA_API_SUCCESS))); @@ -330,13 +278,7 @@ TEST_F(CyadCommandlineDispatcherTest, checkWithError) { using ::testing::StrEq; using ::testing::Unused; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::CheckCyadCommand command("", true, { "client", "user", "privilege" }); @@ -344,12 +286,12 @@ TEST_F(CyadCommandlineDispatcherTest, checkWithError) { strncpy(buf, "Test error message", buflen); }; - EXPECT_CALL(adminApi, cynara_admin_check(_, StrEq(""), true, StrEq("client"), StrEq("user"), + EXPECT_CALL(m_adminApi, cynara_admin_check(_, StrEq(""), true, StrEq("client"), StrEq("user"), StrEq("privilege"), NotNull(), NotNull())) .WillOnce(Return(CYNARA_API_UNKNOWN_ERROR)); // Should we expect some minimal buflen here? - EXPECT_CALL(errorApi, cynara_strerror(CYNARA_API_UNKNOWN_ERROR, NotNull(), _)) + EXPECT_CALL(m_errorApi, cynara_strerror(CYNARA_API_UNKNOWN_ERROR, NotNull(), _)) .WillOnce(DoAll(Invoke(setErrorMessage), Return(CYNARA_API_SUCCESS))); dispatcher.execute(command); @@ -365,13 +307,7 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesNone) { using ::testing::SetArgPointee; using ::testing::StrEq; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::ListPoliciesCyadCommand command("", { "client", "user", "privilege" }); @@ -379,7 +315,7 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesNone) { resultPolicies.seal(); auto policies = resultPolicies.duplicate(); - EXPECT_CALL(adminApi, cynara_admin_list_policies(_, StrEq(""), StrEq("client"), StrEq("user"), + EXPECT_CALL(m_adminApi, cynara_admin_list_policies(_, StrEq(""), StrEq("client"), StrEq("user"), StrEq("privilege"), NotNull())) .WillOnce(DoAll(SetArgPointee<5>(policies), Return(CYNARA_API_SUCCESS))); @@ -396,13 +332,7 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesTwo) { using ::testing::SetArgPointee; using ::testing::StrEq; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::ListPoliciesCyadCommand command("", { "client", "user", "privilege" }); @@ -412,7 +342,7 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesTwo) { resultPolicies.seal(); auto policies = resultPolicies.duplicate(); - EXPECT_CALL(adminApi, cynara_admin_list_policies(_, StrEq(""), StrEq("client"), StrEq("user"), + EXPECT_CALL(m_adminApi, cynara_admin_list_policies(_, StrEq(""), StrEq("client"), StrEq("user"), StrEq("privilege"), NotNull())) .WillOnce(DoAll(SetArgPointee<5>(policies), Return(CYNARA_API_SUCCESS))); @@ -422,64 +352,20 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesTwo) { m_io.coutRaw().str()); } -TEST_F(CyadCommandlineDispatcherTest, listPoliciesDescNone) { +TEST_F(CyadCommandlineDispatcherTest, listPoliciesDesc) { using ::testing::_; using ::testing::DoAll; using ::testing::NotNull; using ::testing::Return; using ::testing::SetArgPointee; + using ::testing::HasSubstr; - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); - - Cynara::ListPoliciesDescCyadCommand command; - - auto descs = static_cast( - calloc(1, sizeof(cynara_admin_policy_descr *))); - descs[0] = nullptr; - - EXPECT_CALL(adminApi, cynara_admin_list_policies_descriptions(_, NotNull())) - .WillOnce(DoAll(SetArgPointee<1>(descs), Return(CYNARA_API_SUCCESS))); - - dispatcher.execute(command); - - ASSERT_EQ("", m_io.coutRaw().str()); -} - -TEST_F(CyadCommandlineDispatcherTest, listPoliciesDescOne) { - using ::testing::_; - using ::testing::DoAll; - using ::testing::NotNull; - using ::testing::Return; - using ::testing::SetArgPointee; - - FakeAdminApiWrapper adminApi; - FakeErrorApiWrapper errorApi; - - EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS)); - EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS)); + addDescriptions({ { 42, "adams" } }); - Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi); + Cynara::CommandsDispatcher dispatcher(m_io, m_adminApi, m_errorApi); Cynara::ListPoliciesDescCyadCommand command; - - auto descs = static_cast( - calloc(2, sizeof(cynara_admin_policy_descr *))); - - descs[0] = static_cast(malloc(sizeof(cynara_admin_policy_descr))); - descs[0]->result = 42; - descs[0]->name = strdup("adams"); - descs[1] = nullptr; - - EXPECT_CALL(adminApi, cynara_admin_list_policies_descriptions(_, NotNull())) - .WillOnce(DoAll(SetArgPointee<1>(descs), Return(CYNARA_API_SUCCESS))); - dispatcher.execute(command); - ASSERT_EQ("42;adams\n", m_io.coutRaw().str()); + EXPECT_THAT(m_io.coutRaw().str(), HasSubstr("42;adams\n")); } diff --git a/test/cyad/policy_parser.cpp b/test/cyad/policy_parser.cpp index ab95987..a3e2f5e 100644 --- a/test/cyad/policy_parser.cpp +++ b/test/cyad/policy_parser.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. @@ -22,22 +22,29 @@ #include #include +#include #include #include #include #include +#include #include #include "helpers.h" +static Cynara::PolicyType translatePolicy(const std::string &rawPolicy) { + return std::stoi(rawPolicy); +} + TEST(AdminPolicyParser, parseInvalid) { auto input = std::make_shared(); *input << "invalid input" << std::endl; - ASSERT_THROW(Cynara::AdminPolicyParser::parse(input), Cynara::BucketRecordCorruptedException); + ASSERT_THROW(Cynara::AdminPolicyParser::parse(input, translatePolicy), + Cynara::BucketRecordCorruptedException); } TEST(AdminPolicyParser, parse0) { @@ -46,7 +53,7 @@ TEST(AdminPolicyParser, parse0) { Cynara::CynaraAdminPolicies expectedPolicies; expectedPolicies.seal(); - auto policies = Cynara::AdminPolicyParser::parse(input); + auto policies = Cynara::AdminPolicyParser::parse(input, translatePolicy); ASSERT_TRUE(policies.sealed()); ASSERT_THAT(policies.data(), AdmPolicyListEq(expectedPolicies.data())); @@ -61,7 +68,7 @@ TEST(AdminPolicyParser, parse1) { expectedPolicies.add("b", { 0, "m" }, { "c", "u", "p" }); expectedPolicies.seal(); - auto policies = Cynara::AdminPolicyParser::parse(input); + auto policies = Cynara::AdminPolicyParser::parse(input, translatePolicy); ASSERT_TRUE(policies.sealed()); ASSERT_THAT(policies.data(), AdmPolicyListEq(expectedPolicies.data())); @@ -78,7 +85,7 @@ TEST(AdminPolicyParser, parse2) { expectedPolicies.add("b2", { 0, "m2" }, { "c2", "u2", "p2" }); expectedPolicies.seal(); - auto policies = Cynara::AdminPolicyParser::parse(input); + auto policies = Cynara::AdminPolicyParser::parse(input, translatePolicy); ASSERT_TRUE(policies.sealed()); ASSERT_THAT(policies.data(), AdmPolicyListEq(expectedPolicies.data())); -- 2.7.4 From ad9b2325f605f3ea48ec7c681ca67fa70462d51d Mon Sep 17 00:00:00 2001 From: Adam Malinowski Date: Fri, 6 Feb 2015 09:58:02 +0100 Subject: [PATCH 09/16] Introduce logging of privilege checks (AUDIT) Added functionality saves privilege checking responses in systemd journal. Such entries may be filtered using CYNARA_LOG_TYPE=AUDIT field. Logging depends on configuration based on environment variable CYNARA_AUDIT_LEVEL which may take one of following values: * NONE - nothing will be saved * DENY - only DENY responses will be saved (DEFAULT behaviour) * ALLOW - only ALLOW respones will be saved * OTHER - other policy types e.g. plugin specific * ALL - all above responses will be saved Change-Id: Iaa46f3c579660784ffe5edc0c2120b822fb0061a --- src/common/CMakeLists.txt | 1 + src/common/log/AuditLog.cpp | 87 +++++++++++++++++++++++++++++++++++++++++++++ src/common/log/AuditLog.h | 56 +++++++++++++++++++++++++++++ src/service/logic/Logic.cpp | 4 +++ src/service/logic/Logic.h | 2 ++ systemd/cynara.service | 1 + 6 files changed, 151 insertions(+) create mode 100644 src/common/log/AuditLog.cpp create mode 100644 src/common/log/AuditLog.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 07167bc..be94ff8 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -30,6 +30,7 @@ SET(COMMON_SOURCES ${COMMON_PATH}/containers/BinaryQueue.cpp ${COMMON_PATH}/error/api.cpp ${COMMON_PATH}/lock/FileLock.cpp + ${COMMON_PATH}/log/AuditLog.cpp ${COMMON_PATH}/log/log.cpp ${COMMON_PATH}/plugin/PluginManager.cpp ${COMMON_PATH}/protocol/ProtocolAdmin.cpp diff --git a/src/common/log/AuditLog.cpp b/src/common/log/AuditLog.cpp new file mode 100644 index 0000000..8ddf8f8 --- /dev/null +++ b/src/common/log/AuditLog.cpp @@ -0,0 +1,87 @@ +/* + * 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/log/AuditLog.cpp + * @author Adam Malinowski + * @version 1.0 + * @brief This file implements privilege check logging utility. + */ + +#include + +#include "AuditLog.h" + +namespace Cynara { + +AuditLog::AuditLog() : m_logLevel(AL_DENY) { + init(); +} + +void AuditLog::init(void) { + char *env_val = getenv("CYNARA_AUDIT_LEVEL"); + if (env_val) { + m_logLevel = stringToLevel(env_val); + } +} + +AuditLog::AuditLevel AuditLog::stringToLevel(const std::string &name) { + if (name == "NONE") + return AL_NONE; + + if (name == "DENY") + return AL_DENY; + + if (name == "ALLOW") + return AL_ALLOW; + + if (name == "OTHER") + return AL_OTHER; + + if (name == "ALL") + return AL_ALL; + + return AL_NONE; +} + +const char *AuditLog::policyResultToString(const PolicyResult &policyResult) { + if (policyResult.policyType() == PredefinedPolicyType::DENY) + return "DENY"; + + if (policyResult.policyType() == PredefinedPolicyType::ALLOW) + return "ALLOW"; + + return "OTHER"; +} + +void AuditLog::log(const PolicyKey &policyKey, const PolicyResult &policyResult) { + if (m_logLevel == AL_NONE) + return; + + PolicyType policyType = policyResult.policyType(); + namespace PPT = PredefinedPolicyType; + + if (m_logLevel == AL_ALL || (m_logLevel == AL_DENY && policyType == PPT::DENY) || + (m_logLevel == AL_ALLOW && policyType == PPT::ALLOW) || + (m_logLevel == AL_OTHER && policyType != PPT::ALLOW && policyType != PPT::DENY)) { + sd_journal_send("MESSAGE=%s;%s;%s => %s", policyKey.client().toString().c_str(), + policyKey.user().toString().c_str(), + policyKey.privilege().toString().c_str(), + policyResultToString(policyResult), "PRIORITY=%i", LOG_INFO, + "CYNARA_LOG_TYPE=AUDIT", NULL); + } +} + +} /* namespace Cynara */ diff --git a/src/common/log/AuditLog.h b/src/common/log/AuditLog.h new file mode 100644 index 0000000..996739d --- /dev/null +++ b/src/common/log/AuditLog.h @@ -0,0 +1,56 @@ +/* + * 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/log/AuditLog.h + * @author Adam Malinowski + * @version 1.0 + * @brief This file defines privilege check logging utility. + */ + +#ifndef SRC_COMMON_LOG_AUDITLOG_H +#define SRC_COMMON_LOG_AUDITLOG_H + +#include + +#include + +namespace Cynara { + +class AuditLog { +public: + AuditLog(); + + void log(const PolicyKey &policyKey, const PolicyResult &policyResult); + +private: + typedef enum { + AL_NONE, + AL_DENY, + AL_ALLOW, + AL_OTHER, + AL_ALL + } AuditLevel; + + int m_logLevel; + + void init(void); + static AuditLevel stringToLevel(const std::string &name); + static const char *policyResultToString(const PolicyResult &policyResult); +}; + +#endif /* SRC_COMMON_LOG_AUDITLOG_H */ + +} // namespace Cynara diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index e92808e..6a1bece 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -169,6 +169,7 @@ void Logic::execute(RequestContextPtr context, CancelRequestPtr request) { void Logic::execute(RequestContextPtr context, CheckRequestPtr request) { PolicyResult result(PredefinedPolicyType::DENY); if (check(context, request->key(), request->sequenceNumber(), result)) { + m_auditLog.log(request->key(), result); context->returnResponse(context, std::make_shared(result, request->sequenceNumber())); } @@ -272,6 +273,7 @@ bool Logic::update(const PolicyKey &key, ProtocolFrameSequenceNumber checkId, } if (answerReady && context->responseQueue()) { + m_auditLog.log(key, result); context->returnResponse(context, std::make_shared(result, checkId)); return true; } @@ -422,6 +424,7 @@ void Logic::execute(RequestContextPtr context, SimpleCheckRequestPtr request) { } } } + m_auditLog.log(request->key(), result); context->returnResponse(context, std::make_shared(retValue, result, request->sequenceNumber())); } @@ -476,6 +479,7 @@ void Logic::handleAgentTalkerDisconnection(const AgentTalkerPtr &agentTalkerPtr) if (!checkContextPtr->cancelled() && checkContextPtr->m_requestContext->responseQueue()) { PolicyResult result(PredefinedPolicyType::DENY); + m_auditLog.log(checkContextPtr->m_key, result); checkContextPtr->m_requestContext->returnResponse(checkContextPtr->m_requestContext, std::make_shared(result, checkContextPtr->m_checkId)); } diff --git a/src/service/logic/Logic.h b/src/service/logic/Logic.h index 444f734..2a4ff8a 100644 --- a/src/service/logic/Logic.h +++ b/src/service/logic/Logic.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -93,6 +94,7 @@ private: PluginManagerPtr m_pluginManager; StoragePtr m_storage; SocketManagerPtr m_socketManager; + AuditLog m_auditLog; bool check(const RequestContextPtr &context, const PolicyKey &key, ProtocolFrameSequenceNumber checkId, PolicyResult &result); diff --git a/systemd/cynara.service b/systemd/cynara.service index 99176fa..4d09d5d 100644 --- a/systemd/cynara.service +++ b/systemd/cynara.service @@ -20,6 +20,7 @@ Group=cynara NoNewPrivileges=true #Environment="CYNARA_LOG_LEVEL=LOG_DEBUG" +#Environment="CYNARA_AUDIT_LEVEL=ALL" [Install] WantedBy=multi-user.target -- 2.7.4 From b779aaba11b59b986744264dbc207322eefda91e Mon Sep 17 00:00:00 2001 From: Adam Malinowski Date: Thu, 12 Feb 2015 15:39:53 +0100 Subject: [PATCH 10/16] Fix (de)serializing sizes of strings & containers Additionally fix (de)serializing bool as its size is implementation specific and remove unused code. Change-Id: I5389b2191b827a2da5dfe0d967064b10ca9d4a73 --- src/common/protocol/ProtocolSerialization.h | 263 ++-------------------------- 1 file changed, 14 insertions(+), 249 deletions(-) diff --git a/src/common/protocol/ProtocolSerialization.h b/src/common/protocol/ProtocolSerialization.h index 06cd05d..8340cf9 100644 --- a/src/common/protocol/ProtocolSerialization.h +++ b/src/common/protocol/ProtocolSerialization.h @@ -41,383 +41,148 @@ public: virtual ~IStream() {}; }; -// Serializable interface -class ISerializable { -public: - /* ISerializable(){}; - * ISerializable(IStream&){}; */ - virtual void serialize(IStream &) const = 0; - virtual ~ISerializable() {}; -}; - struct ProtocolSerialization { - - // ISerializable objects - static void serialize(IStream &stream, const ISerializable &object) { - object.serialize(stream); - } - static void serialize(IStream &stream, const ISerializable * const object) { - object->serialize(stream); - } - // char static void serialize(IStream &stream, const char value) { stream.write(sizeof(value), &value); } - static void serialize(IStream &stream, const char * const value) { - stream.write(sizeof(*value), value); - } // unsigned char static void serialize(IStream &stream, const unsigned char value) { stream.write(sizeof(value), &value); } - static void serialize(IStream &stream, const unsigned char * const value) { - stream.write(sizeof(*value), value); - } // unsigned 16-bit int static void serialize(IStream &stream, const uint16_t value) { uint16_t _value = htole16(value); stream.write(sizeof(value), &_value); } - static void serialize(IStream &stream, const uint16_t * const value) { - uint16_t _value = htole16(*value); - stream.write(sizeof(*value), &_value); - } // 16-bit int static void serialize(IStream &stream, const int16_t value) { int16_t _value = htole16(value); stream.write(sizeof(value), &_value); } - static void serialize(IStream &stream, const int16_t * const value) { - int16_t _value = htole16(*value); - stream.write(sizeof(*value), &_value); - } // unsigned 32-bit int static void serialize(IStream &stream, const uint32_t value) { uint32_t _value = htole32(value); stream.write(sizeof(value), &_value); } - static void serialize(IStream &stream, const uint32_t * const value) { - uint32_t _value = htole32(*value); - stream.write(sizeof(*value), &_value); - } // 32-bit int static void serialize(IStream &stream, const int32_t value) { int32_t _value = htole32(value); stream.write(sizeof(value), &_value); } - static void serialize(IStream &stream, const int32_t * const value) { - int32_t _value = htole32(*value); - stream.write(sizeof(*value), &_value); - } // bool static void serialize(IStream &stream, const bool value) { - stream.write(sizeof(value), &value); - } - static void serialize(IStream &stream, const bool * const value) { - stream.write(sizeof(*value), value); - } - - // time_t - static void serialize(IStream &stream, const time_t value) { - stream.write(sizeof(value), &value); - } - static void serialize(IStream &stream, const time_t * const value) { - stream.write(sizeof(*value), value); + uint8_t bVal = static_cast(value); + stream.write(sizeof(bVal), &bVal); } // ProtocolOpCode static void serialize(IStream &stream, const ProtocolOpCode value) { stream.write(sizeof(value), &value); } - static void serialize(IStream &stream, const ProtocolOpCode * const value) { - stream.write(sizeof(*value), value); - } // std::string static void serialize(IStream &stream, const std::string &str) { - int length = str.size(); + uint32_t length = htole32(static_cast(str.size())); stream.write(sizeof(length), &length); stream.write(length, str.c_str()); } - static void serialize(IStream &stream, const std::string * const str) { - int length = str->size(); - stream.write(sizeof(length), &length); - stream.write(length, str->c_str()); - } static void serializeNoSize(IStream &stream, const std::string &str) { int length = str.size(); stream.write(length, str.c_str()); } - static void serializeNoSize(IStream &stream, const std::string * const str) { - int length = str->size(); - stream.write(length, str->c_str()); - } - - // STL templates - - // std::list - template - static void serialize(IStream &stream, const std::list &list) { - int length = list.size(); - stream.write(sizeof(length), &length); - for (typename std::list::const_iterator list_iter = list.begin(); - list_iter != list.end(); list_iter++) { - serialize(stream, *list_iter); - } - } - template - static void serialize(IStream &stream, const std::list * const list) { - serialize(stream, *list); - } // std::vector template static void serialize(IStream &stream, const std::vector &vec) { - int length = vec.size(); + uint32_t length = htole32(static_cast(vec.size())); stream.write(sizeof(length), &length); for (typename std::vector::const_iterator vec_iter = vec.begin(); vec_iter != vec.end(); vec_iter++) { serialize(stream, *vec_iter); } } - template - static void serialize(IStream &stream, const std::vector * const vec) { - serialize(stream, *vec); - } - - // std::pair - template - static void serialize(IStream &stream, const std::pair &p) { - serialize(stream, p.first); - serialize(stream, p.second); - } - template - static void serialize(IStream &stream, const std::pair * const p) { - serialize(stream, *p); - } - - // std::map - template - static void serialize(IStream &stream, const std::map &map) { - int length = map.size(); - stream.write(sizeof(length), &length); - typename std::map::const_iterator it; - for (it = map.begin(); it != map.end(); ++it) { - serialize(stream, (*it).first); - serialize(stream, (*it).second); - } - } - template - static void serialize(IStream &stream, const std::map * const map) { - serialize(stream, *map); - } - - // std::unique_ptr - template - static void serialize(IStream &stream, const std::unique_ptr &p) { - serialize(stream, *p); - } }; // struct ProtocolSerialization struct ProtocolDeserialization { - - // ISerializable objects - // T instead of ISerializable is needed to call proper constructor - template - static void deserialize(IStream &stream, T &object) { - object = T(stream); - } - template - static void deserialize(IStream &stream, T *&object) { - object = new T(stream); - } - // char static void deserialize(IStream &stream, char &value) { stream.read(sizeof(value), &value); } - static void deserialize(IStream &stream, char *&value) { - value = new char; - stream.read(sizeof(*value), value); - } // unsigned char static void deserialize(IStream &stream, unsigned char &value) { stream.read(sizeof(value), &value); } - static void deserialize(IStream &stream, unsigned char *&value) { - value = new unsigned char; - stream.read(sizeof(*value), value); - } // 16-bit int static void deserialize(IStream &stream, int16_t &value) { stream.read(sizeof(value), &value); value = le16toh(value); } - static void deserialize(IStream &stream, int16_t *&value) { - value = new int16_t; - stream.read(sizeof(*value), value); - value = le16toh(value); - } // unsigned 16-bit int static void deserialize(IStream &stream, uint16_t &value) { stream.read(sizeof(value), &value); value = le16toh(value); } - static void deserialize(IStream &stream, uint16_t *&value) { - value = new uint16_t; - stream.read(sizeof(*value), value); - value = le16toh(value); - } // 32-bit int static void deserialize(IStream &stream, int32_t &value) { stream.read(sizeof(value), &value); value = le32toh(value); } - static void deserialize(IStream &stream, int32_t *&value) { - value = new int32_t; - stream.read(sizeof(*value), value); - value = le32toh(value); - } // unsigned 32-bit int static void deserialize(IStream &stream, uint32_t &value) { stream.read(sizeof(value), &value); value = le32toh(value); } - static void deserialize(IStream &stream, uint32_t *&value) { - value = new uint32_t; - stream.read(sizeof(*value), value); - value = le32toh(value); - } // bool static void deserialize(IStream &stream, bool &value) { - stream.read(sizeof(value), &value); - } - static void deserialize(IStream &stream, bool *&value) { - value = new bool; - stream.read(sizeof(*value), value); - } - - // time_t - static void deserialize(IStream &stream, time_t &value) { - stream.read(sizeof(value), &value); - } - static void deserialize(IStream &stream, time_t *&value) { - value = new time_t; - stream.read(sizeof(*value), value); + uint8_t bVal; + stream.read(sizeof(bVal), &bVal); + value = static_cast(bVal); } // PrtocolOpCode static void deserialize(IStream &stream, ProtocolOpCode &value) { stream.read(sizeof(value), &value); } - static void deserialize(IStream &stream, ProtocolOpCode *&value) { - value = new ProtocolOpCode; - stream.read(sizeof(*value), value); - } // std::string static void deserialize(IStream &stream, std::string &str) { - int length; + uint32_t length; stream.read(sizeof(length), &length); + length = le32toh(length); str.resize(length); stream.read(length, &str[0]); } - static void deserialize(IStream &stream, std::string *&str) { - int length; - stream.read(sizeof(length), &length); - str = new std::string(length, '\0'); - stream.read(length, &str[0]); - } static void deserialize(IStream &stream, int length, std::string &str) { str.resize(length); stream.read(length, &str[0]); } - static void deserialize(IStream &stream, int length, std::string *&str) { - str = new std::string(length, '\0'); - stream.read(length, &str[0]); - } - - // STL templates - - // std::list - template - static void deserialize(IStream &stream, std::list &list) { - int length; - stream.read(sizeof(length), &length); - for (int i = 0; i < length; ++i) { - T obj; - deserialize(stream, obj); - list.push_back(std::move(obj)); - } - } - template - static void deserialize(IStream &stream, std::list *&list) { - list = new std::list; - deserialize(stream, *list); - } // std::vector template static void deserialize(IStream &stream, std::vector &vec) { - int length; + uint32_t length; stream.read(sizeof(length), &length); - for (int i = 0; i < length; ++i) { + length = le32toh(length); + for (uint32_t i = 0; i < length; ++i) { T obj; deserialize(stream, obj); vec.push_back(std::move(obj)); } } - template - static void deserialize(IStream &stream, std::vector *&vec) { - vec = new std::vector; - deserialize(stream, *vec); - } - - // std::pair - template - static void deserialize(IStream &stream, std::pair &p) { - deserialize(stream, p.first); - deserialize(stream, p.second); - } - template - static void deserialize(IStream &stream, std::pair *&p) { - p = new std::pair; - deserialize(stream, *p); - } - - // std::map - template - static void deserialize(IStream &stream, std::map &map) { - int length; - stream.read(sizeof(length), &length); - for (int i = 0; i < length; ++i) { - K key; - T obj; - deserialize(stream, key); - deserialize(stream, obj); - map[key] = std::move(obj); - } - } - template - static void deserialize(IStream &stream, std::map *&map) { - map = new std::map; - deserialize(stream, *map); - } -}; -// struct ProtocolDeserialization -}// namespace Cynara +}; // struct ProtocolDeserialization +} // namespace Cynara #endif // SRC_COMMON_PROTOCOL_PROTOCOLSERIALIZATION_H_ -- 2.7.4 From fa67864a4d6a9192814b47e3b74e59e06fa67cb1 Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Mon, 12 Jan 2015 13:01:24 +0100 Subject: [PATCH 11/16] Add performance tests for InMemoryStorageBackend Methods of InMemoryStorageBackend::hasBucket() and InMemoryStorageBackend::createBucket() are checked against possible performance issues. Change-Id: I0f65b77cab6ae88f62a495f0e34c38e391c61773 --- test/storage/performance/bucket.cpp | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/test/storage/performance/bucket.cpp b/test/storage/performance/bucket.cpp index e55da7f..c24ff3d 100644 --- a/test/storage/performance/bucket.cpp +++ b/test/storage/performance/bucket.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -37,11 +38,6 @@ using namespace Cynara; -class Benchmark { -public: - -}; - class PolicyKeyGenerator { public: typedef std::vector Features; @@ -104,3 +100,41 @@ TEST(Performance, bucket_filtered_100000) { auto value = std::to_string(result.count() / measureRepeats) + " [us]"; RecordProperty(key, value); } + +TEST(Performance, bucket_hasBucket) { + using std::chrono::microseconds; + + InMemoryStorageBackend backend("/some/fake/path"); // don't use load() or save() + + for (auto i = 0u; i < 1000; ++i) { + backend.createBucket("b" + std::to_string(i), Cynara::PredefinedPolicyType::DENY); + } + + const unsigned int measureRepeats = 5000; + auto result = Benchmark::measure([&backend, measureRepeats] () { + for (auto i = 0u; i < measureRepeats; ++i) { + backend.hasBucket("b" + std::to_string(i)); + } + }); + + auto key = std::string("performance"); + auto value = std::to_string(result.count() / measureRepeats) + " [us]"; + RecordProperty(key, value); +} + +TEST(Performance, bucket_createBucket) { + using std::chrono::microseconds; + + InMemoryStorageBackend backend("/some/fake/path"); // don't use load() or save() + + const unsigned int measureRepeats = 1000; + auto result = Benchmark::measure([&backend, measureRepeats] () { + for (auto i = 0u; i < measureRepeats; ++i) { + backend.createBucket("b" + std::to_string(i), Cynara::PredefinedPolicyType::DENY); + } + }); + + auto key = std::string("performance"); + auto value = std::to_string(result.count() / measureRepeats) + " [us]"; + RecordProperty(key, value); +} -- 2.7.4 From cf6c8394d13b0132d271deaa8a3fa1d8e519e3b6 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Mon, 16 Feb 2015 17:14:12 +0100 Subject: [PATCH 12/16] Make commandline tests fixture more generic CyadCommandlineTest fixture can be reused for tests of Cynara's commandline interface (and others, if necessary). Its functionality is now moved to BaseCommandlineTest fixture. Commons for tests will be placed in "test-common", because name "common" was already taken - it's a place for storing tests of Cynara's commons. Change-Id: I57a5c894ed03ee349a30dae922ec669003eaac5c --- test/CMakeLists.txt | 1 + test/cyad/CyadCommandlineTest.h | 59 ++----------------------- test/test-common/BaseCommandlineTest.h | 81 ++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 56 deletions(-) create mode 100644 test/test-common/BaseCommandlineTest.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 806ceb6..119e2e7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -107,6 +107,7 @@ INCLUDE_DIRECTORIES( ${CYNARA_SRC}/common ${CYNARA_SRC}/include ${CYNARA_SRC} + test-common credsCommons/parser common/protocols ) diff --git a/test/cyad/CyadCommandlineTest.h b/test/cyad/CyadCommandlineTest.h index d45fe3d..f24889d 100644 --- a/test/cyad/CyadCommandlineTest.h +++ b/test/cyad/CyadCommandlineTest.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. @@ -23,62 +23,9 @@ #ifndef TEST_CYAD_CYADCOMMANDLINETEST_H_ #define TEST_CYAD_CYADCOMMANDLINETEST_H_ -#include -#include -#include -#include -#include -#include +#include -#include -#include - -#include -#include - -class CyadCommandlineTest : public ::testing::Test { -public: - typedef std::vector Args; - - void prepare_argv(const Args &args) { - destroy_argv(); - - m_argc = args.size(); - m_argv = new char *[m_argc]; - - for (auto i = 0; i < m_argc; ++i) { - m_argv[i] = strdup(args.at(i).c_str()); - if (m_argv[i] == nullptr) - throw std::bad_alloc(); - } - } - - int argc(void) const { - return m_argc; - } - - char * const *argv(void) const { - return m_argv; - } - -protected: - virtual void TearDown(void) { - destroy_argv(); - } - - void destroy_argv(void) { - for (auto i = 0; i < m_argc; ++i) { - free(m_argv[i]); - } - delete[] m_argv; - - m_argc = 0; - m_argv = nullptr; - } - -private: - int m_argc = 0; - char **m_argv = nullptr; +class CyadCommandlineTest : public BaseCommandlineTest { }; #endif /* TEST_CYAD_CYADCOMMANDLINETEST_H_ */ diff --git a/test/test-common/BaseCommandlineTest.h b/test/test-common/BaseCommandlineTest.h new file mode 100644 index 0000000..c8e1285 --- /dev/null +++ b/test/test-common/BaseCommandlineTest.h @@ -0,0 +1,81 @@ +/* + * 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/test-common/BaseCommandlineTest.h + * @author Aleksander Zdyb + * @author Pawel Wieczorek + * @version 1.0 + * @brief Base fixture for tests of commandline parsers + */ + +#ifndef TEST_TEST_COMMON_BASECOMMANDLINETEST_H_ +#define TEST_TEST_COMMON_BASECOMMANDLINETEST_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include + +class BaseCommandlineTest : public ::testing::Test { +public: + typedef std::vector Args; + + void prepare_argv(const Args &args) { + destroy_argv(); + + m_argc = args.size(); + m_argv = new char *[m_argc]; + + for (auto i = 0; i < m_argc; ++i) { + m_argv[i] = strdup(args.at(i).c_str()); + if (m_argv[i] == nullptr) + throw std::bad_alloc(); + } + } + + int argc(void) const { + return m_argc; + } + + char * const *argv(void) const { + return m_argv; + } + +protected: + virtual void TearDown(void) { + destroy_argv(); + } + + void destroy_argv(void) { + for (auto i = 0; i < m_argc; ++i) { + free(m_argv[i]); + } + delete[] m_argv; + + m_argc = 0; + m_argv = nullptr; + } + + int m_argc = 0; + char **m_argv = nullptr; +}; + +#endif /* TEST_TEST_COMMON_BASECOMMANDLINETEST_H_ */ -- 2.7.4 From a733a2ecfb267aa5e35b2b98d4baf7aefc0fecbe Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Tue, 17 Feb 2015 16:29:15 +0100 Subject: [PATCH 13/16] Add quiet fixture for commandline tests This patch introduces fixture which suppresses printing output to std::cout or std::cerr. Data is redirected to temporary buffers and accessible from there. Change-Id: Ia1b8b240be95d1d672a56cd9eaf6e13320bb375b --- test/test-common/QuietCommandlineTest.h | 66 +++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 test/test-common/QuietCommandlineTest.h diff --git a/test/test-common/QuietCommandlineTest.h b/test/test-common/QuietCommandlineTest.h new file mode 100644 index 0000000..5cba131 --- /dev/null +++ b/test/test-common/QuietCommandlineTest.h @@ -0,0 +1,66 @@ +/* + * 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/test-common/QuietCommandlineTest.h + * @author Pawel Wieczorek + * @version 1.0 + * @brief Fixture for tests of commandline parsers with no output to std::cout nor std::cerr + */ + +#ifndef TEST_TEST_COMMON_QUIETCOMMANDLINETEST_H_ +#define TEST_TEST_COMMON_QUIETCOMMANDLINETEST_H_ + +#include +#include +#include +#include + +#include "BaseCommandlineTest.h" + +class QuietCommandlineTest : public BaseCommandlineTest { +public: + void clearOutput(void) { + m_cerr.str(std::string()); + m_cout.str(std::string()); + } + + void getOutput(std::string &out, std::string &err) const { + err = m_cerr.str(); + out = m_cout.str(); + } + +protected: + virtual void SetUp(void) { + m_cerrBackup.reset(std::cerr.rdbuf()); + std::cerr.rdbuf(m_cerr.rdbuf()); + + m_coutBackup.reset(std::cout.rdbuf()); + std::cout.rdbuf(m_cout.rdbuf()); + } + + virtual void TearDown(void) { + destroy_argv(); + std::cerr.rdbuf(m_cerrBackup.release()); + std::cout.rdbuf(m_coutBackup.release()); + } + + std::unique_ptr m_cerrBackup; + std::unique_ptr m_coutBackup; + std::stringstream m_cerr; + std::stringstream m_cout; +}; + +#endif /* TEST_TEST_COMMONS_QUIETCOMMANDLINETEST_H_ */ -- 2.7.4 From f63545c4a541e55fc14e120d830b5fa5b814cba7 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Wed, 21 Jan 2015 14:12:42 +0100 Subject: [PATCH 14/16] Add version information to the main executable In order to comply with GNU Coding Standards for command-line interfaces, Cynara has to report its current version. Cynara now responds to two command-line options: * -V, --version prints installed version of Cynara, * -h, --help prints help message. Change-Id: I386a09d00f1542cbff8db6a4b9eb2ac9a7fab9fb --- packaging/cynara.spec | 3 +- src/service/CMakeLists.txt | 1 + src/service/main/CmdlineParser.cpp | 93 ++++++++++++++++++++++++++++++++++++++ src/service/main/CmdlineParser.h | 50 ++++++++++++++++++++ src/service/main/main.cpp | 10 +++- 5 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 src/service/main/CmdlineParser.cpp create mode 100644 src/service/main/CmdlineParser.h diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 7076933..2eb9a23 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -185,7 +185,8 @@ export CXXFLAGS="$CXXFLAGS -Wp,-U_FORTIFY_SOURCE" export CXXFLAGS="$CXXFLAGS -DCYNARA_STATE_PATH=\\\"%{state_path}\\\" \ -DCYNARA_LIB_PATH=\\\"%{lib_path}\\\" \ -DCYNARA_TESTS_DIR=\\\"%{tests_dir}\\\" \ - -DCYNARA_CONFIGURATION_DIR=\\\"%{conf_path}\\\"" + -DCYNARA_CONFIGURATION_DIR=\\\"%{conf_path}\\\" \ + -DCYNARA_VERSION=\\\"%{version}\\\"" export LDFLAGS+="-Wl,--rpath=%{_libdir}" %cmake . \ diff --git a/src/service/CMakeLists.txt b/src/service/CMakeLists.txt index b28058b..50392cc 100644 --- a/src/service/CMakeLists.txt +++ b/src/service/CMakeLists.txt @@ -22,6 +22,7 @@ SET(CYNARA_SOURCES ${CYNARA_SERVICE_PATH}/agent/AgentManager.cpp ${CYNARA_SERVICE_PATH}/agent/AgentTalker.cpp ${CYNARA_SERVICE_PATH}/logic/Logic.cpp + ${CYNARA_SERVICE_PATH}/main/CmdlineParser.cpp ${CYNARA_SERVICE_PATH}/main/Cynara.cpp ${CYNARA_SERVICE_PATH}/main/main.cpp ${CYNARA_SERVICE_PATH}/request/CheckRequestManager.cpp diff --git a/src/service/main/CmdlineParser.cpp b/src/service/main/CmdlineParser.cpp new file mode 100644 index 0000000..cd8e4cb --- /dev/null +++ b/src/service/main/CmdlineParser.cpp @@ -0,0 +1,93 @@ +/* + * 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/service/main/CmdlineParser.cpp + * @author Pawel Wieczorek + * @version 1.0 + * @brief Helper namespace for Cynara's command-line options parsing + */ + +#include +#include +#include + +#include "CmdlineParser.h" + +namespace Cynara { + +namespace CmdlineParser { + +std::ostream &operator<<(std::ostream &os, CmdlineOpt opt) { + return os << static_cast(opt); +} + +bool handleCmdlineOptions(int argc, char * const *argv) { + const std::string execName(argv[0]); + std::stringstream shortOpts; + shortOpts << ":" << CmdlineOpt::Help << CmdlineOpt::Version; + + const struct option longOpts[] = { + { "help", no_argument, NULL, CmdlineOpt::Help }, + { "version", no_argument, NULL, CmdlineOpt::Version }, + { NULL, 0, NULL, 0 } + }; + + + optind = 0; // On entry to `getopt', zero means this is the first call; initialize. + int opt; + while ((opt = getopt_long(argc, argv, shortOpts.str().c_str(), longOpts, nullptr)) != -1) { + switch (opt) { + case CmdlineOpt::Help: + printHelp(execName); + return true; + case CmdlineOpt::Version: + printVersion(); + return true; + case '?': // Unknown option + default: + printUnknownOption(execName); + return false; + } + } + + printNoOptions(execName); + return false; +} + +void printHelp(const std::string &execName) { + std::cout << "Usage: " << execName << " [OPTIONS]" << std::endl << std::endl; + std::cout << " -V, --version print version of " << execName << " and exit" + << std::endl; + std::cout << " -h, --help print this help message and exit" << std::endl; +} + +void printVersion(void) { + std::cout << std::string(CYNARA_VERSION) << std::endl; +} + +void printUnknownOption(const std::string &execName) { + std::cerr << "Unknown option" << std::endl; + printHelp(execName); +} + +void printNoOptions(const std::string &execName) { + std::cerr << "No options given" << std::endl; + printHelp(execName); +} + +} /* namespace CmdlineOpts */ + +} /* namespace Cynara */ diff --git a/src/service/main/CmdlineParser.h b/src/service/main/CmdlineParser.h new file mode 100644 index 0000000..31d87df --- /dev/null +++ b/src/service/main/CmdlineParser.h @@ -0,0 +1,50 @@ +/* + * 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/service/main/CmdlineParser.h + * @author Pawel Wieczorek + * @version 1.0 + * @brief Helper namespace for Cynara's command-line options parsing + */ + +#ifndef SRC_SERVICE_MAIN_CMDLINEPARSER_H_ +#define SRC_SERVICE_MAIN_CMDLINEPARSER_H_ + +#include +#include + +namespace Cynara { + +namespace CmdlineParser { + +enum CmdlineOpt { + Help = 'h', + Version = 'V' +}; + +std::ostream &operator<<(std::ostream &os, CmdlineOpt opt); + +bool handleCmdlineOptions(int argc, char * const *argv); +void printHelp(const std::string &execName); +void printVersion(void); +void printUnknownOption(const std::string &execName); +void printNoOptions(const std::string &execName); + +} /* namespace CmdlineOpts */ + +} /* namespace Cynara */ + +#endif /* SRC_SERVICE_MAIN_CMDLINEPARSER_H_ */ diff --git a/src/service/main/main.cpp b/src/service/main/main.cpp index a89e3a7..969510d 100644 --- a/src/service/main/main.cpp +++ b/src/service/main/main.cpp @@ -24,6 +24,7 @@ */ #include +#include #include #include @@ -31,12 +32,19 @@ #include #include + +#include "CmdlineParser.h" #include "Cynara.h" -int main(int argc UNUSED, char **argv UNUSED) { +int main(int argc, char **argv) { init_log(); try { + if (1 < argc) { + auto handlingSuccess = Cynara::CmdlineParser::handleCmdlineOptions(argc, argv); + return (handlingSuccess ? EXIT_SUCCESS : EXIT_FAILURE); + } + Cynara::Cynara cynara; LOGI("Cynara service is starting ..."); cynara.init(); -- 2.7.4 From 4537417423bfa6f63dff2dd6254f7570c804d23d Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Tue, 17 Feb 2015 10:28:02 +0100 Subject: [PATCH 15/16] Add tests for version reporting This patch adds tests for calling main Cynara executable with additional options. Following call scenarios are checked (both long and short options): * print version, * print help, * unknown option. Change-Id: Ibab5d7a081fd1da8b98a59c9a242fd17725cd400 --- test/CMakeLists.txt | 2 + test/service/main/CynaraCommandlineTest.h | 31 +++++++ test/service/main/cmdlineparser.cpp | 135 ++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 test/service/main/CynaraCommandlineTest.h create mode 100644 test/service/main/cmdlineparser.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 119e2e7..8032ee3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -59,6 +59,7 @@ SET(CYNARA_SOURCES_FOR_TESTS ${CYNARA_SRC}/cyad/PolicyTypeTranslator.cpp ${CYNARA_SRC}/helpers/creds-commons/CredsCommonsInner.cpp ${CYNARA_SRC}/helpers/creds-commons/creds-commons.cpp + ${CYNARA_SRC}/service/main/CmdlineParser.cpp ${CYNARA_SRC}/storage/BucketDeserializer.cpp ${CYNARA_SRC}/storage/InMemoryStorageBackend.cpp ${CYNARA_SRC}/storage/Integrity.cpp @@ -86,6 +87,7 @@ SET(CYNARA_TESTS_SOURCES cyad/policy_collection.cpp cyad/policy_parser.cpp helpers.cpp + service/main/cmdlineparser.cpp storage/performance/bucket.cpp storage/storage/policies.cpp storage/storage/check.cpp diff --git a/test/service/main/CynaraCommandlineTest.h b/test/service/main/CynaraCommandlineTest.h new file mode 100644 index 0000000..eaf208d --- /dev/null +++ b/test/service/main/CynaraCommandlineTest.h @@ -0,0 +1,31 @@ +/* + * 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/service/main/CynaraCommandlineTest.h + * @author Pawel Wieczorek + * @version 1.0 + * @brief Fixture for CmdlineParser tests + */ + +#ifndef TEST_SERVICE_MAIN_CYNARACOMMANDLINETEST_H_ +#define TEST_SERVICE_MAIN_CYNARACOMMANDLINETEST_H_ + +#include + +class CynaraCommandlineTest : public QuietCommandlineTest { +}; + +#endif /* TEST_SERVICE_MAIN_CYNARACOMMANDLINETEST_H_ */ diff --git a/test/service/main/cmdlineparser.cpp b/test/service/main/cmdlineparser.cpp new file mode 100644 index 0000000..3f6a43b --- /dev/null +++ b/test/service/main/cmdlineparser.cpp @@ -0,0 +1,135 @@ +/* + * 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/service/main/cmdlineparser.cpp + * @author Pawel Wieczorek + * @version 1.0 + * @brief Tests of CmdlineParser + */ + +#include + +#include + +#include "CynaraCommandlineTest.h" + +namespace { + +const std::string execName("./cynara"); +const std::string helpMessage("Usage: " + execName + " [OPTIONS]\n\n" + " -V, --version print version of ./cynara and exit\n" + " -h, --help print this help message and exit\n"); + +} // namespace + +namespace Parser = Cynara::CmdlineParser; + +/** + * @brief Verify if passing "help" option to commandline handler returns help message + * @test Expected result: + * - call handler indicates success + * - help message in output stream + * - empty error stream + */ +TEST_F(CynaraCommandlineTest, help) { + std::string err; + std::string out; + + for (const auto &opt : { "-h", "--help" }) { + clearOutput(); + prepare_argv({ execName, opt }); + + SCOPED_TRACE(opt); + const auto handlingSuccess = Parser::handleCmdlineOptions(this->argc(), this->argv()); + getOutput(out, err); + + ASSERT_TRUE(handlingSuccess); + ASSERT_EQ(helpMessage, out); + ASSERT_TRUE(err.empty()); + } +} + +/** + * @brief Verify if passing "version" option to commandline handler returns version message + * @test Expected result: + * - call handler indicates success + * - version message in output stream + * - empty error stream + */ +TEST_F(CynaraCommandlineTest, version) { + std::string err; + std::string out; + + for (const auto &opt : { "-V", "--version" }) { + clearOutput(); + prepare_argv({ execName, opt }); + + SCOPED_TRACE(opt); + const auto handlingSuccess = Parser::handleCmdlineOptions(this->argc(), this->argv()); + getOutput(out, err); + + ASSERT_TRUE(handlingSuccess); + ASSERT_EQ(std::string(CYNARA_VERSION) + "\n", out); + ASSERT_TRUE(err.empty()); + } +} + +/** + * @brief Verify if passing unknown option to commandline handler returns error message + * @test Expected result: + * - call handler indicates failure + * - help message in output stream + * - error message in error stream + */ +TEST_F(CynaraCommandlineTest, unknownOption) { + std::string err; + std::string out; + + for (const auto &badOpt : { "-b", "--badOption" }) { + clearOutput(); + prepare_argv({ execName, badOpt }); + + SCOPED_TRACE(badOpt); + const auto handlingSuccess = Parser::handleCmdlineOptions(this->argc(), this->argv()); + getOutput(out, err); + + ASSERT_FALSE(handlingSuccess); + ASSERT_EQ(helpMessage, out); + ASSERT_EQ("Unknown option\n", err); + } +} + +/** + * @brief Verify if passing no options to commandline handler returns error message + * @test Expected result: + * - call handler indicates failure + * - help message in output stream + * - error message in error stream + */ +TEST_F(CynaraCommandlineTest, noOption) { + std::string err; + std::string out; + + clearOutput(); + prepare_argv({ execName }); + + const auto handlingSuccess = Parser::handleCmdlineOptions(this->argc(), this->argv()); + getOutput(out, err); + + ASSERT_FALSE(handlingSuccess); + ASSERT_EQ(helpMessage, out); + ASSERT_EQ("No options given\n", err); +} -- 2.7.4 From ba1d0344f96918023da91dad7ac35c53b89c1517 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Wed, 4 Feb 2015 12:11:19 +0100 Subject: [PATCH 16/16] Modify version check during package upgrade Cynara has to determine its currently installed version during package upgrade. Doing RPM queries from inside install-time scripts isn't recommended. Necessary information is obtained from Cynara's version information. However, not all Cynara releases provided mechanism of reporting its version. In case of lack of it, following fallback mechanism is provided: version information is extracted from a name of a file that Cynara depends on, which currently is "/libcynara-commons.so.". Change-Id: I5c9a2abf123d91a32513980e3f9c24112d59547c --- packaging/cynara.spec | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 2eb9a23..bc51ae6 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -225,9 +225,26 @@ if [ $? -eq 1 ]; then fi if [ $1 -gt 1 ] ; then - OLDVERSION="$(rpm -q --qf '%%{version}' %{name})" - %{_sbindir}/cynara/cynara-db-migration.sh upgrade -f ${OLDVERSION} -t %{version} + # upgrade + OLD_VERSION="" + VERSION_INDICATOR="$(ls %{_libdir}/libcynara-commons\.so\.*\.*\.*)" + if [ -z "${VERSION_INDICATOR}" ] ; then + # For releases which dropped "%{_libdir}/libcynara-commons\.so\.*" file + OLD_VERSION="$(/usr/bin/cynara --version)" + else + VERSION="${VERSION_INDICATOR##*so\.}" + SIGNIFICANT="${VERSION%\.*}" + if [ 0 -eq "${SIGNIFICANT%%\.*}" -a 5 -ge "${SIGNIFICANT##*\.}" ] ; then + # For releases which did not provide "--version" functionality + OLD_VERSION="${VERSION}" + else + OLD_VERSION="$(/usr/bin/cynara --version)" + fi + fi + + %{_sbindir}/cynara/cynara-db-migration.sh upgrade -f ${OLD_VERSION} -t %{version} else + # install %{_sbindir}/cynara/cynara-db-migration.sh install -t %{version} fi -- 2.7.4