Support SASL protocol for memcached
Add the SASL protocol for memcached, to improve the security of authority. SASL(Simple Authentication and Security Layer): is a memchanism used to extend the verification ability of C/S mode. SASL is only the authentication process, which integrates the application layer and the system authentication mechanism. However, the current memcached hasn't any authenticaction mechanism to protect the user's data cached in memcached server. Depends-On: 7828bed0febabfa11a0a8f6960f4c7cc8acec841 Implements: blueprint enable-sasl-protocol Change-Id: I40b9f4eac518f34a3dfb710b5c4ab3a76da7c00c
This commit is contained in:
parent
d2aef19023
commit
d229d3edb7
62
oslo_cache/_bmemcache_pool.py
Normal file
62
oslo_cache/_bmemcache_pool.py
Normal file
@ -0,0 +1,62 @@
|
||||
# Copyright 2022 Inspur
|
||||
# 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.
|
||||
|
||||
"""Thread-safe connection pool for python-binary-memcached."""
|
||||
try:
|
||||
import eventlet
|
||||
except ImportError:
|
||||
eventlet = None
|
||||
import bmemcached
|
||||
from oslo_cache._memcache_pool import MemcacheClientPool
|
||||
from oslo_log import log
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class _BMemcacheClient(bmemcached.Client):
|
||||
"""Thread global memcache client
|
||||
|
||||
As client is inherited from threading.local we have to restore object
|
||||
methods overloaded by threading.local so we can reuse clients in
|
||||
different threads
|
||||
"""
|
||||
__delattr__ = object.__delattr__
|
||||
__getattribute__ = object.__getattribute__
|
||||
__setattr__ = object.__setattr__
|
||||
|
||||
# Hack for lp 1812935
|
||||
if eventlet and eventlet.patcher.is_monkey_patched('thread'):
|
||||
# NOTE(bnemec): I'm not entirely sure why this works in a
|
||||
# monkey-patched environment and not with vanilla stdlib, but it does.
|
||||
def __new__(cls, *args, **kwargs):
|
||||
return object.__new__(cls)
|
||||
else:
|
||||
__new__ = object.__new__
|
||||
|
||||
def __del__(self):
|
||||
pass
|
||||
|
||||
|
||||
class BMemcacheClientPool(MemcacheClientPool):
|
||||
def __init__(self, urls, arguments, **kwargs):
|
||||
MemcacheClientPool.__init__(self, urls, arguments, **kwargs)
|
||||
self._arguments = {
|
||||
'username': arguments.get('username', None),
|
||||
'password': arguments.get('password', None),
|
||||
'tls_context': arguments.get('tls_context', None),
|
||||
}
|
||||
|
||||
def _create_connection(self):
|
||||
return _BMemcacheClient(self.urls, **self._arguments)
|
@ -204,7 +204,14 @@ class MemcacheClientPool(ConnectionPool):
|
||||
# old-style class
|
||||
ConnectionPool.__init__(self, **kwargs)
|
||||
self.urls = urls
|
||||
self._arguments = arguments
|
||||
self._arguments = {
|
||||
'dead_retry': arguments.get('dead_retry', 5 * 60),
|
||||
'socket_timeout': arguments.get('socket_timeout', 3.0),
|
||||
'server_max_value_length':
|
||||
arguments.get('server_max_value_length'),
|
||||
'flush_on_reconnect': arguments.get(
|
||||
'pool_flush_on_reconnect', False),
|
||||
}
|
||||
# NOTE(morganfainberg): The host objects expect an int for the
|
||||
# deaduntil value. Initialize this at 0 for each host with 0 indicating
|
||||
# the host is not dead.
|
||||
|
@ -116,6 +116,16 @@ FILE_OPTIONS = {
|
||||
help='Global toggle if memcache will be flushed'
|
||||
' on reconnect.'
|
||||
' (oslo_cache.memcache_pool backend only).'),
|
||||
cfg.BoolOpt('memcache_sasl_enabled',
|
||||
default=False,
|
||||
help='Enable the SASL(Simple Authentication and Security'
|
||||
'Layer) if the SASL_enable is true, else disable.'),
|
||||
cfg.StrOpt('memcache_username',
|
||||
default='',
|
||||
help='the user name for the memcached which SASL enabled'),
|
||||
cfg.StrOpt('memcache_password',
|
||||
default='',
|
||||
help='the password for the memcached which SASL enabled'),
|
||||
cfg.BoolOpt('tls_enabled',
|
||||
default=False,
|
||||
help='Global toggle for TLS usage when comunicating with'
|
||||
|
@ -19,6 +19,7 @@ import functools
|
||||
|
||||
from dogpile.cache.backends import memcached as memcached_backend
|
||||
|
||||
from oslo_cache import _bmemcache_pool
|
||||
from oslo_cache import _memcache_pool
|
||||
|
||||
|
||||
@ -55,20 +56,24 @@ class PooledMemcachedBackend(memcached_backend.MemcachedBackend):
|
||||
# Composed from GenericMemcachedBackend's and MemcacheArgs's __init__
|
||||
def __init__(self, arguments):
|
||||
super(PooledMemcachedBackend, self).__init__(arguments)
|
||||
self.client_pool = _memcache_pool.MemcacheClientPool(
|
||||
self.url,
|
||||
arguments={
|
||||
'dead_retry': arguments.get('dead_retry', 5 * 60),
|
||||
'socket_timeout': arguments.get('socket_timeout', 3.0),
|
||||
'server_max_value_length':
|
||||
arguments.get('server_max_value_length'),
|
||||
'flush_on_reconnect': arguments.get('pool_flush_on_reconnect',
|
||||
False),
|
||||
},
|
||||
maxsize=arguments.get('pool_maxsize', 10),
|
||||
unused_timeout=arguments.get('pool_unused_timeout', 60),
|
||||
conn_get_timeout=arguments.get('pool_connection_get_timeout', 10),
|
||||
)
|
||||
if arguments.get('sasl_enabled', False):
|
||||
self.client_pool = _bmemcache_pool.BMemcacheClientPool(
|
||||
self.url,
|
||||
arguments,
|
||||
maxsize=arguments.get('pool_maxsize', 10),
|
||||
unused_timeout=arguments.get('pool_unused_timeout', 60),
|
||||
conn_get_timeout=arguments.get('pool_connection_get_timeout',
|
||||
10),
|
||||
)
|
||||
else:
|
||||
self.client_pool = _memcache_pool.MemcacheClientPool(
|
||||
self.url,
|
||||
arguments,
|
||||
maxsize=arguments.get('pool_maxsize', 10),
|
||||
unused_timeout=arguments.get('pool_unused_timeout', 60),
|
||||
conn_get_timeout=arguments.get('pool_connection_get_timeout',
|
||||
10),
|
||||
)
|
||||
|
||||
# Since all methods in backend just call one of methods of client, this
|
||||
# lets us avoid need to hack it too much
|
||||
|
@ -163,7 +163,8 @@ def _build_cache_config(conf):
|
||||
conf.cache.memcache_servers)
|
||||
for arg in ('dead_retry', 'socket_timeout', 'pool_maxsize',
|
||||
'pool_unused_timeout', 'pool_connection_get_timeout',
|
||||
'pool_flush_on_reconnect'):
|
||||
'pool_flush_on_reconnect', 'sasl_enabled', 'username',
|
||||
'password'):
|
||||
value = getattr(conf.cache, 'memcache_' + arg)
|
||||
conf_dict['%s.arguments.%s' % (prefix, arg)] = value
|
||||
|
||||
|
@ -30,3 +30,20 @@ class TestMemcachePoolCacheBackend(test_base.BaseTestCaseCacheBackend):
|
||||
# config fixture is properly initialized with value related to
|
||||
# the current backend in use.
|
||||
super(TestMemcachePoolCacheBackend, self).setUp()
|
||||
|
||||
|
||||
class TestBMemcachePoolCacheBackend(test_base.BaseTestCaseCacheBackend):
|
||||
def setUp(self):
|
||||
MEMCACHED_PORT = os.getenv("OSLO_CACHE_TEST_MEMCACHED_PORT", "11211")
|
||||
# If the cache support the sasl, the memcache_sasl_enabled
|
||||
# should be True.
|
||||
self.config_fixture.config(
|
||||
group='cache',
|
||||
backend='oslo_cache.memcache_pool',
|
||||
enabled=True,
|
||||
memcache_servers=[f'localhost:{MEMCACHED_PORT}'],
|
||||
memcache_sasl_enabled=False,
|
||||
memcache_username='sasl_name',
|
||||
memcache_password='sasl_pswd'
|
||||
)
|
||||
super(TestBMemcachePoolCacheBackend, self).setUp()
|
||||
|
@ -18,6 +18,7 @@ from unittest import mock
|
||||
import testtools
|
||||
from testtools import matchers
|
||||
|
||||
from oslo_cache import _bmemcache_pool
|
||||
from oslo_cache import _memcache_pool
|
||||
from oslo_cache import exception
|
||||
from oslo_cache.tests import test_cache
|
||||
@ -161,3 +162,13 @@ class TestMemcacheClientOverrides(test_cache.BaseTestCase):
|
||||
self.assertFalse(client.do_check_key)
|
||||
# Make sure our __new__ override still results in the right type
|
||||
self.assertIsInstance(client, _memcache_pool._MemcacheClient)
|
||||
|
||||
|
||||
class TestBMemcacheClient(test_cache.BaseTestCase):
|
||||
|
||||
def test_can_create_with_kwargs(self):
|
||||
client = _bmemcache_pool._BMemcacheClient('foo', password='123456')
|
||||
# Make sure kwargs are properly processed by the client
|
||||
self.assertEqual('123456', client.password)
|
||||
# Make sure our __new__ override still results in the right type
|
||||
self.assertIsInstance(client, _bmemcache_pool._BMemcacheClient)
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add the feature to support SASL for olso.cache to improve the security
|
||||
of authority.
|
Loading…
Reference in New Issue
Block a user