Working on secure DB access (part 3)

* Moving method get_project_id() to services/security.py

Change-Id: Id4a166a754c1eda24280e7454530339b43243cb3
This commit is contained in:
Renat Akhmerov 2015-01-19 17:27:19 +06:00
parent 14a7b44bb0
commit 9fcbfbe2f9
11 changed files with 31 additions and 72 deletions

View File

@ -23,7 +23,7 @@ from sqlalchemy import event
from sqlalchemy.ext import declarative from sqlalchemy.ext import declarative
from sqlalchemy.orm import attributes from sqlalchemy.orm import attributes
from mistral.db import v2 as db_base from mistral.services import security
def _generate_unicode_uuid(): def _generate_unicode_uuid():
@ -90,11 +90,11 @@ class MistralSecureModelBase(MistralModelBase):
__abstract__ = True __abstract__ = True
scope = sa.Column(sa.String(80), default='private') scope = sa.Column(sa.String(80), default='private')
project_id = sa.Column(sa.String(80), default=db_base.get_project_id) project_id = sa.Column(sa.String(80), default=security.get_project_id)
def _set_project_id(target, value, oldvalue, initiator): def _set_project_id(target, value, oldvalue, initiator):
return db_base.get_project_id() return security.get_project_id()
def register_secure_model_hooks(): def register_secure_model_hooks():

View File

@ -1,32 +0,0 @@
# Copyright 2014 - Mirantis, Inc.
#
# 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 mistral import context as auth_context
# Make sure to import 'auth_enable' option before using it.
cfg.CONF.import_opt('auth_enable', 'mistral.config', group='pecan')
CONF = cfg.CONF
DEFAULT_PROJECT_ID = "<default-project>"
def get_project_id():
if CONF.pecan.auth_enable and auth_context.has_ctx():
return auth_context.ctx().project_id
else:
return DEFAULT_PROJECT_ID

View File

@ -21,11 +21,10 @@ from oslo.db import exception as db_exc
import sqlalchemy as sa import sqlalchemy as sa
from mistral.db.sqlalchemy import base as b from mistral.db.sqlalchemy import base as b
from mistral.db import v2 as db_base
from mistral.db.v2.sqlalchemy import models from mistral.db.v2.sqlalchemy import models
from mistral import exceptions as exc from mistral import exceptions as exc
from mistral.openstack.common import log as logging from mistral.openstack.common import log as logging
from mistral.services import security
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -94,7 +93,7 @@ def _get_collection_sorted_by_name(model, **kwargs):
query = b.model_query(model) query = b.model_query(model)
proj = query.filter_by( proj = query.filter_by(
project_id=db_base.get_project_id(), project_id=security.get_project_id(),
**kwargs **kwargs
) )
public = query.filter_by(scope='public', **kwargs) public = query.filter_by(scope='public', **kwargs)
@ -106,7 +105,7 @@ def _get_collection_sorted_by_time(model, **kwargs):
query = b.model_query(model) query = b.model_query(model)
return query.filter_by( return query.filter_by(
project_id=db_base.get_project_id(), project_id=security.get_project_id(),
**kwargs **kwargs
).order_by(model.created_at).all() ).order_by(model.created_at).all()
@ -114,7 +113,7 @@ def _get_collection_sorted_by_time(model, **kwargs):
def _get_db_object_by_name(model, name): def _get_db_object_by_name(model, name):
query = b.model_query(model) query = b.model_query(model)
private = query.filter_by(name=name, project_id=db_base.get_project_id()) private = query.filter_by(name=name, project_id=security.get_project_id())
public = query.filter_by(name=name, scope='public') public = query.filter_by(name=name, scope='public')
return private.union(public).first() return private.union(public).first()
@ -123,7 +122,7 @@ def _get_db_object_by_name(model, name):
def _get_db_object_by_id(model, id): def _get_db_object_by_id(model, id):
query = b.model_query(model) query = b.model_query(model)
return query.filter_by(id=id, project_id=db_base.get_project_id()).first() return query.filter_by(id=id, project_id=security.get_project_id()).first()
# Workbooks. # Workbooks.

View File

@ -16,7 +16,6 @@
import copy import copy
from oslo.config import cfg from oslo.config import cfg
from mistral.db import v2 as db_base
from mistral.db.v2 import api as db_api from mistral.db.v2 import api as db_api
from mistral.engine1 import base from mistral.engine1 import base
from mistral.engine1 import commands from mistral.engine1 import commands
@ -194,7 +193,6 @@ class DefaultEngine(base.Engine):
'output': {}, 'output': {},
'context': copy.copy(wf_input) or {}, 'context': copy.copy(wf_input) or {},
'parent_task_id': params.get('parent_task_id'), 'parent_task_id': params.get('parent_task_id'),
'project_id': db_base.get_project_id()
}) })
data_flow.add_openstack_data_to_context(wf_db, exec_db.context) data_flow.add_openstack_data_to_context(wf_db, exec_db.context)

View File

@ -1,4 +1,4 @@
# Copyright 2013 - Mirantis, Inc. # Copyright 2015 - Mirantis, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -14,7 +14,6 @@
from mistral.db.v2 import api as db_api from mistral.db.v2 import api as db_api
from mistral import exceptions as exc from mistral import exceptions as exc
from mistral.services import security
from mistral.workbook import parser as spec_parser from mistral.workbook import parser as spec_parser
@ -80,6 +79,4 @@ def _get_action_values(action_spec, definition, scope):
'scope': scope 'scope': scope
} }
security.add_project_id(values, scope)
return values return values

View File

