此處以OpenStack mitaka版本為例,實際最新的Ocata版本也差不多,keystone的管理端口為35357,公共服務端口為5000,使用者認證的方式包括使用者密碼認證和admin_token認證兩種方式。用戶端的authenticate()方法主要完成三個主要工作:a.嘗試從本地擷取token。b.本地沒有token設定為強制更新,從伺服器擷取token。c.将新的token儲存在本地。伺服器端的admin_token認證方式判斷用戶端發傳來的token與配置檔案裡的admin_token是否一緻,使用者密碼認證方式authenticate()方法主要完成三個工作:a.如果封包中有token這個字段,則進行token認證。b.嘗試外部認證。c.嘗試本地認證。一個token有三個重要的屬性:ID、使用者資訊、服務目錄。
以擷取某個使用者資訊為例分析keystonev2.0源碼。
用戶端:
加載使用者資源。
/keystoneclient/v2_0/client.py
class Client(httpclient.HTTPClient):
def __init__(self, **kwargs):
...
self.users = users.UserManager(self._adapter, self.roles)
...
設定請求的url和userid參數。
/keystoneclient/v2_0/users.py
class UserManager(base.ManagerWithFind):
...
def get(self, user):
return self._get("/users/%s" % base.getid(user), "user")
...
最終調用HTTPClient發送GET請求
class Manager(object):
...
def _get(self, url, response_key, **kwargs):
resp, body = self.client.get(url, **kwargs)
return self.resource_class(self, body[response_key], loaded=True)
...
伺服器端:
通過wsgi完成keystone元件中所有資源與用戶端請求的映射,此處的routers包含identity_routers.Admin(),
assignment_routers.Admin(),
token_routers.Router(),
resource_routers.Admin(),
admin_crud.Router(),
routers.VersionV2(‘admin’),
routers.Extension()
管理服務的routers定義在/keystone/version/service.py中的admin_app.factory()方法中
公共服務的routers定義在/keystone/version/service.py中的public_app.factory()方法中
/keystone/common/wsgi.py
class ComposingRouter(Router):
def __init__(self, mapper=None, routers=None):
if mapper is None:
mapper = routes.Mapper()
if routers is None:
routers = []
for router in routers:
router.add_routes(mapper)
super(ComposingRouter, self).__init__(mapper)
以identity.routers.Admin()為例,完成對用戶端請求資源的響應,可以看到對應請求的url為’/users/{user_id}’,業務處理的控制器為user_controller,處理方法為get_user,請求為GET類型。
/keystone/identity/routers.py
class Admin(wsgi.ComposableRouter):
def add_routes(self, mapper):
# User Operations
user_controller = controllers.User()
mapper.connect('/users/{user_id}',
controller=user_controller,
action='get_user',
conditions=dict(method=['GET']))
調用API接口查詢ID為{user_id}的使用者
/keystone/identity/controllers.py
def get_user(self, context, user_id):
self.assert_admin(context)
ref = self.identity_api.get_user(user_id)
return {'user': self.v3_to_v2_user(ref)}
此處的identity_api是通過裝飾器模式将其定義為類的成員變量
@dependency.requires('assignment_api', 'identity_api', 'resource_api')
/keystone/common/dependency.py
def requires(*dependencies):
def wrapper(self, *args, **kwargs):
"""Inject each dependency from the registry."""
self.__wrapped_init__(*args, **kwargs)
_process_dependencies(self)
def wrapped(cls):
existing_dependencies = getattr(cls, '_dependencies', set())
cls._dependencies = existing_dependencies.union(dependencies)
if not hasattr(cls, '__wrapped_init__'):
cls.__wrapped_init__ = cls.__init__
cls.__init__ = wrapper
return cls
return wrapped
其中,identity_api會通過父類的構造方法完成預設驅動的加載
class Manager(object):
driver_namespace = None
def __init__(self, driver_name):
self.driver = load_driver(self.driver_namespace, driver_name)
此處的driver_namespace為keystone.identity,driver_name為keystone.conf配置檔案中的identity鍵值
keystone中重要的API
名稱 | 類 | 驅動 | 描述 |
---|---|---|---|
catalog_api | keystone.catalog.Manager | keystone.catalog.backends.sql.Catalog | endpoint管理 |
identity_api | keystone.identity.Manager | keystone.identity.backends.sql.Catalog | user、tenant管理 |
token_api | keystone.token.Manager | keystone.catalog.backends.kvs.Token | token管理 |
policy_api | keystone.policy.Manager | keystone.policy.backends.sql.Policy | policy管理 |