Enforce project ownership of subCAs

The add-to-project and create CA commands can only be performed by
a project administrator when the target CA is either a root CA
or a subCA owned by the admin's project.

This CR adds checks to enforce this condition.

Change-Id: Ifbd7bb471b137a5549a8e627344f8f02adda2ed1
Closes-bug: #1501862
This commit is contained in:
Dave McCowan 2015-10-01 14:13:15 -04:00
parent 4afaee095a
commit 8bbf06caae
5 changed files with 88 additions and 1 deletions

View File

@ -17,6 +17,7 @@ from six.moves.urllib import parse
from barbican import api
from barbican.api import controllers
from barbican.common import exception as excep
from barbican.common import hrefs
from barbican.common import quota
from barbican.common import resources as res
@ -144,6 +145,11 @@ class CertificateAuthorityController(controllers.ACLMixin):
self.ca.id, external_project_id)
project_model = res.get_or_create_project(external_project_id)
# CA must be a base CA or a subCA owned by this project
if (self.ca.project_id is not None and
self.ca.project_id != project_model.id):
raise excep.UnauthorizedSubCA()
project_cas = project_model.cas
num_cas = len(project_cas)
for project_ca in project_cas:

View File

@ -200,7 +200,10 @@ def create_subordinate_ca(project_model, name, description, subject_dn,
if not parent_ca:
raise excep.InvalidParentCA(parent_ca_ref=parent_ca_ref)
# TODO(alee) check if the parent_ca is accessible for this project
# Parent CA must be a base CA or a subCA owned by this project
if (parent_ca.project_id is not None and
parent_ca.project_id != project_model.id):
raise excep.UnauthorizedSubCA()
# get the parent plugin, raises CertPluginNotFound if missing
cert_plugin = cert.CertificatePluginManager().get_plugin_by_name(

View File

@ -257,6 +257,16 @@ class WhenTestingCAsResource(utils.BarbicanAPIBaseTestCase):
'/cas/bogus_ca/add-to-project', expect_errors=True)
self.assertEqual(404, resp.status_int)
def test_should_raise_add_to_project_on_ca_not_owned_by_project(self):
self.create_cas()
self.app.extra_environ = {
'barbican.context': self._build_context("other_project",
user="user1")
}
resp = self.app.post('/cas/{0}/add-to-project'.format(
self.subca.id), expect_errors=True)
self.assertEqual(403, resp.status_int)
def test_should_raise_add_to_project_not_post(self):
self.create_cas()
resp = self.app.get(

View File

@ -908,6 +908,26 @@ class WhenCreatingSubordinateCAs(utils.BaseTestCase):
creator_id=self.creator_id
)
def test_should_raise_unauthorized_parent_ca(self):
subca = cert_res.create_subordinate_ca(
project_model=self.project2,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=self.parent_ca_ref,
creator_id=self.creator_id
)
subca_ref = hrefs.convert_certificate_authority_to_href(subca.id)
self.assertRaises(
excep.UnauthorizedSubCA,
cert_res.create_subordinate_ca,
project_model=self.project,
name=self.name,
description=self.description,
subject_dn=self.subject_name,
parent_ca_ref=subca_ref,
creator_id=self.creator_id)
def test_should_raise_subcas_not_supported(self):
self.cert_plugin.supports_create_ca.return_value = False
self.assertRaises(

View File

@ -252,6 +252,30 @@ class CertificateAuthoritiesTestCase(CATestCommon):
resp = self.ca_behaviors.delete_ca(ca_ref=parent_ref)
self.assertEqual(204, resp.status_code)
@depends_on_ca_plugins('snakeoil_ca')
def test_fail_to_create_subca_of_snakeoil_not_owned_subca(self):
self._fail_to_create_subca_of_not_owned_subca(
self.get_snakeoil_root_ca_ref())
@testtools.skipIf(not dogtag_subcas_enabled, "dogtag subcas not enabled")
@depends_on_ca_plugins('dogtag')
def test_fail_to_create_subca_of_dogtag_not_owned_subca(self):
self._fail_to_create_subca_of_not_owned_subca(
self.get_dogtag_root_ca_ref())
def _fail_to_create_subca_of_not_owned_subca(self, root_ca_ref):
parent_model = self.get_subca_model(root_ca_ref)
resp, parent_ref = self.ca_behaviors.create_ca(parent_model)
self.assertEqual(201, resp.status_code)
child_model = self.get_sub_subca_model(parent_ref)
resp, child_ref = self.ca_behaviors.create_ca(child_model,
user_name=admin_a)
self.assertEqual(403, resp.status_code)
resp = self.ca_behaviors.delete_ca(ca_ref=parent_ref)
self.assertEqual(204, resp.status_code)
def test_create_subca_with_invalid_parent_ca_id(self):
ca_model = self.get_subca_model(
'http://localhost:9311/cas/invalid_ref'
@ -332,6 +356,30 @@ class CertificateAuthoritiesTestCase(CATestCommon):
resp = self.ca_behaviors.get_preferred(user_name=admin_a)
self.assertEqual(404, resp.status_code)
@depends_on_ca_plugins('snakeoil_ca')
def test_try_and_fail_to_add_to_proj_snakeoil_subca_that_is_not_mine(self):
self._try_and_fail_to_add_to_proj_subca_that_is_not_mine(
self.get_snakeoil_root_ca_ref()
)
@testtools.skipIf(not dogtag_subcas_enabled, "dogtag subcas not enabled")
@depends_on_ca_plugins('dogtag')
def test_try_and_fail_to_add_to_proj_dogtag_subca_that_is_not_mine(self):
self._try_and_fail_to_add_to_proj_subca_that_is_not_mine(
self.get_dogtag_root_ca_ref()
)
def _try_and_fail_to_add_to_proj_subca_that_is_not_mine(self, root_ca_ref):
ca_model = self.get_subca_model(root_ca_ref)
resp, ca_ref = self.ca_behaviors.create_ca(ca_model, user_name=admin_a)
self.assertEqual(201, resp.status_code)
resp = self.ca_behaviors.add_ca_to_project(ca_ref, user_name=admin_b)
self.assertEqual(403, resp.status_code)
resp = self.ca_behaviors.delete_ca(ca_ref=ca_ref, user_name=admin_a)
self.assertEqual(204, resp.status_code)
@depends_on_ca_plugins('snakeoil_ca')
def test_create_and_delete_snakeoil_subca(self):
self._create_and_delete_subca(