From: Zofia Abramowska Date: Thu, 17 Jul 2014 12:38:56 +0000 (+0200) Subject: Change cache interface and add simple implementations X-Git-Tag: accepted/tizen/common/20140801.173752~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0552bff66f450d8fd66dda8ed10444b1150a9e20;p=platform%2Fcore%2Fsecurity%2Fcynara.git Change cache interface and add simple implementations Change CacheInterface so it supports different plugins Implement naive plugin Implement class responsible for getting values from server Change-Id: I8ca21a65ec9b9dfcbc922270d2b1351797bbd92d --- diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 72db5f1..4431556 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -23,7 +23,8 @@ SET(CYNARA_LIB_CYNARA_PATH ${CYNARA_PATH}/client) SET(LIB_CYNARA_SOURCES ${CYNARA_LIB_CYNARA_PATH}/api/client-api.cpp - ${CYNARA_LIB_CYNARA_PATH}/cache/NoCache.cpp + ${CYNARA_LIB_CYNARA_PATH}/cache/CapacityCache.cpp + ${CYNARA_LIB_CYNARA_PATH}/cache/PolicyGetter.cpp ${CYNARA_LIB_CYNARA_PATH}/logic/Logic.cpp ) diff --git a/src/client/cache/CacheInterface.h b/src/client/cache/CacheInterface.h index acfbd7e..22c4cb9 100644 --- a/src/client/cache/CacheInterface.h +++ b/src/client/cache/CacheInterface.h @@ -16,37 +16,66 @@ /* * @file CacheInterface.h * @author Lukasz Wojciechowski + * @author Zofia Abramowska * @version 1.0 - * @brief This file contains cache interface definition. + * @brief This file contains cache interface definitions. */ #ifndef SRC_CLIENT_CACHE_CACHEINTERFACE_H_ #define SRC_CLIENT_CACHE_CACHEINTERFACE_H_ +#include #include #include +#include #include #include - -#include +#include namespace Cynara { -class CacheInterface; -typedef std::shared_ptr CacheInterfacePtr; +class InterpreterInterface; +typedef std::shared_ptr InterpreterInterfacePtr; + +class PluginCache; +typedef std::shared_ptr PluginCachePtr; + +class ResultGetterInterface; +typedef std::shared_ptr ResultGetterInterfacePtr; + +class ResultGetterInterface { +public: + virtual cynara_api_result requestResult(const PolicyKey &key, PolicyResult &result) noexcept = 0; + virtual ~ResultGetterInterface() = default; +}; + +class InterpreterInterface { +public: + virtual bool isCacheable(const PolicyResult &result) noexcept = 0; + virtual bool isUsable(const PolicyResult &result) noexcept = 0; + virtual cynara_api_result toResult(const PolicyResult &result) noexcept = 0; + + virtual ~InterpreterInterface() = default; +}; -class CacheInterface { +class PluginCache { public: - CacheInterface() = default; - virtual ~CacheInterface() = default; + PluginCache(ResultGetterInterfacePtr getter) : m_getter(getter) {} + virtual cynara_api_result get(const std::string &session, const PolicyKey &key) = 0; + void registerPlugin(const PolicyType policyType, InterpreterInterfacePtr plugin) { + m_plugins[policyType] = plugin; + } + virtual void clear(void) { + m_plugins.clear(); + } + virtual ~PluginCache() = default; - virtual cynara_api_result check(const std::string &session, const PolicyKey &key) = 0; - virtual cynara_api_result updateAndCheck(const std::string &session, const PolicyKey &key, - const PolicyResult &result) = 0; - virtual void clear(void) = 0; +protected: + std::map m_plugins; + ResultGetterInterfacePtr m_getter; }; } // namespace Cynara -#endif /* SRC_CLIENT_CACHE_CACHEINTERFACE_H_ */ +#endif // SRC_CLIENT_CACHE_CACHEINTERFACE_H_ diff --git a/src/client/cache/CapacityCache.cpp b/src/client/cache/CapacityCache.cpp new file mode 100644 index 0000000..6b9f48e --- /dev/null +++ b/src/client/cache/CapacityCache.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2014 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 CapacityCache.cpp + * @author Zofia Abramowska + * @version 1.0 + * @brief This file contains capacity cache implementation. + */ + +#include + +#include + +#include + +namespace Cynara { + +cynara_api_result CapacityCache::get(const std::string &session, const PolicyKey &key) { + //This can be very time heavy. This part is welcomed to be optimized. + if (session != m_session) { + LOGD("Session changed from %s to %s.", m_session.c_str(), session.c_str()); + m_keyValue.clear(); + m_keyUsage.clear(); + m_session = session; + } + auto resultIt = m_keyValue.find(keyToString(key)); + //Do we have entry in cache? + if (resultIt == m_keyValue.end()) { + LOGD("No entry for client=%s user=%s privilege=%s.", + key.client().toString().c_str(), + key.user().toString().c_str(), + key.privilege().toString().c_str()); + return update(key); + } else { + LOGD("Entry available for client=%s user=%s privilege=%s", + key.client().toString().c_str(), + key.user().toString().c_str(), + key.privilege().toString().c_str()); + + auto pluginIt = m_plugins.find(resultIt->second.first.policyType()); + if (pluginIt == m_plugins.end()) { + LOGE("No plugin registered for given PolicyType : %" PRIu16, + resultIt->second.first.policyType()); + return cynara_api_result::CYNARA_API_ACCESS_DENIED; + } + + //Is it still usable? + InterpreterInterfacePtr plugin = pluginIt->second; + if (plugin->isUsable(resultIt->second.first)) { + LOGD("Entry usable."); + m_keyUsage.splice(m_keyUsage.begin(), m_keyUsage, resultIt->second.second); + return plugin->toResult(resultIt->second.first); + } else { + //remove from list and map and update + LOGD("Entry not usable."); + auto usage_it = resultIt->second.second; + m_keyUsage.erase(usage_it); + m_keyValue.erase(resultIt); + return update(key); + } + } +} + +void CapacityCache::clear(void) { + m_keyUsage.clear(); + m_keyValue.clear(); + m_session.clear(); +} + +std::string CapacityCache::keyToString(const PolicyKey &key) { + const char separator = '\1'; + auto clientStr = key.client().toString(); + auto privilegeStr = key.privilege().toString(); + auto userStr = key.user().toString(); + return clientStr + privilegeStr + userStr + separator + + std::to_string(clientStr.size()) + separator + + std::to_string(privilegeStr.size()) + separator + + std::to_string(userStr.size()); +} + +void CapacityCache::evict(void) { + + auto lastUsedKey = m_keyUsage.back(); + m_keyUsage.pop_back(); + + auto value_it = m_keyValue.find(lastUsedKey); + m_keyValue.erase(value_it); +} + +cynara_api_result CapacityCache::update(const PolicyKey &key) { + cynara_api_result ret; + PolicyResult result; + if ((ret = m_getter->requestResult(key, result)) != cynara_api_result::CYNARA_API_SUCCESS) { + LOGE("Error fetching new entry."); + return ret; + } + LOGD("Fetched new entry."); + auto pluginIt = m_plugins.find(result.policyType()); + + //No registered plugin for returned type of policy + if (pluginIt == m_plugins.end()) { + LOGE("No registered plugin for given PolicyType: %" PRIu16, + result.policyType()); + return cynara_api_result::CYNARA_API_ACCESS_DENIED; + } + auto plugin = pluginIt->second; + + if (m_capacity != 0) { + if (plugin->isCacheable(result)) { + LOGD("Entry cacheable"); + if (m_keyValue.size() == m_capacity) { + LOGD("Capacity reached."); + evict(); + } + m_keyUsage.push_front(keyToString(key)); + m_keyValue[keyToString(key)] = std::make_pair(result, m_keyUsage.begin()); + } + } + return plugin->toResult(result); +} + +} // namespace Cynara diff --git a/src/client/cache/CapacityCache.h b/src/client/cache/CapacityCache.h new file mode 100644 index 0000000..b5c4a1f --- /dev/null +++ b/src/client/cache/CapacityCache.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014 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 CapacityCache.h + * @author Zofia Abramowska + * @version 1.0 + * @brief This file contains capacity cache header. + */ + +#ifndef SRC_CLIENT_CACHE_CAPACITYCACHE_H_ +#define SRC_CLIENT_CACHE_CAPACITYCACHE_H_ + +#include +#include + +#include + +namespace Cynara { + +class CapacityCache : public PluginCache { +public: + static const std::size_t CACHE_DEFAULT_CAPACITY = 10000; + + CapacityCache(ResultGetterInterfacePtr getter, + std::size_t capacity = CACHE_DEFAULT_CAPACITY) : + PluginCache(getter), + m_capacity(capacity) {} + + cynara_api_result get(const std::string &session, + const PolicyKey &key); + void clear(void); + +private: + typedef std::list KeyUsageList; + typedef std::map> KeyValueMap; + + static std::string keyToString(const PolicyKey &key); + void evict(void); + cynara_api_result update(const PolicyKey &key); + + std::size_t m_capacity; + std::string m_session; + + KeyUsageList m_keyUsage; + KeyValueMap m_keyValue; +}; + +} //namespace Cynara + +#endif // SRC_CLIENT_CACHE_CAPACITYCACHE_H_ + + + + diff --git a/src/client/cache/NaiveInterpreter.h b/src/client/cache/NaiveInterpreter.h new file mode 100644 index 0000000..6b96d4b --- /dev/null +++ b/src/client/cache/NaiveInterpreter.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 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 NaiveInterpreter.h + * @author Zofia Abramowska + * @version 1.0 + * @brief This file contains PolicyType naive interpreter implementation. + */ +#ifndef SRC_CLIENT_CACHE_NAIVEINTERPRETER_H_ +#define SRC_CLIENT_CACHE_NAIVEINTERPRETER_H_ + +#include +#include + +namespace Cynara { + +class NaiveInterpreter : public InterpreterInterface { + bool isUsable(const PolicyResult &result UNUSED) noexcept { + return true; + } + bool isCacheable(const PolicyResult &result UNUSED) noexcept { + return true; + } + cynara_api_result toResult(const PolicyResult &result) noexcept { + if (result.policyType() == PredefinedPolicyType::ALLOW) + return cynara_api_result::CYNARA_API_SUCCESS; + else + return cynara_api_result::CYNARA_API_ACCESS_DENIED; + } +}; + +} // namespace Cynara + +#endif // SRC_CLIENT_CACHE_NAIVEINTERPRETER_H_ + + diff --git a/src/client/cache/NoCache.cpp b/src/client/cache/NoCache.cpp deleted file mode 100644 index c9220e3..0000000 --- a/src/client/cache/NoCache.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2014 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 NoCache.cpp - * @author Lukasz Wojciechowski - * @version 1.0 - * @brief This file contains implementation of NoCache class - stub for no-cache version - */ - -#include -#include - -#include "NoCache.h" - -namespace Cynara { - -cynara_api_result NoCache::updateAndCheck(const std::string &session UNUSED, - const PolicyKey &key UNUSED, - const PolicyResult &result) { - if (result.policyType() == PredefinedPolicyType::ALLOW) - return cynara_api_result::CYNARA_API_SUCCESS; - else - return cynara_api_result::CYNARA_API_ACCESS_DENIED; -} - -} // namespace Cynara diff --git a/src/client/cache/NoCache.h b/src/client/cache/NoCache.h deleted file mode 100644 index c4330b1..0000000 --- a/src/client/cache/NoCache.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2014 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 NoCache.h - * @author Lukasz Wojciechowski - * @version 1.0 - * @brief This file contains definition of NoCache class - stub for no-cache version - */ - -#ifndef SRC_CLIENT_CACHE_NOCACHE_H_ -#define SRC_CLIENT_CACHE_NOCACHE_H_ - -#include - -#include -#include -#include - -#include -#include - -namespace Cynara { - -class NoCache : public CacheInterface { -public: - NoCache() = default; - virtual ~NoCache() = default; - - virtual cynara_api_result check(const std::string &session UNUSED, - const PolicyKey &key UNUSED) { - return cynara_api_result::CYNARA_API_SERVICE_NOT_AVAILABLE; - } - - virtual cynara_api_result updateAndCheck(const std::string &session, const PolicyKey &key, - const PolicyResult &result); - - virtual void clear(void) { - } -}; - -} // namespace Cynara - -#endif /* SRC_CLIENT_CACHE_NOCACHE_H_ */ diff --git a/src/client/cache/PolicyGetter.cpp b/src/client/cache/PolicyGetter.cpp new file mode 100644 index 0000000..e383f9f --- /dev/null +++ b/src/client/cache/PolicyGetter.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014 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 PolicyGetter.cpp + * @author Zofia Abramowska + * @version 1.0 + * @brief This file contains PolicyResult getter class implementation. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace Cynara { + +cynara_api_result PolicyGetter::requestResult(const PolicyKey &key, PolicyResult &result) noexcept { + ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber(); + + //Ask cynara service + CheckResponsePtr checkResponse; + try { + RequestPtr request = std::make_shared(key, sequenceNumber); + ResponsePtr response = m_socketClient->askCynaraServer(request); + if (!response) { + LOGW("Disconnected by cynara server."); + return cynara_api_result::CYNARA_API_SERVICE_NOT_AVAILABLE; + } + checkResponse = std::dynamic_pointer_cast(response); + if (!checkResponse) { + LOGC("Critical error. Casting Response to CheckResponse failed."); + return cynara_api_result::CYNARA_API_ACCESS_DENIED; + } + + LOGD("checkResponse: policyType = %" PRIu16 ", metadata = %s", + checkResponse->m_resultRef.policyType(), + checkResponse->m_resultRef.metadata().c_str()); + } catch (const ServerConnectionErrorException &ex) { + LOGE("Cynara service not available."); + return cynara_api_result::CYNARA_API_SERVICE_NOT_AVAILABLE; + } + + result = checkResponse->m_resultRef; + return cynara_api_result::CYNARA_API_SUCCESS; +} + +} // namespace Cynara diff --git a/src/client/cache/PolicyGetter.h b/src/client/cache/PolicyGetter.h new file mode 100644 index 0000000..fec6797 --- /dev/null +++ b/src/client/cache/PolicyGetter.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014 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 PolicyGetter.h + * @author Zofia Abramowska + * @version 1.0 + * @brief This file contains Cynara PolicyResult getter implementation. + */ + +#ifndef SRC_CLIENT_CACHE_POLICYGETTER_H_ +#define SRC_CLIENT_CACHE_POLICYGETTER_H_ + +#include + +#include +#include + + +namespace Cynara { + +class PolicyGetter : public ResultGetterInterface { +public: + PolicyGetter(const SocketClientPtr &socketClient) : m_socketClient(socketClient) {} + cynara_api_result requestResult(const PolicyKey &key, PolicyResult &result) noexcept; + +private: + ProtocolFrameSequenceNumber generateSequenceNumber(void) { + static ProtocolFrameSequenceNumber sequenceNumber = 0; + return ++sequenceNumber; + } + + SocketClientPtr m_socketClient; +}; + +} //namespace Cynara + +#endif // SRC_CLIENT_CACHE_POLICYGETTER_H_ + + + + diff --git a/src/client/logic/Logic.cpp b/src/client/logic/Logic.cpp index ecdf34b..c2d9cb6 100644 --- a/src/client/logic/Logic.cpp +++ b/src/client/logic/Logic.cpp @@ -23,20 +23,14 @@ #include #include -#include -#include -#include #include #include -#include -#include -#include -#include #include #include -#include -#include +#include +#include +#include #include "Logic.h" namespace Cynara { @@ -44,56 +38,25 @@ namespace Cynara { const std::string clientSocketPath("/run/cynara/cynara.socket"); Logic::Logic() { - m_socketClient = std::make_shared(clientSocketPath, - std::make_shared()); - m_cache = std::make_shared(); + m_cache = std::make_shared( + std::make_shared( + std::make_shared(clientSocketPath, + std::make_shared()))); + auto naiveInterpreter = std::make_shared(); + m_cache->registerPlugin(PredefinedPolicyType::ALLOW, naiveInterpreter); + m_cache->registerPlugin(PredefinedPolicyType::DENY, naiveInterpreter); + m_cache->registerPlugin(PredefinedPolicyType::BUCKET, naiveInterpreter); } -ProtocolFrameSequenceNumber generateSequenceNumber(void) { - static ProtocolFrameSequenceNumber sequenceNumber = 0; - return ++sequenceNumber; -} - -cynara_api_result Logic::check(const std::string &client, const std::string &session UNUSED, +cynara_api_result Logic::check(const std::string &client, const std::string &session, const std::string &user, const std::string &privilege) noexcept { PolicyKey key(client, user, privilege); - auto cacheResponse = m_cache->check(session, key); - if(cacheResponse != cynara_api_result::CYNARA_API_SERVICE_NOT_AVAILABLE) - return cacheResponse; - - ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber(); - - //Ask cynara service - CheckResponsePtr checkResponse; - try { - RequestPtr request = std::make_shared(key, sequenceNumber); - ResponsePtr response = m_socketClient->askCynaraServer(request); - if (!response) { - LOGW("Disconnected by cynara server."); - onDisconnected(); - return cynara_api_result::CYNARA_API_SERVICE_NOT_AVAILABLE; - } - checkResponse = std::dynamic_pointer_cast(response); - if (!checkResponse) { - LOGC("Critical error. Casting Response to CheckResponse failed."); - throw UnexpectedErrorException("Error casting Response to CheckResponse"); - } - - LOGD("checkResponse: policyType = %d, metadata = %s", - (int)checkResponse->m_resultRef.policyType(), - checkResponse->m_resultRef.metadata().c_str()); - } catch (const ServerConnectionErrorException &ex) { - LOGE("Cynara service not available."); + auto ret = m_cache->get(session, key); + if (ret == cynara_api_result::CYNARA_API_SERVICE_NOT_AVAILABLE) onDisconnected(); - return cynara_api_result::CYNARA_API_SERVICE_NOT_AVAILABLE; - } catch (const std::exception &ex) { - LOGE("Error during check of privilege: %s", ex.what()); - return cynara_api_result::CYNARA_API_ACCESS_DENIED; - } - - return m_cache->updateAndCheck(session, key, checkResponse->m_resultRef); + return ret; } void Logic::onDisconnected(void) { diff --git a/src/client/logic/Logic.h b/src/client/logic/Logic.h index 06950d8..b2eb486 100644 --- a/src/client/logic/Logic.h +++ b/src/client/logic/Logic.h @@ -25,8 +25,6 @@ #include -#include - #include #include @@ -34,8 +32,7 @@ namespace Cynara { class Logic : public ApiInterface { private: - SocketClientPtr m_socketClient; - CacheInterfacePtr m_cache; + PluginCachePtr m_cache; void onDisconnected(void); diff --git a/src/common/types/PolicyResult.h b/src/common/types/PolicyResult.h index a8febc2..a9369d8 100644 --- a/src/common/types/PolicyResult.h +++ b/src/common/types/PolicyResult.h @@ -34,6 +34,7 @@ public: typedef std::string PolicyMetadata; public: + PolicyResult() : m_type(PredefinedPolicyType::DENY) {} PolicyResult(const PolicyType &policyType) : m_type(policyType) {} PolicyResult(const PolicyType &policyType, const PolicyMetadata &metadata) : m_type(policyType), m_metadata(metadata) {}