4 space indentation
This commit is contained in:
parent
95c0f1011c
commit
7812e1e8b6
@ -1,4 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import requests
|
||||
|
@ -1,4 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
import json
|
||||
import yaml
|
||||
|
@ -1,3 +1,15 @@
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import requests
|
||||
import os
|
||||
|
@ -1,4 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import requests
|
||||
|
@ -1,4 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
|
@ -1,4 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
import json
|
||||
import yaml
|
||||
|
12
setup.py
12
setup.py
@ -1,3 +1,15 @@
|
||||
# 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.
|
||||
|
||||
import setuptools
|
||||
|
||||
# In python < 2.7.4, a lazy loading of package `pbr` will break
|
||||
|
@ -1,3 +1,15 @@
|
||||
# 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.
|
||||
|
||||
import falcon
|
||||
import models
|
||||
import os.path
|
||||
@ -11,6 +23,7 @@ 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())
|
||||
@ -23,8 +36,10 @@ def create_app(sa):
|
||||
api.add_route('/novavendordata', models.NovaVendorData())
|
||||
return api
|
||||
|
||||
|
||||
def get_app():
|
||||
return create_app(SQLAlchemySessionManager())
|
||||
|
||||
|
||||
def main(global_config, **settings):
|
||||
return create_app(SQLAlchemySessionManager())
|
||||
|
@ -1,3 +1,15 @@
|
||||
# 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.
|
||||
|
||||
import falcon
|
||||
import json
|
||||
import logging
|
||||
@ -5,6 +17,7 @@ import uuid
|
||||
from tatu.db import models as db
|
||||
from Crypto.PublicKey import RSA
|
||||
|
||||
|
||||
def validate_uuid(map, key):
|
||||
try:
|
||||
# Verify it's a valid UUID, then convert to canonical string representation
|
||||
@ -14,6 +27,7 @@ def validate_uuid(map, key):
|
||||
msg = '{} is not a valid UUID'.format(map[key])
|
||||
raise falcon.HTTPBadRequest('Bad request', msg)
|
||||
|
||||
|
||||
def validate_uuids(req, params):
|
||||
id_keys = ['token_id', 'auth_id', 'host_id', 'user_id', 'project-id', 'instance-id']
|
||||
if req.method in ('POST', 'PUT'):
|
||||
@ -24,6 +38,7 @@ def validate_uuids(req, params):
|
||||
if key in params:
|
||||
validate_uuid(params, key)
|
||||
|
||||
|
||||
def validate(req, resp, resource, params):
|
||||
if req.content_length:
|
||||
# Store the body since we cannot read the stream again later
|
||||
@ -32,6 +47,7 @@ def validate(req, resp, resource, params):
|
||||
raise falcon.HTTPBadRequest('The POST/PUT request is missing a body.')
|
||||
validate_uuids(req, params)
|
||||
|
||||
|
||||
class Logger(object):
|
||||
def __init__(self):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
@ -47,8 +63,8 @@ class Logger(object):
|
||||
req.body if hasattr(req, 'body') else 'None',
|
||||
resp.status, resp.location, resp.body))
|
||||
|
||||
class Authorities(object):
|
||||
|
||||
class Authorities(object):
|
||||
@falcon.before(validate)
|
||||
def on_post(self, req, resp):
|
||||
try:
|
||||
@ -61,8 +77,8 @@ class Authorities(object):
|
||||
resp.status = falcon.HTTP_201
|
||||
resp.location = '/authorities/' + req.body['auth_id']
|
||||
|
||||
class Authority(object):
|
||||
|
||||
class Authority(object):
|
||||
@falcon.before(validate)
|
||||
def on_get(self, req, resp, auth_id):
|
||||
auth = db.getAuthority(self.session, auth_id)
|
||||
@ -81,8 +97,8 @@ class Authority(object):
|
||||
resp.body = json.dumps(body)
|
||||
resp.status = falcon.HTTP_OK
|
||||
|
||||
class UserCerts(object):
|
||||
|
||||
class UserCerts(object):
|
||||
@falcon.before(validate)
|
||||
def on_post(self, req, resp):
|
||||
# TODO: validation
|
||||
@ -98,8 +114,8 @@ class UserCerts(object):
|
||||
resp.status = falcon.HTTP_201
|
||||
resp.location = '/usercerts/' + user.user_id + '/' + user.fingerprint
|
||||
|
||||
class UserCert(object):
|
||||
|
||||
class UserCert(object):
|
||||
@falcon.before(validate)
|
||||
def on_get(self, req, resp, user_id, fingerprint):
|
||||
user = db.getUserCert(self.session, user_id, fingerprint)
|
||||
@ -115,6 +131,7 @@ class UserCert(object):
|
||||
resp.body = json.dumps(body)
|
||||
resp.status = falcon.HTTP_OK
|
||||
|
||||
|
||||
def hostToJson(host):
|
||||
return json.dumps({
|
||||
'host_id': host.host_id,
|
||||
@ -123,8 +140,8 @@ def hostToJson(host):
|
||||
'key-cert.pub': host.cert,
|
||||
})
|
||||
|
||||
class HostCerts(object):
|
||||
|
||||
class HostCerts(object):
|
||||
@falcon.before(validate)
|
||||
def on_post(self, req, resp):
|
||||
# Note that we could have found the host_id using the token_id.
|
||||
@ -142,8 +159,8 @@ class HostCerts(object):
|
||||
resp.status = falcon.HTTP_201
|
||||
resp.location = '/hostcerts/' + host.host_id + '/' + host.fingerprint
|
||||
|
||||
class HostCert(object):
|
||||
|
||||
class HostCert(object):
|
||||
@falcon.before(validate)
|
||||
def on_get(self, req, resp, host_id, fingerprint):
|
||||
host = db.getHostCert(self.session, host_id, fingerprint)
|
||||
@ -153,8 +170,8 @@ class HostCert(object):
|
||||
resp.body = hostToJson(host)
|
||||
resp.status = falcon.HTTP_OK
|
||||
|
||||
class Tokens(object):
|
||||
|
||||
class Tokens(object):
|
||||
@falcon.before(validate)
|
||||
def on_post(self, req, resp):
|
||||
try:
|
||||
@ -169,8 +186,8 @@ class Tokens(object):
|
||||
resp.status = falcon.HTTP_201
|
||||
resp.location = '/hosttokens/' + token.token_id
|
||||
|
||||
class NovaVendorData(object):
|
||||
|
||||
class NovaVendorData(object):
|
||||
@falcon.before(validate)
|
||||
def on_post(self, req, resp):
|
||||
# An example of the data nova sends to vendordata services:
|
||||
|
@ -1,3 +1,15 @@
|
||||
# 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.passphrase import Passphrase
|
||||
from castellan.common.utils import credential_factory
|
||||
from castellan.key_manager import API
|
||||
@ -16,6 +28,7 @@ CONF.register_opts(opts, group='tatu')
|
||||
_context = None
|
||||
_api = None
|
||||
|
||||
|
||||
def validate_config():
|
||||
if CONF.tatu.use_barbican_key_manager:
|
||||
set_castellan_defaults(CONF)
|
||||
@ -23,18 +36,21 @@ def validate_config():
|
||||
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
|
||||
@ -43,6 +59,7 @@ def delete_secret(id, ctx=None):
|
||||
"""
|
||||
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
|
||||
@ -52,6 +69,7 @@ def get_secret(id, ctx=None):
|
||||
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
|
||||
@ -61,10 +79,13 @@ def store_secret(secret, ctx=None):
|
||||
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
|
||||
@ -73,6 +94,7 @@ class TatuKeyManager(KeyManager):
|
||||
This behavior allows Tatu to continue storing secrets in its database
|
||||
while using the Castellan key manager abstraction.
|
||||
"""
|
||||
|
||||
def __init__(self, configuration=None):
|
||||
pass
|
||||
|
||||
|
@ -1,3 +1,15 @@
|
||||
# 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 datetime import datetime
|
||||
import falcon
|
||||
import os
|
||||
@ -6,12 +18,13 @@ from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
import sshpubkeys
|
||||
from tatu.castellano import get_secret, store_secret
|
||||
from tatu.utils import generateCert,random_uuid
|
||||
from tatu.utils import generateCert, random_uuid
|
||||
import uuid
|
||||
from Crypto.PublicKey import RSA
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
class Authority(Base):
|
||||
__tablename__ = 'authorities'
|
||||
|
||||
@ -19,15 +32,19 @@ class Authority(Base):
|
||||
user_key = sa.Column(sa.Text)
|
||||
host_key = sa.Column(sa.Text)
|
||||
|
||||
|
||||
def getAuthority(session, auth_id):
|
||||
return session.query(Authority).get(auth_id)
|
||||
|
||||
|
||||
def getAuthUserKey(auth):
|
||||
return get_secret(auth.user_key)
|
||||
|
||||
|
||||
def getAuthHostKey(auth):
|
||||
return get_secret(auth.host_key)
|
||||
|
||||
|
||||
def createAuthority(session, auth_id):
|
||||
user_key = RSA.generate(2048).exportKey('PEM')
|
||||
user_secret_id = store_secret(user_key)
|
||||
@ -43,6 +60,7 @@ def createAuthority(session, auth_id):
|
||||
raise falcon.HTTPConflict("This certificate authority already exists.")
|
||||
return auth
|
||||
|
||||
|
||||
class UserCert(Base):
|
||||
__tablename__ = 'user_certs'
|
||||
|
||||
@ -51,9 +69,11 @@ class UserCert(Base):
|
||||
auth_id = sa.Column(sa.String(36), sa.ForeignKey('authorities.auth_id'))
|
||||
cert = sa.Column(sa.Text)
|
||||
|
||||
|
||||
def getUserCert(session, user_id, fingerprint):
|
||||
return session.query(UserCert).get([user_id, fingerprint])
|
||||
|
||||
|
||||
def createUserCert(session, user_id, auth_id, pub):
|
||||
# Retrieve the authority's private key and generate the certificate
|
||||
auth = getAuthority(session, auth_id)
|
||||
@ -76,6 +96,7 @@ def createUserCert(session, user_id, auth_id, pub):
|
||||
session.commit()
|
||||
return user
|
||||
|
||||
|
||||
class Token(Base):
|
||||
__tablename__ = 'tokens'
|
||||
|
||||
@ -88,12 +109,13 @@ class Token(Base):
|
||||
date_used = sa.Column(sa.DateTime, default=datetime.min)
|
||||
fingerprint_used = sa.Column(sa.String(36))
|
||||
|
||||
|
||||
def createToken(session, host_id, auth_id, hostname):
|
||||
# Validate the certificate authority
|
||||
auth = getAuthority(session, auth_id)
|
||||
if auth is None:
|
||||
raise falcon.HTTPNotFound(description='No Authority found with that ID')
|
||||
#Check whether a token was already created for this host_id
|
||||
# Check whether a token was already created for this host_id
|
||||
try:
|
||||
token = session.query(Token).filter(Token.host_id == host_id).one()
|
||||
if token is not None:
|
||||
@ -108,6 +130,7 @@ def createToken(session, host_id, auth_id, hostname):
|
||||
session.commit()
|
||||
return token
|
||||
|
||||
|
||||
class HostCert(Base):
|
||||
__tablename__ = 'host_certs'
|
||||
|
||||
@ -119,9 +142,11 @@ class HostCert(Base):
|
||||
cert = sa.Column(sa.Text)
|
||||
hostname = sa.Column(sa.String(36))
|
||||
|
||||
|
||||
def getHostCert(session, host_id, fingerprint):
|
||||
return session.query(HostCert).get([host_id, fingerprint])
|
||||
|
||||
|
||||
def createHostCert(session, token_id, host_id, pub):
|
||||
token = session.query(Token).get(token_id)
|
||||
if token is None:
|
||||
@ -155,7 +180,7 @@ def createHostCert(session, token_id, host_id, pub):
|
||||
fingerprint=fingerprint,
|
||||
auth_id=token.auth_id,
|
||||
token_id=token_id,
|
||||
pubkey = pub,
|
||||
pubkey=pub,
|
||||
cert=cert,
|
||||
hostname=token.hostname)
|
||||
session.add(host)
|
||||
|
@ -1,3 +1,15 @@
|
||||
# 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.
|
||||
|
||||
import os
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
@ -7,7 +19,8 @@ from tatu.db.models import Base
|
||||
|
||||
def get_url():
|
||||
return os.getenv("DATABASE_URL", "sqlite:///development.db")
|
||||
#return os.getenv("DATABASE_URL", "sqlite:///:memory:")
|
||||
# return os.getenv("DATABASE_URL", "sqlite:///:memory:")
|
||||
|
||||
|
||||
class SQLAlchemySessionManager:
|
||||
"""
|
||||
|
@ -1,3 +1,15 @@
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import requests
|
||||
import os
|
||||
@ -8,6 +20,7 @@ import uuid
|
||||
|
||||
server = 'http://172.24.4.1:18322'
|
||||
|
||||
|
||||
def vendordata_request(instance_id, project_id, hostname):
|
||||
return {
|
||||
'instance-id': instance_id,
|
||||
@ -15,6 +28,7 @@ def vendordata_request(instance_id, project_id, hostname):
|
||||
'hostname': hostname
|
||||
}
|
||||
|
||||
|
||||
def host_request(token, host, pub_key):
|
||||
return {
|
||||
'token_id': token,
|
||||
@ -22,6 +36,7 @@ def host_request(token, host, pub_key):
|
||||
'key.pub': pub_key
|
||||
}
|
||||
|
||||
|
||||
def test_host_certificate_generation():
|
||||
project_id = random_uuid()
|
||||
response = requests.post(
|
||||
|
@ -1,3 +1,15 @@
|
||||
# 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 oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging
|
||||
@ -14,15 +26,15 @@ LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
DOMAIN = 'tatu'
|
||||
|
||||
class NotificationEndpoint(object):
|
||||
|
||||
class NotificationEndpoint(object):
|
||||
filter_rule = oslo_messaging.NotificationFilter(
|
||||
publisher_id='^identity.*',
|
||||
event_type='^identity.project.created')
|
||||
|
||||
def __init__(self):
|
||||
self.engine = create_engine(get_url())
|
||||
#Base.metadata.create_all(self.engine)
|
||||
# Base.metadata.create_all(self.engine)
|
||||
self.Session = scoped_session(sessionmaker(self.engine))
|
||||
|
||||
def info(self, ctxt, publisher_id, event_type, payload, metadata):
|
||||
@ -46,6 +58,7 @@ class NotificationEndpoint(object):
|
||||
else:
|
||||
LOG.error("Status update or unknown")
|
||||
|
||||
|
||||
def main():
|
||||
logging.register_options(CONF)
|
||||
extra_log_level_defaults = ['tatu=DEBUG', '__main__=DEBUG']
|
||||
@ -74,5 +87,6 @@ def main():
|
||||
server.stop()
|
||||
server.wait()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
@ -1,4 +1,14 @@
|
||||
# coding=utf-8
|
||||
# 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.
|
||||
import json
|
||||
import falcon
|
||||
from falcon import testing
|
||||
@ -12,15 +22,18 @@ from Crypto.PublicKey import RSA
|
||||
import sshpubkeys
|
||||
import time
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def db():
|
||||
return SQLAlchemySessionManager()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(db):
|
||||
api = create_app(db)
|
||||
return testing.TestClient(api)
|
||||
|
||||
|
||||
token_id = ''
|
||||
|
||||
host_id = random_uuid()
|
||||
@ -36,6 +49,7 @@ user_fingerprint = sshpubkeys.SSHKey(user_pub_key).hash_md5()
|
||||
auth_id = random_uuid()
|
||||
auth_user_pub_key = None
|
||||
|
||||
|
||||
@pytest.mark.dependency()
|
||||
def test_post_authority(client, auth_id=auth_id):
|
||||
body = {
|
||||
@ -48,6 +62,7 @@ def test_post_authority(client, auth_id=auth_id):
|
||||
assert response.status == falcon.HTTP_CREATED
|
||||
assert response.headers['location'] == '/authorities/' + auth_id
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_authority'])
|
||||
def test_post_authority_duplicate(client):
|
||||
body = {
|
||||
@ -59,12 +74,14 @@ def test_post_authority_duplicate(client):
|
||||
)
|
||||
assert response.status == falcon.HTTP_CONFLICT
|
||||
|
||||
|
||||
def test_post_no_body(client):
|
||||
for path in ['/authorities', '/usercerts', '/hosttokens',
|
||||
'/hostcerts', '/novavendordata']:
|
||||
response = client.simulate_post(path)
|
||||
assert response.status == falcon.HTTP_BAD_REQUEST
|
||||
|
||||
|
||||
def test_post_empty_body(client):
|
||||
bodystr = json.dumps({})
|
||||
for path in ['/authorities', '/usercerts', '/hosttokens',
|
||||
@ -72,6 +89,7 @@ def test_post_empty_body(client):
|
||||
response = client.simulate_post(path, body=bodystr)
|
||||
assert response.status == falcon.HTTP_BAD_REQUEST
|
||||
|
||||
|
||||
def test_post_authority_bad_uuid(client):
|
||||
body = {
|
||||
'auth_id': 'foobar',
|
||||
@ -82,6 +100,7 @@ def test_post_authority_bad_uuid(client):
|
||||
)
|
||||
assert response.status == falcon.HTTP_BAD_REQUEST
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_authority'])
|
||||
def test_get_authority(client):
|
||||
response = client.simulate_get('/authorities/' + auth_id)
|
||||
@ -95,14 +114,17 @@ def test_get_authority(client):
|
||||
assert 'user_key' not in body
|
||||
assert 'host_key' not in body
|
||||
|
||||
|
||||
def test_get_authority_doesnt_exist(client):
|
||||
response = client.simulate_get('/authorities/' + random_uuid())
|
||||
assert response.status == falcon.HTTP_NOT_FOUND
|
||||
|
||||
|
||||
def test_get_authority_with_bad_uuid(client):
|
||||
response = client.simulate_get('/authorities/foobar')
|
||||
assert response.status == falcon.HTTP_BAD_REQUEST
|
||||
|
||||
|
||||
def user_request(auth=auth_id, user_id=user_id, pub_key=user_pub_key):
|
||||
return {
|
||||
'user_id': user_id,
|
||||
@ -110,6 +132,7 @@ def user_request(auth=auth_id, user_id=user_id, pub_key=user_pub_key):
|
||||
'key.pub': pub_key
|
||||
}
|
||||
|
||||
|
||||
def test_post_user_bad_uuid(client):
|
||||
for key in ['user_id', 'auth_id']:
|
||||
body = user_request()
|
||||
@ -120,6 +143,7 @@ def test_post_user_bad_uuid(client):
|
||||
)
|
||||
assert response.status == falcon.HTTP_BAD_REQUEST
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_authority'])
|
||||
def test_post_user(client):
|
||||
body = user_request()
|
||||
@ -134,6 +158,7 @@ def test_post_user(client):
|
||||
assert location[2] == body['user_id']
|
||||
assert location[3] == sshpubkeys.SSHKey(body['key.pub']).hash_md5()
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_user'])
|
||||
def test_get_user(client):
|
||||
response = client.simulate_get('/usercerts/' + user_id + '/' + user_fingerprint)
|
||||
@ -145,14 +170,17 @@ def test_get_user(client):
|
||||
assert 'key-cert.pub' in body
|
||||
assert body['auth_id'] == auth_id
|
||||
|
||||
|
||||
def test_get_user_doesnt_exist(client):
|
||||
response = client.simulate_get('/usercerts/' + random_uuid() + '/' + user_fingerprint)
|
||||
assert response.status == falcon.HTTP_NOT_FOUND
|
||||
|
||||
|
||||
def test_get_user_with_bad_uuid(client):
|
||||
response = client.simulate_get('/usercerts/foobar/' + user_fingerprint)
|
||||
assert response.status == falcon.HTTP_BAD_REQUEST
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_user'])
|
||||
def test_post_second_cert_same_user(client):
|
||||
key = RSA.generate(2048)
|
||||
@ -169,6 +197,7 @@ def test_post_second_cert_same_user(client):
|
||||
assert location[2] == user_id
|
||||
assert location[3] == sshpubkeys.SSHKey(pub_key).hash_md5()
|
||||
|
||||
|
||||
def test_post_user_unknown_auth(client):
|
||||
body = user_request(auth=random_uuid())
|
||||
response = client.simulate_post(
|
||||
@ -177,10 +206,12 @@ 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_and_key_returns_same_result(client):
|
||||
test_post_user(client)
|
||||
|
||||
|
||||
def token_request(auth=auth_id, host=host_id):
|
||||
return {
|
||||
'host_id': host,
|
||||
@ -188,6 +219,7 @@ def token_request(auth=auth_id, host=host_id):
|
||||
'hostname': 'testname.local'
|
||||
}
|
||||
|
||||
|
||||
def host_request(token, host=host_id, pub_key=host_pub_key):
|
||||
return {
|
||||
'token_id': token,
|
||||
@ -195,6 +227,7 @@ def host_request(token, host=host_id, pub_key=host_pub_key):
|
||||
'key.pub': pub_key
|
||||
}
|
||||
|
||||
|
||||
def vendordata_request(auth, host):
|
||||
return {
|
||||
'instance-id': host,
|
||||
@ -202,6 +235,7 @@ def vendordata_request(auth, host):
|
||||
'hostname': 'mytest.testing'
|
||||
}
|
||||
|
||||
|
||||
def test_post_vendordata_bad_uuid(client):
|
||||
for key in ['instance-id', 'project-id']:
|
||||
body = vendordata_request(auth_id, host_id)
|
||||
@ -212,6 +246,7 @@ def test_post_vendordata_bad_uuid(client):
|
||||
)
|
||||
assert response.status == falcon.HTTP_BAD_REQUEST
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_authority'])
|
||||
def test_post_novavendordata(client):
|
||||
req = vendordata_request(auth_id, random_uuid())
|
||||
@ -231,6 +266,7 @@ def test_post_novavendordata(client):
|
||||
assert 'principals' in vendordata
|
||||
assert vendordata['principals'] == 'admin'
|
||||
|
||||
|
||||
def test_post_token_bad_uuid(client):
|
||||
for key in ['auth_id', 'host_id']:
|
||||
body = token_request()
|
||||
@ -241,6 +277,7 @@ def test_post_token_bad_uuid(client):
|
||||
)
|
||||
assert response.status == falcon.HTTP_BAD_REQUEST
|
||||
|
||||
|
||||
def test_post_host_bad_uuid(client):
|
||||
for key in ['token_id', 'host_id']:
|
||||
body = host_request(random_uuid())
|
||||
@ -251,6 +288,7 @@ def test_post_host_bad_uuid(client):
|
||||
)
|
||||
assert response.status == falcon.HTTP_BAD_REQUEST
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_authority'])
|
||||
def test_post_token_and_host(client):
|
||||
token = token_request()
|
||||
@ -327,6 +365,7 @@ def test_stress_post_token_and_host(client):
|
||||
assert location[3] == fingerprint
|
||||
assert time.time() - start < 5
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_token_and_host'])
|
||||
def test_post_token_same_host_id(client):
|
||||
# Posting with the same host ID should return the same token
|
||||
@ -342,6 +381,7 @@ def test_post_token_same_host_id(client):
|
||||
# The token id should be the same as that from the previous test.
|
||||
assert token_id == location_path[-1]
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_token_and_host'])
|
||||
def test_get_host(client):
|
||||
response = client.simulate_get('/hostcerts/' + host_id + '/' + host_fingerprint)
|
||||
@ -355,14 +395,17 @@ def test_get_host(client):
|
||||
assert body['fingerprint'] == host_fingerprint
|
||||
assert body['auth_id'] == auth_id
|
||||
|
||||
|
||||
def test_get_host_doesnt_exist(client):
|
||||
response = client.simulate_get('/hostcerts/' + random_uuid() + '/' + host_fingerprint)
|
||||
assert response.status == falcon.HTTP_NOT_FOUND
|
||||
|
||||
|
||||
def test_get_host_with_bad_uuid(client):
|
||||
response = client.simulate_get('/hostcerts/foobar/' + host_fingerprint)
|
||||
assert response.status == falcon.HTTP_BAD_REQUEST
|
||||
|
||||
|
||||
def test_post_token_unknown_auth(client):
|
||||
token = token_request(auth=random_uuid())
|
||||
response = client.simulate_post(
|
||||
@ -371,6 +414,7 @@ def test_post_token_unknown_auth(client):
|
||||
)
|
||||
assert response.status == falcon.HTTP_NOT_FOUND
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_authority'])
|
||||
def test_post_host_with_bogus_token(client):
|
||||
host = host_request(random_uuid(), random_uuid())
|
||||
@ -380,6 +424,7 @@ def test_post_host_with_bogus_token(client):
|
||||
)
|
||||
assert response.status == falcon.HTTP_NOT_FOUND
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_token_and_host'])
|
||||
def test_post_host_with_wrong_host_id(client):
|
||||
# Get a new token for the same host_id as the base test.
|
||||
@ -403,6 +448,7 @@ def test_post_host_with_wrong_host_id(client):
|
||||
)
|
||||
assert response.status == falcon.HTTP_CONFLICT
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_token_and_host'])
|
||||
def test_post_host_different_public_key_fails(client):
|
||||
# Use the same token compared to the test this depends on.
|
||||
@ -425,6 +471,7 @@ def test_post_host_different_public_key_fails(client):
|
||||
)
|
||||
assert response.status == falcon.HTTP_CONFLICT
|
||||
|
||||
|
||||
@pytest.mark.dependency(depends=['test_post_token_and_host'])
|
||||
def test_post_host_with_used_token(client):
|
||||
# Re-use the token from the test this depends on.
|
||||
|
@ -1,10 +1,24 @@
|
||||
# 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.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import uuid
|
||||
|
||||
|
||||
def random_uuid():
|
||||
return str(uuid.uuid4())
|
||||
|
||||
|
||||
def generateCert(auth_key, entity_key, hostname=None, principals='root'):
|
||||
# Temporarily write the authority private key and entity public key to files
|
||||
prefix = uuid.uuid4().hex
|
||||
|
Loading…
Reference in New Issue
Block a user