@ -16,17 +16,31 @@
from oslo.config import cfg from oslo.config import cfg
from mistral import context from mistral import context as auth_ctx
from mistral.utils.openstack import keystone from mistral.utils.openstack import keystone
CONF = cfg.CONF CONF = cfg.CONF
# Make sure to import 'auth_enable' option before using it.
# TODO(rakhmerov): Try to find a better solution.
CONF.import_opt('auth_enable', 'mistral.config', group='pecan')
DEFAULT_PROJECT_ID = "<default-project>"
def get_project_id():
if CONF.pecan.auth_enable and auth_ctx.has_ctx():
return auth_ctx.ctx().project_id
else:
return DEFAULT_PROJECT_ID
def create_trust(): def create_trust():
client = keystone.client() client = keystone.client()
ctx = context.ctx() ctx = auth_ctx.ctx()
trustee_id = keystone.client_for_admin( trustee_id = keystone.client_for_admin(
CONF.keystone_authtoken.admin_tenant_name).user_id CONF.keystone_authtoken.admin_tenant_name).user_id
@ -53,13 +67,13 @@ def create_context(trust_id, project_id):
if CONF.pecan.auth_enable: if CONF.pecan.auth_enable:
client = keystone.client_for_trusts(trust_id) client = keystone.client_for_trusts(trust_id)
return context.MistralContext( return auth_ctx.MistralContext(
user_id=client.user_id, user_id=client.user_id,
project_id=project_id, project_id=project_id,
auth_token=client.auth_token auth_token=client.auth_token
) )
return context.MistralContext( return auth_ctx.MistralContext(
user_id=None, user_id=None,
project_id=None, project_id=None,
auth_token=None, auth_token=None,
@ -75,13 +89,6 @@ def delete_trust(workbook):
keystone_client.trusts.delete(workbook.trust_id) keystone_client.trusts.delete(workbook.trust_id)
def add_project_id(secure_object_values, scope='private'):
if cfg.CONF.pecan.auth_enable and scope == 'private':
secure_object_values.update({
'project_id': context.ctx().project_id
})
def add_trust_id(secure_object_values): def add_trust_id(secure_object_values):
if cfg.CONF.pecan.auth_enable: if cfg.CONF.pecan.auth_enable:
secure_object_values.update({ secure_object_values.update({

View File

@ -17,7 +17,6 @@ import datetime
from mistral.db.v1 import api as db_api_v1 from mistral.db.v1 import api as db_api_v1
from mistral.db.v2 import api as db_api_v2 from mistral.db.v2 import api as db_api_v2
from mistral.services import security
from mistral.workbook import parser as spec_parser from mistral.workbook import parser as spec_parser
@ -100,8 +99,6 @@ def create_cron_trigger(name, pattern, workflow_name, workflow_input,
'scope': 'private' 'scope': 'private'
} }
security.add_project_id(values)
trig = db_api_v2.create_cron_trigger(values) trig = db_api_v2.create_cron_trigger(values)
return trig return trig

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright 2013 - Mirantis, Inc. # Copyright 2015 - Mirantis, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -22,8 +22,6 @@ from mistral.workbook import parser as spec_parser
def create_workbook_v1(values, scope='private'): def create_workbook_v1(values, scope='private'):
security.add_project_id(values, scope)
return db_api_v1.workbook_create(values) return db_api_v1.workbook_create(values)
@ -115,6 +113,4 @@ def _get_workbook_values(wb_spec, definition, scope):
'scope': scope 'scope': scope
} }
security.add_project_id(values, scope)
return values return values

View File

@ -70,7 +70,6 @@ def _get_workflow_values(wf_spec, definition, scope):
'scope': scope 'scope': scope
} }
security.add_project_id(values, scope)
security.add_trust_id(values) security.add_trust_id(values)
return values return values

View File

@ -79,8 +79,6 @@ class TestWorkbooksController(base.FunctionalTest):
@mock.patch.object(db_api, "workbook_create", @mock.patch.object(db_api, "workbook_create",
mock.MagicMock(side_effect=exceptions.DBDuplicateEntry)) mock.MagicMock(side_effect=exceptions.DBDuplicateEntry))
@mock.patch("mistral.services.security.add_project_id",
mock.MagicMock(return_value=None))
def test_post_dup(self): def test_post_dup(self):
resp = self.app.post_json('/v1/workbooks', WORKBOOKS[0], resp = self.app.post_json('/v1/workbooks', WORKBOOKS[0],
expect_errors=True) expect_errors=True)

View File

@ -21,9 +21,9 @@ import datetime
from oslo.config import cfg from oslo.config import cfg
from mistral import context as auth_context from mistral import context as auth_context
from mistral.db import v2 as db_base
from mistral.db.v2.sqlalchemy import api as db_api from mistral.db.v2.sqlalchemy import api as db_api
from mistral import exceptions as exc from mistral import exceptions as exc
from mistral.services import security
from mistral.tests import base as test_base from mistral.tests import base as test_base
@ -335,8 +335,8 @@ class WorkflowTest(SQLAlchemyTest):
fetched0 = db_api.load_workflow(created0.name) fetched0 = db_api.load_workflow(created0.name)
fetched1 = db_api.load_workflow(created1.name) fetched1 = db_api.load_workflow(created1.name)
self.assertEqual(db_base.get_project_id(), fetched0.project_id) self.assertEqual(security.get_project_id(), fetched0.project_id)
self.assertEqual(db_base.get_project_id(), fetched1.project_id) self.assertEqual(security.get_project_id(), fetched1.project_id)
fetched = db_api.get_workflows() fetched = db_api.get_workflows()