Debugged Castellan API with TatuKeyManager
This commit is contained in:
parent
fa70477628
commit
0b1c82f016
@ -2,6 +2,7 @@
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
castellan>=0.16.0
|
||||
requests>=2.18.2 # Apache-2.0
|
||||
python-keystoneclient!=1.8.0,!=2.1.0,>=1.7.0 # Apache-2.0
|
||||
keystoneauth1>=2.7.0 # Apache-2.0
|
||||
|
@ -1,22 +1,30 @@
|
||||
import falcon
|
||||
import models
|
||||
import os.path
|
||||
from oslo_config import cfg
|
||||
from tatu.castellano import validate_config as validate_castellan_config
|
||||
from tatu.db.persistence import SQLAlchemySessionManager
|
||||
|
||||
def create_app(sa):
|
||||
api = falcon.API(middleware=[models.Logger(), sa])
|
||||
api.add_route('/authorities', models.Authorities())
|
||||
api.add_route('/authorities/{auth_id}', models.Authority())
|
||||
api.add_route('/usercerts', models.UserCerts())
|
||||
api.add_route('/usercerts/{user_id}/{fingerprint}', models.UserCert())
|
||||
api.add_route('/hostcerts', models.HostCerts())
|
||||
api.add_route('/hostcerts/{host_id}/{fingerprint}', models.HostCert())
|
||||
api.add_route('/hosttokens', models.Tokens())
|
||||
api.add_route('/novavendordata', models.NovaVendorData())
|
||||
return api
|
||||
validate_castellan_config()
|
||||
fname = 'tatu.conf'
|
||||
CONF = cfg.CONF
|
||||
if os.path.isfile(fname):
|
||||
CONF(default_config_files=[fname])
|
||||
|
||||
def create_app(sa):
|
||||
api = falcon.API(middleware=[models.Logger(), sa])
|
||||
api.add_route('/authorities', models.Authorities())
|
||||
api.add_route('/authorities/{auth_id}', models.Authority())
|
||||
api.add_route('/usercerts', models.UserCerts())
|
||||
api.add_route('/usercerts/{user_id}/{fingerprint}', models.UserCert())
|
||||
api.add_route('/hostcerts', models.HostCerts())
|
||||
api.add_route('/hostcerts/{host_id}/{fingerprint}', models.HostCert())
|
||||
api.add_route('/hosttokens', models.Tokens())
|
||||
api.add_route('/novavendordata', models.NovaVendorData())
|
||||
return api
|
||||
|
||||
def get_app():
|
||||
return create_app(SQLAlchemySessionManager())
|
||||
return create_app(SQLAlchemySessionManager())
|
||||
|
||||
def main(global_config, **settings):
|
||||
return create_app(SQLAlchemySessionManager())
|
||||
return create_app(SQLAlchemySessionManager())
|
||||
|
@ -1,52 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from tatu.castellan import options as castellan
|
||||
from oslo_config import cfg
|
||||
|
||||
#from sahara.utils.openstack import base as utils
|
||||
|
||||
|
||||
opts = [
|
||||
cfg.BoolOpt('use_barbican_key_manager', default=False,
|
||||
help='Enable the usage of the OpenStack Key Management '
|
||||
'service provided by barbican.'),
|
||||
]
|
||||
|
||||
castellan_opts = [
|
||||
cfg.StrOpt('barbican_api_endpoint',
|
||||
help='The endpoint to use for connecting to the barbican '
|
||||
'api controller. By default, castellan will use the '
|
||||
'URL from the service catalog.'),
|
||||
cfg.StrOpt('barbican_api_version', default='v1',
|
||||
help='Version of the barbican API, for example: "v1"'),
|
||||
]
|
||||
|
||||
castellan_group = cfg.OptGroup(name='castellan',
|
||||
title='castellan key manager options')
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_group(castellan_group)
|
||||
CONF.register_opts(opts)
|
||||
CONF.register_opts(castellan_opts, group=castellan_group)
|
||||
|
||||
|
||||
def validate_config():
|
||||
if CONF.use_barbican_key_manager:
|
||||
# NOTE (elmiko) there is no need to set the api_class as castellan
|
||||
# uses barbican by default.
|
||||
#castellan.set_defaults(CONF, auth_endpoint=utils.retrieve_auth_url())
|
||||
castellan.set_defaults(CONF)
|
||||
else:
|
||||
castellan.set_defaults(CONF, api_class='tatu.castellan.'
|
||||
'tatu_key_manager.TatuKeyManager')
|
@ -1,68 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from castellan.common.objects import passphrase as key
|
||||
from castellan.key_manager import key_manager as km
|
||||
|
||||
|
||||
"""tatu.castellan.tatu_key_manager
|
||||
This module contains the KeyManager class that will be used by the
|
||||
castellan library, it is not meant for direct usage within tatu.
|
||||
"""
|
||||
|
||||
|
||||
class TatuKeyManager(km.KeyManager):
|
||||
"""Tatu specific key manager
|
||||
This manager is a thin wrapper around the secret being stored. It is
|
||||
intended for backward compatible use only. It will not store keys
|
||||
or generate UUIDs but instead return the secret that is being stored.
|
||||
This behavior allows Tatu to continue storing secrets in its database
|
||||
while using the Castellan key manager abstraction.
|
||||
"""
|
||||
def __init__(self, configuration=None):
|
||||
pass
|
||||
|
||||
def create_key(self, context, algorithm=None, length=0,
|
||||
expiration=None, **kwargs):
|
||||
"""creates a key
|
||||
algorithm, length, and expiration are unused by tatu keys.
|
||||
"""
|
||||
return key.Passphrase(passphrase=kwargs.get('passphrase', ''))
|
||||
|
||||
def create_key_pair(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def store(self, context, key, expiration=None, **kwargs):
|
||||
"""store a key
|
||||
in normal usage a store_key will return the UUID of the key as
|
||||
dictated by the key manager. Tatu would then store this UUID in
|
||||
its database to use for retrieval. As tatu is not actually using
|
||||
a key manager in this context it will return the key's payload for
|
||||
storage.
|
||||
"""
|
||||
return key.get_encoded()
|
||||
|
||||
def get(self, context, key_id, **kwargs):
|
||||
"""get a key
|
||||
since tatu is not actually storing key UUIDs the key_id to this
|
||||
function should actually be the key payload. this function will
|
||||
simply return a new TatuKey based on that value.
|
||||
"""
|
||||
return key.Passphrase(passphrase=key_id)
|
||||
|
||||
def delete(self, context, key_id, **kwargs):
|
||||
"""delete a key
|
||||
as there is no external key manager, this function will not
|
||||
perform any external actions. therefore, it won't change anything.
|
||||
"""
|
||||
pass
|
@ -1,52 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from castellan.common.objects import passphrase
|
||||
from castellan import key_manager
|
||||
|
||||
from oslo_context import context
|
||||
|
||||
|
||||
def delete_secret(id, ctx=None):
|
||||
"""delete a secret from the external key manager
|
||||
:param id: The identifier of the secret to delete
|
||||
:param ctx: The context, and associated authentication, to use with
|
||||
this operation (defaults to the current context)
|
||||
"""
|
||||
if ctx is None:
|
||||
ctx = context.current()
|
||||
key_manager.API().delete(ctx, id)
|
||||
|
||||
|
||||
def get_secret(id, ctx=None):
|
||||
"""get a secret associated with an id
|
||||
:param id: The identifier of the secret to retrieve
|
||||
:param ctx: The context, and associated authentication, to use with
|
||||
this operation (defaults to the current context)
|
||||
"""
|
||||
if ctx is None:
|
||||
ctx = context.current()
|
||||
key = key_manager.API().get(ctx, id)
|
||||
return key.get_encoded()
|
||||
|
||||
|
||||
def store_secret(secret, ctx=None):
|
||||
"""store a secret and return its identifier
|
||||
:param secret: The secret to store, this should be a string
|
||||
:param ctx: The context, and associated authentication, to use with
|
||||
this operation (defaults to the current context)
|
||||
"""
|
||||
if ctx is None:
|
||||
ctx = context.current()
|
||||
key = passphrase.Passphrase(secret)
|
||||
return key_manager.API().store(ctx, key)
|
109
tatu/castellano.py
Normal file
109
tatu/castellano.py
Normal file
@ -0,0 +1,109 @@
|
||||
from castellan.common.objects.passphrase import Passphrase
|
||||
from castellan.common.utils import credential_factory
|
||||
from castellan.key_manager import API
|
||||
from castellan.key_manager.key_manager import KeyManager
|
||||
from castellan.options import set_defaults as set_castellan_defaults
|
||||
from oslo_config import cfg
|
||||
|
||||
opts = [
|
||||
cfg.BoolOpt('use_barbican_key_manager', default=False,
|
||||
help='Enable the usage of the OpenStack Key Management '
|
||||
'service provided by barbican.'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(opts, group='tatu')
|
||||
_context = None
|
||||
_api = None
|
||||
|
||||
def validate_config():
|
||||
if CONF.tatu.use_barbican_key_manager:
|
||||
set_castellan_defaults(CONF)
|
||||
else:
|
||||
set_castellan_defaults(CONF,
|
||||
api_class='tatu.castellano.TatuKeyManager')
|
||||
|
||||
def context():
|
||||
global _context
|
||||
if _context is None and CONF.tatu.use_barbican_key_manager:
|
||||
_context = credential_factory(conf=CONF)
|
||||
return _context
|
||||
|
||||
def api():
|
||||
global _api
|
||||
if _api is None:
|
||||
_api = API()
|
||||
return _api
|
||||
|
||||
def delete_secret(id, ctx=None):
|
||||
"""delete a secret from the external key manager
|
||||
:param id: The identifier of the secret to delete
|
||||
:param ctx: The context, and associated authentication, to use with
|
||||
this operation (defaults to the current context)
|
||||
"""
|
||||
api().delete(ctx or context(), id)
|
||||
|
||||
def get_secret(id, ctx=None):
|
||||
"""get a secret associated with an id
|
||||
:param id: The identifier of the secret to retrieve
|
||||
:param ctx: The context, and associated authentication, to use with
|
||||
this operation (defaults to the current context)
|
||||
"""
|
||||
key = api().get(ctx or context(), id)
|
||||
return key.get_encoded()
|
||||
|
||||
def store_secret(secret, ctx=None):
|
||||
"""store a secret and return its identifier
|
||||
:param secret: The secret to store, this should be a string
|
||||
:param ctx: The context, and associated authentication, to use with
|
||||
this operation (defaults to the current context)
|
||||
"""
|
||||
key = Passphrase(secret)
|
||||
return api().store(ctx or context(), key)
|
||||
|
||||
"""
|
||||
This module contains the KeyManager class that will be used by the
|
||||
castellan library, it is not meant for direct usage within tatu.
|
||||
"""
|
||||
class TatuKeyManager(KeyManager):
|
||||
"""Tatu specific key manager
|
||||
This manager is a thin wrapper around the secret being stored. It is
|
||||
intended for backward compatible use only. It will not store keys
|
||||
or generate UUIDs but instead return the secret that is being stored.
|
||||
This behavior allows Tatu to continue storing secrets in its database
|
||||
while using the Castellan key manager abstraction.
|
||||
"""
|
||||
def __init__(self, configuration=None):
|
||||
pass
|
||||
|
||||
def create_key(self, context, algorithm=None, length=0,
|
||||
expiration=None, **kwargs):
|
||||
pass
|
||||
|
||||
def create_key_pair(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def store(self, context, key, expiration=None, **kwargs):
|
||||
"""store a key
|
||||
in normal usage a store_key will return the UUID of the key as
|
||||
dictated by the key manager. Tatu would then store this UUID in
|
||||
its database to use for retrieval. As tatu is not actually using
|
||||
a key manager in this context it will return the key's payload for
|
||||
storage.
|
||||
"""
|
||||
return key.get_encoded()
|
||||
|
||||
def get(self, context, key_id, **kwargs):
|
||||
"""get a key
|
||||
since tatu is not actually storing key UUIDs the key_id to this
|
||||
function should actually be the key payload. this function will
|
||||
simply return a new TatuKey based on that value.
|
||||
"""
|
||||
return Passphrase(passphrase=key_id)
|
||||
|
||||
def delete(self, context, key_id, **kwargs):
|
||||
"""delete a key
|
||||
as there is no external key manager, this function will not
|
||||
perform any external actions. therefore, it won't change anything.
|
||||
"""
|
||||
pass
|
@ -5,7 +5,7 @@ import sqlalchemy as sa
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
import sshpubkeys
|
||||
from tatu.castellan.utils import get_secret, store_secret
|
||||
from tatu.castellano import get_secret, store_secret
|
||||
from tatu.utils import generateCert,random_uuid
|
||||
import uuid
|
||||
from Crypto.PublicKey import RSA
|
||||
|
@ -178,14 +178,8 @@ def test_post_user_unknown_auth(client):
|
||||
assert response.status == falcon.HTTP_NOT_FOUND
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_user'])
|
||||
def test_post_same_user_same_key_fails(client):
|
||||
# Show that using the same user ID and public key fails.
|
||||
body = user_request()
|
||||
response = client.simulate_post(
|
||||
'/usercerts',
|
||||
body=json.dumps(body)
|
||||
)
|
||||
assert response.status == falcon.HTTP_CONFLICT
|
||||
def test_post_same_user_and_key_returns_same_result(client):
|
||||
test_post_user(client)
|
||||
|
||||
def token_request(auth=auth_id, host=host_id):
|
||||
return {
|
||||
|
Loading…
Reference in New Issue
Block a user