1# Copyright 2012 United States Government as represented by the
2# Administrator of the National Aeronautics and Space Administration.
3# All Rights Reserved.
4#
5# Copyright 2012 OpenStack Foundation
6# Copyright 2012 Nebula, Inc.
7#
8#    Licensed under the Apache License, Version 2.0 (the "License"); you may
9#    not use this file except in compliance with the License. You may obtain
10#    a copy of the License at
11#
12#         http://www.apache.org/licenses/LICENSE-2.0
13#
14#    Unless required by applicable law or agreed to in writing, software
15#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17#    License for the specific language governing permissions and limitations
18#    under the License.
19
20import collections
21import logging
22from urllib import parse
23
24from django.conf import settings
25from django.utils.translation import ugettext_lazy as _
26
27from keystoneauth1 import session
28from keystoneauth1 import token_endpoint
29from keystoneclient import exceptions as keystone_exceptions
30
31from openstack_auth import backend
32from openstack_auth import utils as auth_utils
33
34from horizon import exceptions
35
36from openstack_dashboard.api import base
37from openstack_dashboard.contrib.developer.profiler import api as profiler
38from openstack_dashboard import policy
39from openstack_dashboard.utils import settings as setting_utils
40
41
42LOG = logging.getLogger(__name__)
43DEFAULT_ROLE = None
44DEFAULT_DOMAIN = settings.OPENSTACK_KEYSTONE_DEFAULT_DOMAIN
45
46
47# Set up our data structure for managing Identity API versions, and
48# add a couple utility methods to it.
49class IdentityAPIVersionManager(base.APIVersionManager):
50    def upgrade_v2_user(self, user):
51        if getattr(user, "project_id", None) is None:
52            user.project_id = getattr(user, "default_project_id",
53                                      getattr(user, "tenantId", None))
54        return user
55
56    def get_project_manager(self, *args, **kwargs):
57        return keystoneclient(*args, **kwargs).projects
58
59
60VERSIONS = IdentityAPIVersionManager(
61    "identity", preferred_version=auth_utils.get_keystone_version())
62
63
64try:
65    # pylint: disable=ungrouped-imports
66    from keystoneclient.v3 import client as keystone_client_v3
67    VERSIONS.load_supported_version(3, {"client": keystone_client_v3})
68except ImportError:
69    pass
70
71
72class Service(base.APIDictWrapper):
73    """Wrapper for a dict based on the service data from keystone."""
74    _attrs = ['id', 'type', 'name']
75
76    def __init__(self, service, region, *args, **kwargs):
77        super().__init__(service, *args, **kwargs)
78        self.public_url = base.get_url_for_service(service, region,
79                                                   'publicURL')
80        self.url = base.get_url_for_service(service, region,
81                                            settings.OPENSTACK_ENDPOINT_TYPE)
82        if self.url:
83            self.host = parse.urlparse(self.url).hostname
84        else:
85            self.host = None
86        self.disabled = None
87        self.region = region
88
89    def __str__(self):
90        if(self.type == "identity"):
91            return _("%(type)s (%(backend)s backend)") \
92                % {"type": self.type, "backend": keystone_backend_name()}
93        return self.type
94
95    def __repr__(self):
96        return "<Service: %s>" % self
97
98
99def _get_endpoint_url(request, endpoint_type, catalog=None):
100    if getattr(request.user, "service_catalog", None):
101        url = base.url_for(request,
102                           service_type='identity',
103                           endpoint_type=endpoint_type)
104        message = ("The Keystone URL in service catalog points to a v2.0 "
105                   "Keystone endpoint, but v3 is specified as the API version "
106                   "to use by Horizon. Using v3 endpoint for authentication.")
107    else:
108        auth_url = settings.OPENSTACK_KEYSTONE_URL
109        url = request.session.get('region_endpoint', auth_url)
110        message = ("The OPENSTACK_KEYSTONE_URL setting points to a v2.0 "
111                   "Keystone endpoint, but v3 is specified as the API version "
112                   "to use by Horizon. Using v3 endpoint for authentication.")
113
114    # TODO(gabriel): When the Service Catalog no longer contains API versions
115    # in the endpoints this can be removed.
116    url, url_fixed = auth_utils.fix_auth_url_version_prefix(url)
117    if url_fixed:
118        LOG.warning(message)
119
120    return url
121
122
123def keystoneclient(request, admin=False):
124    """Returns a client connected to the Keystone backend.
125
126    Several forms of authentication are supported:
127
128        * Username + password -> Unscoped authentication
129        * Username + password + tenant id -> Scoped authentication
130        * Unscoped token -> Unscoped authentication
131        * Unscoped token + tenant id -> Scoped authentication
132        * Scoped token -> Scoped authentication
133
134    Available services and data from the backend will vary depending on
135    whether the authentication was scoped or unscoped.
136
137    Lazy authentication if an ``endpoint`` parameter is provided.
138
139    Calls requiring the admin endpoint should have ``admin=True`` passed in
140    as a keyword argument.
141
142    The client is cached so that subsequent API calls during the same
143    request/response cycle don't have to be re-authenticated.
144    """
145    client_version = VERSIONS.get_active_version()
146    user = request.user
147    token_id = user.token.id
148
149    if settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT:
150        is_domain_context_specified = bool(
151            request.session.get("domain_context"))
152
153        # If user is Cloud Admin, Domain Admin or Mixed Domain Admin and there
154        # is no domain context specified, use domain scoped token
155        if is_domain_admin(request) and not is_domain_context_specified:
156            domain_token = request.session.get('domain_token')
157            if domain_token:
158                token_id = getattr(domain_token, 'auth_token', None)
159
160    if admin:
161        if not policy.check((("identity", "admin_required"),), request):
162            raise exceptions.NotAuthorized
163        endpoint_type = 'adminURL'
164    else:
165        endpoint_type = settings.OPENSTACK_ENDPOINT_TYPE
166
167    # Take care of client connection caching/fetching a new client.
168    # Admin vs. non-admin clients are cached separately for token matching.
169    cache_attr = "_keystoneclient_admin" if admin \
170        else backend.KEYSTONE_CLIENT_ATTR
171    if (hasattr(request, cache_attr) and
172        (not user.token.id or
173         getattr(request, cache_attr).auth_token == user.token.id)):
174        conn = getattr(request, cache_attr)
175    else:
176        endpoint = _get_endpoint_url(request, endpoint_type)
177        verify = not settings.OPENSTACK_SSL_NO_VERIFY
178        cacert = settings.OPENSTACK_SSL_CACERT
179        verify = verify and cacert
180        LOG.debug("Creating a new keystoneclient connection to %s.", endpoint)
181        remote_addr = request.environ.get('REMOTE_ADDR', '')
182        token_auth = token_endpoint.Token(endpoint=endpoint,
183                                          token=token_id)
184        keystone_session = session.Session(auth=token_auth,
185                                           original_ip=remote_addr,
186                                           verify=verify)
187        conn = client_version['client'].Client(session=keystone_session,
188                                               debug=settings.DEBUG)
189        setattr(request, cache_attr, conn)
190    return conn
191
192
193@profiler.trace
194def get_identity_api_version(request):
195    client = keystoneclient(request)
196    endpoint_data = client.session.get_endpoint_data(service_type='identity')
197    return endpoint_data.api_version
198
199
200@profiler.trace
201def domain_create(request, name, description=None, enabled=None):
202    manager = keystoneclient(request, admin=True).domains
203    return manager.create(name=name,
204                          description=description,
205                          enabled=enabled)
206
207
208@profiler.trace
209def domain_get(request, domain_id):
210    manager = keystoneclient(request, admin=True).domains
211    return manager.get(domain_id)
212
213
214@profiler.trace
215def domain_delete(request, domain_id):
216    manager = keystoneclient(request, admin=True).domains
217    manager.delete(domain_id)
218
219
220@profiler.trace
221def domain_list(request):
222    manager = keystoneclient(request, admin=True).domains
223    return manager.list()
224
225
226def domain_lookup(request):
227    if policy.check((("identity", "identity:list_domains"),), request) \
228            and request.session.get('domain_token'):
229        try:
230            domains = domain_list(request)
231            return dict((d.id, d.name) for d in domains)
232        except Exception:
233            LOG.warning("Pure project admin doesn't have a domain token")
234            return {}
235    else:
236        domain = get_default_domain(request)
237        return {domain.id: domain.name}
238
239
240@profiler.trace
241def domain_update(request, domain_id, name=None, description=None,
242                  enabled=None):
243    manager = keystoneclient(request, admin=True).domains
244    try:
245        response = manager.update(domain_id, name=name,
246                                  description=description, enabled=enabled)
247    except Exception:
248        LOG.exception("Unable to update Domain: %s", domain_id)
249        raise
250    return response
251
252
253@profiler.trace
254def tenant_create(request, name, description=None, enabled=None,
255                  domain=None, **kwargs):
256    manager = VERSIONS.get_project_manager(request, admin=True)
257    try:
258        return manager.create(name, domain,
259                              description=description,
260                              enabled=enabled, **kwargs)
261    except keystone_exceptions.Conflict:
262        raise exceptions.Conflict()
263
264
265def get_default_domain(request, get_name=True):
266    """Gets the default domain object to use when creating Identity object.
267
268    Returns the domain context if is set, otherwise return the domain
269    of the logon user.
270
271    :param get_name: Whether to get the domain name from Keystone if the
272        context isn't set.  Setting this to False prevents an unnecessary call
273        to Keystone if only the domain ID is needed.
274    """
275    domain_id = request.session.get("domain_context", None)
276    domain_name = request.session.get("domain_context_name", None)
277    if domain_id is None:
278        # if no domain context set, default to user's domain
279        domain_id = request.user.user_domain_id
280        domain_name = request.user.user_domain_name
281        if get_name and not request.user.is_federated:
282            try:
283                domain = domain_get(request, domain_id)
284                domain_name = domain.name
285            except exceptions.NotAuthorized:
286                # NOTE (knasim-wrs): Retrieving domain information
287                # is an admin URL operation. As a pre-check, such
288                # operations would be Forbidden if the logon user does
289                # not have an 'admin' role on the current project.
290                #
291                # Since this can be a common occurence and can cause
292                # incessant warning logging in the horizon logs,
293                # we recognize this condition and return the user's
294                # domain information instead.
295                LOG.debug("Cannot retrieve domain information for "
296                          "user (%(user)s) that does not have an admin role "
297                          "on project (%(project)s)",
298                          {'user': request.user.username,
299                           'project': request.user.project_name})
300            except Exception:
301                LOG.warning("Unable to retrieve Domain: %s", domain_id)
302    domain = base.APIDictWrapper({"id": domain_id,
303                                  "name": domain_name})
304    return domain
305
306
307def get_effective_domain_id(request):
308    """Gets the id of the default domain.
309
310    If the requests default domain is the same as DEFAULT_DOMAIN,
311    return None.
312    """
313    default_domain = get_default_domain(request)
314    domain_id = default_domain.get('id')
315    domain_name = default_domain.get('name')
316    return None if domain_name == DEFAULT_DOMAIN else domain_id
317
318
319def is_cloud_admin(request):
320    return policy.check((("identity", "cloud_admin"),), request)
321
322
323def is_domain_admin(request):
324    return policy.check(
325        (("identity", "admin_and_matching_domain_id"),), request)
326
327
328# TODO(gabriel): Is there ever a valid case for admin to be false here?
329# A quick search through the codebase reveals that it's always called with
330# admin=true so I suspect we could eliminate it entirely as with the other
331# tenant commands.
332@profiler.trace
333def tenant_get(request, project, admin=True):
334    manager = VERSIONS.get_project_manager(request, admin=admin)
335    try:
336        return manager.get(project)
337    except keystone_exceptions.NotFound:
338        LOG.info("Tenant '%s' not found.", project)
339        raise
340
341
342@profiler.trace
343def tenant_delete(request, project):
344    manager = VERSIONS.get_project_manager(request, admin=True)
345    manager.delete(project)
346
347
348@profiler.trace
349def tenant_list(request, paginate=False, marker=None, domain=None, user=None,
350                admin=True, filters=None):
351    manager = VERSIONS.get_project_manager(request, admin=admin)
352    tenants = []
353    has_more_data = False
354
355    # if requesting the projects for the current user,
356    # return the list from the cache
357    if user == request.user.id:
358        tenants = request.user.authorized_tenants
359    else:
360        domain_id = get_effective_domain_id(request)
361        kwargs = {
362            "domain": domain_id,
363            "user": user
364        }
365        if filters is not None:
366            kwargs.update(filters)
367        if 'id' in kwargs:
368            try:
369                tenants = [tenant_get(request, kwargs['id'])]
370            except keystone_exceptions.NotFound:
371                tenants = []
372            except Exception:
373                exceptions.handle(request)
374        else:
375            tenants = manager.list(**kwargs)
376    return tenants, has_more_data
377
378
379@profiler.trace
380def tenant_update(request, project, name=None, description=None,
381                  enabled=None, domain=None, **kwargs):
382    manager = VERSIONS.get_project_manager(request, admin=True)
383    try:
384        return manager.update(project, name=name, description=description,
385                              enabled=enabled, domain=domain, **kwargs)
386    except keystone_exceptions.Conflict:
387        raise exceptions.Conflict()
388
389
390@profiler.trace
391def user_list(request, project=None, domain=None, group=None, filters=None):
392    users = []
393    kwargs = {
394        "project": project,
395        "domain": domain,
396        "group": group
397    }
398    if filters is not None:
399        kwargs.update(filters)
400    if 'id' in kwargs:
401        try:
402            users = [user_get(request, kwargs['id'])]
403        except keystone_exceptions.NotFound:
404            raise exceptions.NotFound()
405    else:
406        users = keystoneclient(request, admin=True).users.list(**kwargs)
407    return [VERSIONS.upgrade_v2_user(user) for user in users]
408
409
410@profiler.trace
411def user_create(request, name=None, email=None, password=None, project=None,
412                enabled=None, domain=None, description=None, **data):
413    manager = keystoneclient(request, admin=True).users
414    try:
415        return manager.create(name, password=password, email=email,
416                              default_project=project, enabled=enabled,
417                              domain=domain, description=description,
418                              **data)
419    except keystone_exceptions.Conflict:
420        raise exceptions.Conflict()
421
422
423@profiler.trace
424def user_delete(request, user_id):
425    keystoneclient(request, admin=True).users.delete(user_id)
426
427
428@profiler.trace
429def user_get(request, user_id, admin=True):
430    user = keystoneclient(request, admin=admin).users.get(user_id)
431    return VERSIONS.upgrade_v2_user(user)
432
433
434@profiler.trace
435def user_update(request, user, **data):
436    manager = keystoneclient(request, admin=True).users
437
438    if not keystone_can_edit_user():
439        raise keystone_exceptions.ClientException(
440            _("Identity service does not allow editing user data."))
441    try:
442        user = manager.update(user, **data)
443    except keystone_exceptions.Conflict:
444        raise exceptions.Conflict()
445
446
447@profiler.trace
448def user_update_enabled(request, user, enabled):
449    manager = keystoneclient(request, admin=True).users
450    manager.update(user, enabled=enabled)
451
452
453@profiler.trace
454def user_update_password(request, user, password, admin=True):
455
456    if not keystone_can_edit_user():
457        raise keystone_exceptions.ClientException(
458            _("Identity service does not allow editing user password."))
459
460    manager = keystoneclient(request, admin=admin).users
461    manager.update(user, password=password)
462
463
464def user_verify_admin_password(request, admin_password):
465    # attempt to create a new client instance with admin password to
466    # verify if it's correct.
467    client = keystone_client_v3
468    try:
469        endpoint = _get_endpoint_url(request, 'publicURL')
470        insecure = settings.OPENSTACK_SSL_NO_VERIFY
471        cacert = settings.OPENSTACK_SSL_CACERT
472        client.Client(
473            username=request.user.username,
474            password=admin_password,
475            insecure=insecure,
476            cacert=cacert,
477            auth_url=endpoint
478        )
479        return True
480    except Exception:
481        exceptions.handle(request, ignore=True)
482        return False
483
484
485@profiler.trace
486def user_update_own_password(request, origpassword, password):
487    client = keystoneclient(request, admin=False)
488    client.users.client.session.auth.user_id = request.user.id
489    return client.users.update_password(origpassword, password)
490
491
492@profiler.trace
493def user_update_tenant(request, user, project, admin=True):
494    manager = keystoneclient(request, admin=admin).users
495    return manager.update(user, project=project)
496
497
498@profiler.trace
499def group_create(request, domain_id, name, description=None):
500    manager = keystoneclient(request, admin=True).groups
501    try:
502        return manager.create(domain=domain_id,
503                              name=name,
504                              description=description)
505    except keystone_exceptions.Conflict:
506        raise exceptions.Conflict()
507
508
509@profiler.trace
510def group_get(request, group_id, admin=True):
511    manager = keystoneclient(request, admin=admin).groups
512    return manager.get(group_id)
513
514
515@profiler.trace
516def group_delete(request, group_id):
517    manager = keystoneclient(request, admin=True).groups
518    return manager.delete(group_id)
519
520
521@profiler.trace
522def group_list(request, domain=None, project=None, user=None, filters=None):
523    manager = keystoneclient(request, admin=True).groups
524    groups = []
525    kwargs = {
526        "domain": domain,
527        "user": user,
528        "name": None
529    }
530    if filters is not None:
531        kwargs.update(filters)
532    if 'id' in kwargs:
533        try:
534            groups = [manager.get(kwargs['id'])]
535        except keystone_exceptions.NotFound:
536            raise exceptions.NotFound()
537    else:
538        groups = manager.list(**kwargs)
539
540    if project:
541        project_groups = []
542        for group in groups:
543            roles = roles_for_group(request, group=group.id, project=project)
544            if roles:
545                project_groups.append(group)
546        groups = project_groups
547    return groups
548
549
550@profiler.trace
551def group_update(request, group_id, name=None, description=None):
552    manager = keystoneclient(request, admin=True).groups
553    try:
554        return manager.update(group=group_id,
555                              name=name,
556                              description=description)
557    except keystone_exceptions.Conflict:
558        raise exceptions.Conflict()
559
560
561@profiler.trace
562def add_group_user(request, group_id, user_id):
563    manager = keystoneclient(request, admin=True).users
564    return manager.add_to_group(group=group_id, user=user_id)
565
566
567@profiler.trace
568def remove_group_user(request, group_id, user_id):
569    manager = keystoneclient(request, admin=True).users
570    return manager.remove_from_group(group=group_id, user=user_id)
571
572
573def get_project_groups_roles(request, project):
574    """Gets the groups roles in a given project.
575
576    :param request: the request entity containing the login user information
577    :param project: the project to filter the groups roles. It accepts both
578                    project object resource or project ID
579
580    :returns group_roles: a dictionary mapping the groups and their roles in
581                          given project
582
583    """
584    groups_roles = collections.defaultdict(list)
585    project_role_assignments = role_assignments_list(request,
586                                                     project=project)
587
588    for role_assignment in project_role_assignments:
589        if not hasattr(role_assignment, 'group'):
590            continue
591        group_id = role_assignment.group['id']
592        role_id = role_assignment.role['id']
593
594        # filter by project_id
595        if ('project' in role_assignment.scope and
596                role_assignment.scope['project']['id'] == project):
597            groups_roles[group_id].append(role_id)
598    return groups_roles
599
600
601@profiler.trace
602def role_assignments_list(request, project=None, user=None, role=None,
603                          group=None, domain=None, effective=False,
604                          include_subtree=True, include_names=False):
605    if include_subtree:
606        domain = None
607
608    manager = keystoneclient(request, admin=True).role_assignments
609
610    return manager.list(project=project, user=user, role=role, group=group,
611                        domain=domain, effective=effective,
612                        include_subtree=include_subtree,
613                        include_names=include_names)
614
615
616@profiler.trace
617def role_create(request, name):
618    manager = keystoneclient(request, admin=True).roles
619    return manager.create(name)
620
621
622@profiler.trace
623def role_get(request, role_id):
624    manager = keystoneclient(request, admin=True).roles
625    return manager.get(role_id)
626
627
628@profiler.trace
629def role_update(request, role_id, name=None):
630    manager = keystoneclient(request, admin=True).roles
631    return manager.update(role_id, name)
632
633
634@profiler.trace
635def role_delete(request, role_id):
636    manager = keystoneclient(request, admin=True).roles
637    manager.delete(role_id)
638
639
640@profiler.trace
641def role_list(request, filters=None):
642    """Returns a global list of available roles."""
643    manager = keystoneclient(request, admin=True).roles
644    roles = []
645    kwargs = {}
646    if filters is not None:
647        kwargs.update(filters)
648    if 'id' in kwargs:
649        try:
650            roles = [manager.get(kwargs['id'])]
651        except keystone_exceptions.NotFound:
652            roles = []
653        except Exception:
654            exceptions.handle(request)
655    else:
656        roles = manager.list(**kwargs)
657    return roles
658
659
660@profiler.trace
661def roles_for_user(request, user, project=None, domain=None):
662    """Returns a list of user roles scoped to a project or domain."""
663    manager = keystoneclient(request, admin=True).roles
664    return manager.list(user=user, domain=domain, project=project)
665
666
667@profiler.trace
668def get_domain_users_roles(request, domain):
669    users_roles = collections.defaultdict(list)
670    domain_role_assignments = role_assignments_list(request,
671                                                    domain=domain,
672                                                    include_subtree=False)
673    for role_assignment in domain_role_assignments:
674        if not hasattr(role_assignment, 'user'):
675            continue
676        user_id = role_assignment.user['id']
677        role_id = role_assignment.role['id']
678
679        # filter by domain_id
680        if ('domain' in role_assignment.scope and
681                role_assignment.scope['domain']['id'] == domain):
682            users_roles[user_id].append(role_id)
683    return users_roles
684
685
686@profiler.trace
687def add_domain_user_role(request, user, role, domain):
688    """Adds a role for a user on a domain."""
689    manager = keystoneclient(request, admin=True).roles
690    return manager.grant(role, user=user, domain=domain)
691
692
693@profiler.trace
694def remove_domain_user_role(request, user, role, domain=None):
695    """Removes a given single role for a user from a domain."""
696    manager = keystoneclient(request, admin=True).roles
697    return manager.revoke(role, user=user, domain=domain)
698
699
700@profiler.trace
701def get_project_users_roles(request, project):
702    users_roles = collections.defaultdict(list)
703    project_role_assignments = role_assignments_list(request,
704                                                     project=project)
705    for role_assignment in project_role_assignments:
706        if not hasattr(role_assignment, 'user'):
707            continue
708        user_id = role_assignment.user['id']
709        role_id = role_assignment.role['id']
710
711        # filter by project_id
712        if ('project' in role_assignment.scope and
713                role_assignment.scope['project']['id'] == project):
714            users_roles[user_id].append(role_id)
715    return users_roles
716
717
718@profiler.trace
719def add_tenant_user_role(request, project=None, user=None, role=None,
720                         group=None, domain=None):
721    """Adds a role for a user on a tenant."""
722    manager = keystoneclient(request, admin=True).roles
723    manager.grant(role, user=user, project=project,
724                  group=group, domain=domain)
725
726
727@profiler.trace
728def remove_tenant_user_role(request, project=None, user=None, role=None,
729                            group=None, domain=None):
730    """Removes a given single role for a user from a tenant."""
731    manager = keystoneclient(request, admin=True).roles
732    return manager.revoke(role, user=user, project=project,
733                          group=group, domain=domain)
734
735
736def remove_tenant_user(request, project=None, user=None, domain=None):
737    """Removes all roles from a user on a tenant, removing them from it."""
738    client = keystoneclient(request, admin=True)
739    roles = client.roles.roles_for_user(user, project)
740    for role in roles:
741        remove_tenant_user_role(request, user=user, role=role.id,
742                                project=project, domain=domain)
743
744
745@profiler.trace
746def roles_for_group(request, group, domain=None, project=None):
747    manager = keystoneclient(request, admin=True).roles
748    return manager.list(group=group, domain=domain, project=project)
749
750
751@profiler.trace
752def add_group_role(request, role, group, domain=None, project=None):
753    """Adds a role for a group on a domain or project."""
754    manager = keystoneclient(request, admin=True).roles
755    return manager.grant(role=role, group=group, domain=domain,
756                         project=project)
757
758
759@profiler.trace
760def remove_group_role(request, role, group, domain=None, project=None):
761    """Removes a given single role for a group from a domain or project."""
762    manager = keystoneclient(request, admin=True).roles
763    return manager.revoke(role=role, group=group, project=project,
764                          domain=domain)
765
766
767@profiler.trace
768def remove_group_roles(request, group, domain=None, project=None):
769    """Removes all roles from a group on a domain or project."""
770    client = keystoneclient(request, admin=True)
771    roles = client.roles.list(group=group, domain=domain, project=project)
772    for role in roles:
773        remove_group_role(request, role=role.id, group=group,
774                          domain=domain, project=project)
775
776
777def get_default_role(request):
778    """Gets the default role object from Keystone and saves it as a global.
779
780    Since this is configured in settings and should not change from request
781    to request. Supports lookup by name or id.
782    """
783    global DEFAULT_ROLE
784    default = settings.OPENSTACK_KEYSTONE_DEFAULT_ROLE
785    if default and DEFAULT_ROLE is None:
786        try:
787            roles = keystoneclient(request, admin=True).roles.list()
788        except Exception:
789            roles = []
790            exceptions.handle(request)
791        for role in roles:
792            if default in (role.id, role.name):
793                DEFAULT_ROLE = role
794                break
795    return DEFAULT_ROLE
796
797
798def ec2_manager(request):
799    client = keystoneclient(request)
800    if hasattr(client, 'ec2'):
801        return client.ec2
802
803    from keystoneclient.v3 import ec2
804    return ec2.EC2Manager(client)
805
806
807@profiler.trace
808def list_ec2_credentials(request, user_id):
809    return ec2_manager(request).list(user_id)
810
811
812@profiler.trace
813def create_ec2_credentials(request, user_id, tenant_id):
814    return ec2_manager(request).create(user_id, tenant_id)
815
816
817@profiler.trace
818def get_user_ec2_credentials(request, user_id, access_token):
819    return ec2_manager(request).get(user_id, access_token)
820
821
822@profiler.trace
823def delete_user_ec2_credentials(request, user_id, access_token):
824    return ec2_manager(request).delete(user_id, access_token)
825
826
827def keystone_can_edit_domain():
828    can_edit_domain = setting_utils.get_dict_config(
829        'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_domain')
830    multi_domain_support = settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT
831    return can_edit_domain and multi_domain_support
832
833
834def keystone_can_edit_user():
835    return setting_utils.get_dict_config(
836        'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_user')
837
838
839def keystone_can_edit_project():
840    return setting_utils.get_dict_config(
841        'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_project')
842
843
844def keystone_can_edit_group():
845    return setting_utils.get_dict_config(
846        'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_group')
847
848
849def keystone_can_edit_role():
850    return setting_utils.get_dict_config(
851        'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_role')
852
853
854def keystone_backend_name():
855    return setting_utils.get_dict_config(
856        'OPENSTACK_KEYSTONE_BACKEND', 'name') or 'unknown'
857
858
859def get_version():
860    return VERSIONS.active
861
862
863def identity_provider_create(request, idp_id, description=None,
864                             enabled=False, remote_ids=None):
865    manager = keystoneclient(request, admin=True).federation.identity_providers
866    try:
867        return manager.create(id=idp_id,
868                              description=description,
869                              enabled=enabled,
870                              remote_ids=remote_ids)
871    except keystone_exceptions.Conflict:
872        raise exceptions.Conflict()
873
874
875@profiler.trace
876def identity_provider_get(request, idp_id):
877    manager = keystoneclient(request, admin=True).federation.identity_providers
878    return manager.get(idp_id)
879
880
881@profiler.trace
882def identity_provider_update(request, idp_id, description=None,
883                             enabled=False, remote_ids=None):
884    manager = keystoneclient(request, admin=True).federation.identity_providers
885    try:
886        return manager.update(idp_id,
887                              description=description,
888                              enabled=enabled,
889                              remote_ids=remote_ids)
890    except keystone_exceptions.Conflict:
891        raise exceptions.Conflict()
892
893
894@profiler.trace
895def identity_provider_delete(request, idp_id):
896    manager = keystoneclient(request, admin=True).federation.identity_providers
897    return manager.delete(idp_id)
898
899
900@profiler.trace
901def identity_provider_list(request):
902    manager = keystoneclient(request, admin=True).federation.identity_providers
903    return manager.list()
904
905
906@profiler.trace
907def mapping_create(request, mapping_id, rules):
908    manager = keystoneclient(request, admin=True).federation.mappings
909    try:
910        return manager.create(mapping_id=mapping_id, rules=rules)
911    except keystone_exceptions.Conflict:
912        raise exceptions.Conflict()
913
914
915@profiler.trace
916def mapping_get(request, mapping_id):
917    manager = keystoneclient(request, admin=True).federation.mappings
918    return manager.get(mapping_id)
919
920
921@profiler.trace
922def mapping_update(request, mapping_id, rules):
923    manager = keystoneclient(request, admin=True).federation.mappings
924    return manager.update(mapping_id, rules=rules)
925
926
927@profiler.trace
928def mapping_delete(request, mapping_id):
929    manager = keystoneclient(request, admin=True).federation.mappings
930    return manager.delete(mapping_id)
931
932
933@profiler.trace
934def mapping_list(request):
935    manager = keystoneclient(request, admin=True).federation.mappings
936    return manager.list()
937
938
939@profiler.trace
940def protocol_create(request, protocol_id, identity_provider, mapping):
941    manager = keystoneclient(request).federation.protocols
942    try:
943        return manager.create(protocol_id, identity_provider, mapping)
944    except keystone_exceptions.Conflict:
945        raise exceptions.Conflict()
946
947
948@profiler.trace
949def protocol_get(request, identity_provider, protocol):
950    manager = keystoneclient(request).federation.protocols
951    return manager.get(identity_provider, protocol)
952
953
954@profiler.trace
955def protocol_update(request, identity_provider, protocol, mapping):
956    manager = keystoneclient(request).federation.protocols
957    return manager.update(identity_provider, protocol, mapping)
958
959
960@profiler.trace
961def protocol_delete(request, identity_provider, protocol):
962    manager = keystoneclient(request).federation.protocols
963    return manager.delete(identity_provider, protocol)
964
965
966@profiler.trace
967def protocol_list(request, identity_provider):
968    manager = keystoneclient(request).federation.protocols
969    return manager.list(identity_provider)
970
971
972@profiler.trace
973def application_credential_list(request, filters=None):
974    user = request.user.id
975    manager = keystoneclient(request).application_credentials
976    return manager.list(user=user, **filters)
977
978
979@profiler.trace
980def application_credential_get(request, application_credential_id):
981    user = request.user.id
982    manager = keystoneclient(request).application_credentials
983    return manager.get(application_credential=application_credential_id,
984                       user=user)
985
986
987@profiler.trace
988def application_credential_delete(request, application_credential_id):
989    user = request.user.id
990    manager = keystoneclient(request).application_credentials
991    return manager.delete(application_credential=application_credential_id,
992                          user=user)
993
994
995@profiler.trace
996def application_credential_create(request, name, secret=None,
997                                  description=None, expires_at=None,
998                                  roles=None, unrestricted=False,
999                                  access_rules=None):
1000    user = request.user.id
1001    manager = keystoneclient(request).application_credentials
1002    try:
1003        return manager.create(name=name, user=user, secret=secret,
1004                              description=description, expires_at=expires_at,
1005                              roles=roles, unrestricted=unrestricted,
1006                              access_rules=access_rules)
1007    except keystone_exceptions.Conflict:
1008        raise exceptions.Conflict()
1009