VYPR
Unrated severityNVD Advisory· Published Jul 31, 2018· Updated Aug 5, 2024

CVE-2018-14432

CVE-2018-14432

Description

In the Federation component of OpenStack Keystone before 11.0.4, 12.0.0, and 13.0.0, an authenticated "GET /v3/OS-FEDERATION/projects" request may bypass intended access restrictions on listing projects. An authenticated user may discover projects they have no authority to access, leaking all projects in the deployment and their attributes. Only Keystone with the /v3/OS-FEDERATION endpoint enabled via policy.json is affected.

Affected products

179

Patches

1
ade177ad357d

Reduce duplication in federated auth APIs

https://github.com/openstack/keystoneLance BragstadJul 25, 2018via osv
2 files changed · +57 15
  • keystone/federation/controllers.py+4 15 modified
    @@ -447,13 +447,8 @@ def list_domains_for_user(self, request):
             :returns: list of accessible domains
     
             """
    -        domains = self.assignment_api.list_domains_for_groups(
    -            request.auth_context['group_ids'])
    -        domains = domains + self.assignment_api.list_domains_for_user(
    -            request.auth_context['user_id'])
    -        # remove duplicates
    -        domains = [dict(t) for t in set([tuple(d.items()) for d in domains])]
    -        return DomainV3.wrap_collection(request.context_dict, domains)
    +        controller = auth_controllers.Auth()
    +        return controller.get_auth_domains(request)
     
     
     @dependency.requires('assignment_api', 'resource_api')
    @@ -473,14 +468,8 @@ def list_projects_for_user(self, request):
             :returns: list of accessible projects
     
             """
    -        projects = self.assignment_api.list_projects_for_groups(
    -            request.auth_context['group_ids'])
    -        projects = projects + self.assignment_api.list_projects_for_user(
    -            request.auth_context['user_id'])
    -        # remove duplicates
    -        projects = [dict(t) for t in set([tuple(d.items()) for d in projects])]
    -        return ProjectAssignmentV3.wrap_collection(request.context_dict,
    -                                                   projects)
    +        controller = auth_controllers.Auth()
    +        return controller.get_auth_projects(request)
     
     
     @dependency.requires('federation_api')
    
  • keystone/tests/unit/test_v3_auth.py+53 0 modified
    @@ -5090,6 +5090,59 @@ def test_get_domains_project_scoped_token(self):
             self.assertThat(r.json['domains'], matchers.HasLength(1))
             self.assertValidDomainListResponse(r)
     
    +    def test_get_projects_matches_federated_get_projects(self):
    +        # create at least one addition project to make sure it doesn't end up
    +        # in the response, since the user doesn't have any authorization on it
    +        ref = unit.new_project_ref(domain_id=CONF.identity.default_domain_id)
    +        r = self.post('/projects', body={'project': ref})
    +        unauthorized_project_id = r.json['project']['id']
    +
    +        r = self.get('/auth/projects', expected_status=http_client.OK)
    +        self.assertThat(r.json['projects'], matchers.HasLength(1))
    +        for project in r.json['projects']:
    +            self.assertNotEqual(unauthorized_project_id, project['id'])
    +
    +        expected_project_id = r.json['projects'][0]['id']
    +
    +        # call GET /v3/OS-FEDERATION/projects
    +        r = self.get('/OS-FEDERATION/projects', expected_status=http_client.OK)
    +
    +        # make sure the response is the same
    +        self.assertThat(r.json['projects'], matchers.HasLength(1))
    +        for project in r.json['projects']:
    +            self.assertEqual(expected_project_id, project['id'])
    +
    +    def test_get_domains_matches_federated_get_domains(self):
    +        # create at least one addition domain to make sure it doesn't end up
    +        # in the response, since the user doesn't have any authorization on it
    +        ref = unit.new_domain_ref()
    +        r = self.post('/domains', body={'domain': ref})
    +        unauthorized_domain_id = r.json['domain']['id']
    +
    +        ref = unit.new_domain_ref()
    +        r = self.post('/domains', body={'domain': ref})
    +        authorized_domain_id = r.json['domain']['id']
    +
    +        path = '/domains/%(domain_id)s/users/%(user_id)s/roles/%(role_id)s' % {
    +            'domain_id': authorized_domain_id,
    +            'user_id': self.user_id,
    +            'role_id': self.role_id
    +        }
    +        self.put(path, expected_status=http_client.NO_CONTENT)
    +
    +        r = self.get('/auth/domains', expected_status=http_client.OK)
    +        self.assertThat(r.json['domains'], matchers.HasLength(1))
    +        self.assertEqual(authorized_domain_id, r.json['domains'][0]['id'])
    +        self.assertNotEqual(unauthorized_domain_id, r.json['domains'][0]['id'])
    +
    +        # call GET /v3/OS-FEDERATION/domains
    +        r = self.get('/OS-FEDERATION/domains', expected_status=http_client.OK)
    +
    +        # make sure the response is the same
    +        self.assertThat(r.json['domains'], matchers.HasLength(1))
    +        self.assertEqual(authorized_domain_id, r.json['domains'][0]['id'])
    +        self.assertNotEqual(unauthorized_domain_id, r.json['domains'][0]['id'])
    +
     
     class TestTrustAuthFernetTokenProvider(TrustAPIBehavior, TestTrustChain):
         def config_overrides(self):
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.