summaryrefslogtreecommitdiffstats
path: root/keystone/trust
diff options
context:
space:
mode:
authorAdam Young <ayoung@redhat.com>2013-02-26 14:54:32 -0500
committerGerrit Code Review <review@openstack.org>2013-03-05 19:35:38 +0000
commit601eeb50b60a2e99041690fe19238202bc203503 (patch)
treef1be4ab425ba9150b61c1e1c6c5bd1a67f180021 /keystone/trust
parentab6e5529513af656db512b888fed9b320391afbd (diff)
downloadkeystone-601eeb50b60a2e99041690fe19238202bc203503.tar.gz
keystone-601eeb50b60a2e99041690fe19238202bc203503.tar.xz
keystone-601eeb50b60a2e99041690fe19238202bc203503.zip
Trusts
Blueprint trusts creates a trust. Using a trust, one user (the trustee), can then create tokens with a subset of another user's (the trustor) roles and projects. If the impersonate flag in the trust is set, the token user_id is set to the trustor's user ID If the impersonate flag is not set, the token's user_is is set to the trustee's user ID check that both trustor and trustee are enabled prior to creating the trust token. sql and kvs backends sql upgrade scripts unit tests for backends, auth and v3 api modifications to the trust controller for creating tokens Authenticates that only user can be trustor in create Deleting a trust invalidates all tokens created from that trust Adds the trust id and the id of the trustee to the header of the token policy rules for trust This version has a workaround for testing against the KVS version of the Service catalog Change-Id: I5745f4d9a4180b59671a143a55ed87019e98ec76
Diffstat (limited to 'keystone/trust')
-rw-r--r--keystone/trust/__init__.py19
-rw-r--r--keystone/trust/backends/__init__.py0
-rw-r--r--keystone/trust/backends/kvs.py92
-rw-r--r--keystone/trust/backends/sql.py123
-rw-r--r--keystone/trust/controllers.py244
-rw-r--r--keystone/trust/core.py63
-rw-r--r--keystone/trust/routers.py58
7 files changed, 599 insertions, 0 deletions
diff --git a/keystone/trust/__init__.py b/keystone/trust/__init__.py
new file mode 100644
index 00000000..9c6a22f0
--- /dev/null
+++ b/keystone/trust/__init__.py
@@ -0,0 +1,19 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC
+#
+# 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 keystone.trust.core import Manager, Driver
+from keystone.trust import controllers
+from keystone.trust import routers
diff --git a/keystone/trust/backends/__init__.py b/keystone/trust/backends/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/keystone/trust/backends/__init__.py
diff --git a/keystone/trust/backends/kvs.py b/keystone/trust/backends/kvs.py
new file mode 100644
index 00000000..ef528626
--- /dev/null
+++ b/keystone/trust/backends/kvs.py
@@ -0,0 +1,92 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC
+#
+# 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.
+"""
+An in memory implementation of the trusts API.
+only to be used for testing purposes
+"""
+import copy
+import datetime
+
+
+from keystone.common import kvs
+from keystone.openstack.common import timeutils
+from keystone import exception
+from keystone import trust
+
+
+class Trust(kvs.Base, trust.Driver):
+ def create_trust(self, trust_id, trust, roles):
+ trust_ref = trust
+ trust_ref['id'] = trust_id
+ trust_ref['deleted'] = False
+ trust_ref['roles'] = roles
+ if (trust_ref.get('expires_at') and
+ trust_ref['expires_at'].tzinfo is not None):
+ trust_ref['expires_at'] = (timeutils.normalize_time
+ (trust_ref['expires_at']))
+
+ self.db.set('trust-%s' % trust_id, trust_ref)
+ trustee_user_id = trust_ref['trustee_user_id']
+ trustee_list = self.db.get('trustee-%s' % trustee_user_id, [])
+ trustee_list.append(trust_id)
+ self.db.set('trustee-%s' % trustee_user_id, trustee_list)
+ trustor_user_id = trust_ref['trustor_user_id']
+ trustor_list = self.db.get('trustor-%s' % trustor_user_id, [])
+ trustor_list.append(trust_id)
+ self.db.set('trustor-%s' % trustor_user_id, trustor_list)
+ return copy.deepcopy(trust_ref)
+
+ def _filter_trust(selfself, ref):
+ if ref['deleted']:
+ return None
+ if ref.get('expires_at') and timeutils.utcnow() > ref['expires_at']:
+ return None
+ ref = copy.deepcopy(ref)
+ return ref
+
+ def get_trust(self, trust_id):
+ try:
+ ref = self.db.get('trust-%s' % trust_id)
+ return self._filter_trust(ref)
+ except exception.NotFound:
+ return None
+
+ def delete_trust(self, trust_id):
+ try:
+ ref = self.db.get('trust-%s' % trust_id)
+ except exception.NotFound:
+ raise exception.TrustNotFound(token_id=token_id)
+ ref['deleted'] = True
+ self.db.set('trust-%s' % trust_id, ref)
+
+ def list_trusts(self):
+ trusts = []
+ for key, value in self.db.items():
+ if key.startswith("trust-") and not value['deleted']:
+ trusts.append(value)
+ return trusts
+
+ def list_trusts_for_trustee(self, trustee_user_id):
+ trusts = []
+ for trust in self.db.get('trustee-%s' % trustee_user_id, []):
+ trusts.append(self.get_trust(trust))
+ return trusts
+
+ def list_trusts_for_trustor(self, trustor_user_id):
+ trusts = []
+ for trust in self.db.get('trustor-%s' % trustor_user_id, []):
+ trusts.append(self.get_trust(trust))
+ return trusts
diff --git a/keystone/trust/backends/sql.py b/keystone/trust/backends/sql.py
new file mode 100644
index 00000000..dc3644e3
--- /dev/null
+++ b/keystone/trust/backends/sql.py
@@ -0,0 +1,123 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC
+#
+# 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 keystone.common import sql
+from keystone import exception
+from keystone.openstack.common import timeutils
+from keystone import trust
+
+
+class TrustModel(sql.ModelBase, sql.DictBase):
+ __tablename__ = 'trust'
+ attributes = ['id', 'trustor_user_id', 'trustee_user_id',
+ 'project_id', 'impersonation', 'expires_at']
+ id = sql.Column(sql.String(64), primary_key=True)
+ #user id Of owner
+ trustor_user_id = sql.Column(sql.String(64), unique=False, nullable=False,)
+ #user_id of user allowed to consume this preauth
+ trustee_user_id = sql.Column(sql.String(64), unique=False, nullable=False)
+ project_id = sql.Column(sql.String(64), unique=False, nullable=True)
+ impersonation = sql.Column(sql.Boolean)
+ deleted_at = sql.Column(sql.DateTime)
+ expires_at = sql.Column(sql.DateTime)
+ extra = sql.Column(sql.JsonBlob())
+
+
+class TrustRole(sql.ModelBase):
+ __tablename__ = 'trust_role'
+ attributes = ['trust_id', 'role_id']
+ trust_id = sql.Column(sql.String(64), primary_key=True, nullable=False)
+ role_id = sql.Column(sql.String(64), primary_key=True, nullable=False)
+
+
+class Trust(sql.Base, trust.Driver):
+ @sql.handle_conflicts(type='trust')
+ def create_trust(self, trust_id, trust, roles):
+ session = self.get_session()
+ with session.begin():
+ ref = TrustModel.from_dict(trust)
+ ref['id'] = trust_id
+ if ref.get('expires_at') and ref['expires_at'].tzinfo is not None:
+ ref['expires_at'] = timeutils.normalize_time(ref['expires_at'])
+ session.add(ref)
+ added_roles = []
+ for role in roles:
+ trust_role = TrustRole()
+ trust_role.trust_id = trust_id
+ trust_role.role_id = role['id']
+ added_roles.append({'id': role['id']})
+ session.add(trust_role)
+ session.flush()
+ trust_dict = ref.to_dict()
+ trust_dict['roles'] = added_roles
+ return trust_dict
+
+ def _add_roles(self, trust_id, session, trust_dict):
+ roles = []
+ for role in session.query(TrustRole).filter_by(trust_id=trust_id):
+ roles.append({'id': role.role_id})
+ trust_dict['roles'] = roles
+
+ @sql.handle_conflicts(type='trust')
+ def get_trust(self, trust_id):
+ session = self.get_session()
+ ref = (session.query(TrustModel).
+ filter_by(deleted_at=None).
+ filter_by(id=trust_id).first())
+ if ref is None:
+ return None
+ if ref.expires_at is not None:
+ now = timeutils.utcnow()
+ if now > ref.expires_at:
+ return None
+ trust_dict = ref.to_dict()
+
+ self._add_roles(trust_id, session, trust_dict)
+ return trust_dict
+
+ @sql.handle_conflicts(type='trust')
+ def list_trusts(self):
+ session = self.get_session()
+ trusts = session.query(TrustModel).filter_by(deleted_at=None)
+ return [trust_ref.to_dict() for trust_ref in trusts]
+
+ @sql.handle_conflicts(type='trust')
+ def list_trusts_for_trustee(self, trustee_user_id):
+ session = self.get_session()
+ trusts = (session.query(TrustModel).
+ filter_by(deleted_at=None).
+ filter_by(trustee_user_id=trustee_user_id))
+ return [trust_ref.to_dict() for trust_ref in trusts]
+
+ @sql.handle_conflicts(type='trust')
+ def list_trusts_for_trustor(self, trustor_user_id):
+ session = self.get_session()
+ trusts = (session.query(TrustModel).
+ filter_by(deleted_at=None).
+ filter_by(trustor_user_id=trustor_user_id))
+ return [trust_ref.to_dict() for trust_ref in trusts]
+
+ @sql.handle_conflicts(type='trust')
+ def delete_trust(self, trust_id):
+ session = self.get_session()
+ with session.begin():
+ try:
+ trust_ref = (session.query(TrustModel).
+ filter_by(id=trust_id).one())
+ except sql.NotFound:
+ raise exception.TrustNotFound(trust_id=trust_id)
+ trust_ref.deleted_at = timeutils.utcnow()
+ session.flush()
diff --git a/keystone/trust/controllers.py b/keystone/trust/controllers.py
new file mode 100644
index 00000000..00183bc5
--- /dev/null
+++ b/keystone/trust/controllers.py
@@ -0,0 +1,244 @@
+import uuid
+import json
+
+from keystone import config
+from keystone import exception
+from keystone import identity
+from keystone.common import controller
+from keystone.common import dependency
+from keystone.common import logging
+from keystone import exception
+from keystone.openstack.common import timeutils
+
+
+LOG = logging.getLogger(__name__)
+CONF = config.CONF
+
+
+def _trustor_only(context, trust, user_id):
+ if user_id != trust.get('trustor_user_id'):
+ raise exception.Forbidden()
+
+
+def _admin_trustor_trustee_only(context, trust, user_id):
+ if (user_id != trust.get('trustor_user_id') and
+ user_id != trust.get('trustor_user_id') and
+ context['is_admin']):
+ raise exception.Forbidden()
+
+
+def _admin_trustor_only(context, trust, user_id):
+ if user_id != trust.get('trustor_user_id') and not context['is_admin']:
+ raise exception.Forbidden()
+
+
+@dependency.requires('identity_api', 'trust_api', 'token_api')
+class TrustV3(controller.V3Controller):
+ collection_name = "trusts"
+ member_name = "trust"
+
+ def _get_user_id(self, context):
+ if 'token_id' in context:
+ token_id = context['token_id']
+ token = self.token_api.get_token(context, token_id)
+ user_id = token['user']['id']
+ return user_id
+ return None
+
+ def get_trust(self, context, trust_id):
+ user_id = self._get_user_id(context)
+ trust = self.trust_api.get_trust(context, trust_id)
+ if not trust:
+ raise exception.TrustNotFound(trust_id)
+ _admin_trustor_trustee_only(context, trust, user_id)
+ if not trust:
+ raise exception.TrustNotFound(trust_id=trust_id)
+ if (user_id != trust['trustor_user_id'] and
+ user_id != trust['trustee_user_id']):
+ raise exception.Forbidden()
+ self._fill_in_roles(context, trust,
+ self.identity_api.list_roles(context))
+ return TrustV3.wrap_member(context, trust)
+
+ def _fill_in_roles(self, context, trust, global_roles):
+ if trust.get('expires_at') is not None:
+ trust['expires_at'] = (timeutils.isotime
+ (trust['expires_at'],
+ subsecond=True))
+
+ if not 'roles' in trust:
+ trust['roles'] = []
+ trust_full_roles = []
+ for trust_role in trust['roles']:
+ if isinstance(trust_role, basestring):
+ trust_role = {'id': trust_role}
+ matching_roles = [x for x in global_roles
+ if x['id'] == trust_role['id']]
+ if matching_roles:
+ full_role = identity.controllers.RoleV3.wrap_member(
+ context, matching_roles[0])['role']
+ trust_full_roles.append(full_role)
+ trust['roles'] = trust_full_roles
+ trust['roles_links'] = {
+ 'self': (CONF.public_endpoint % CONF +
+ "trusts/%s/roles" % trust['id']),
+ 'next': None,
+ 'previous': None}
+
+ def _clean_role_list(self, context, trust, global_roles):
+ trust_roles = []
+ global_role_names = dict((r['name'], r)
+ for r in
+ global_roles)
+ for role in trust.get('roles', []):
+ if 'id' in role:
+ trust_roles.append({'id': role['id']})
+ elif 'name' in role:
+ rolename = role['name']
+ if rolename in global_role_names:
+ trust_roles.append({'id':
+ global_role_names[rolename]['id']})
+ else:
+ raise exception.RoleNotFound("role %s is not defined" %
+ rolename)
+ else:
+ raise exception.ValidationError(attribute='id or name',
+ target='roles')
+ return trust_roles
+
+ @controller.protected
+ def create_trust(self, context, trust=None):
+ """
+ The user creating the trust must be trustor
+ """
+
+ #TODO instead of raising ValidationError on the first problem,
+ #return a collection of all the problems.
+ if not trust:
+ raise exception.ValidationError(attribute='trust',
+ target='request')
+ try:
+ user_id = self._get_user_id(context)
+ _trustor_only(context, trust, user_id)
+ #confirm that the trustee exists
+ trustee_ref = self.identity_api.get_user(context,
+ trust['trustee_user_id'])
+ if not trustee_ref:
+ raise exception.UserNotFound(user_id=trust['trustee_user_id'])
+ global_roles = self.identity_api.list_roles(context)
+ clean_roles = self._clean_role_list(context, trust, global_roles)
+ if trust.get('project_id'):
+ user_roles = self.identity_api.get_roles_for_user_and_project(
+ context, user_id, trust['project_id'])
+ else:
+ user_roles = []
+ for trust_role in clean_roles:
+ matching_roles = [x for x in user_roles
+ if x == trust_role['id']]
+ if not matching_roles:
+ raise exception.RoleNotFound(role_id=trust_role['id'])
+ if trust.get('expires_at') is not None:
+ if not trust['expires_at'].endswith('Z'):
+ trust['expires_at'] += 'Z'
+ trust['expires_at'] = (timeutils.parse_isotime
+ (trust['expires_at']))
+ new_trust = self.trust_api.create_trust(
+ context=context,
+ trust_id=uuid.uuid4().hex,
+ trust=trust,
+ roles=clean_roles)
+ self._fill_in_roles(context,
+ new_trust,
+ global_roles)
+ return TrustV3.wrap_member(context, new_trust)
+ except KeyError as e:
+ raise exception.ValidationError(attribute=e.args[0],
+ target='trust')
+
+ @controller.protected
+ def list_trusts(self, context):
+ query = context['query_string']
+ trusts = []
+ if not query:
+ self.assert_admin(context)
+ trusts += self.trust_api.list_trusts(context)
+ if 'trustor_user_id' in query:
+ user_id = query['trustor_user_id']
+ calling_user_id = self._get_user_id(context)
+ if user_id != calling_user_id:
+ raise exception.Forbidden()
+ trusts += (self.trust_api.
+ list_trusts_for_trustor(context, user_id))
+ if 'trustee_user_id' in query:
+ user_id = query['trustee_user_id']
+ calling_user_id = self._get_user_id(context)
+ if user_id != calling_user_id:
+ raise exception.Forbidden()
+ trusts += (self.trust_api.
+ list_trusts_for_trustee(context, user_id))
+ global_roles = self.identity_api.list_roles(context)
+ for trust in trusts:
+ self._fill_in_roles(context, trust, global_roles)
+ return TrustV3.wrap_collection(context, trusts)
+
+ @controller.protected
+ def delete_trust(self, context, trust_id):
+ trust = self.trust_api.get_trust(context, trust_id)
+ if not trust:
+ raise exception.TrustNotFound(trust_id)
+
+ user_id = self._get_user_id(context)
+ _admin_trustor_only(context, trust, user_id)
+ self.trust_api.delete_trust(context, trust_id)
+ userid = trust['trustor_user_id']
+ token_list = self.token_api.list_tokens(context,
+ userid,
+ trust_id=trust_id)
+ for token in token_list:
+ self.token_api.delete_token(context, token)
+
+ @controller.protected
+ def list_roles_for_trust(self, context, trust_id):
+ trust = self.get_trust(context, trust_id)['trust']
+ if not trust:
+ raise exception.TrustNotFound(trust_id)
+ user_id = self._get_user_id(context)
+ _admin_trustor_trustee_only(context, trust, user_id)
+ return {'roles': trust['roles'],
+ 'links': trust['roles_links']}
+
+ @controller.protected
+ def check_role_for_trust(self, context, trust_id, role_id):
+ """Checks if a role has been assigned to a trust."""
+ trust = self.trust_api.get_trust(context, trust_id)
+ if not trust:
+ raise exception.TrustNotFound(trust_id)
+ user_id = self._get_user_id(context)
+ _admin_trustor_trustee_only(context, trust, user_id)
+ matching_roles = [x for x in trust['roles']
+ if x['id'] == role_id]
+ if not matching_roles:
+ raise exception.RoleNotFound(role_id=role_id)
+
+ @controller.protected
+ def get_role_for_trust(self, context, trust_id, role_id):
+ """Checks if a role has been assigned to a trust."""
+ trust = self.trust_api.get_trust(context, trust_id)
+ if not trust:
+ raise exception.TrustNotFound(trust_id)
+
+ user_id = self._get_user_id(context)
+ _admin_trustor_trustee_only(context, trust, user_id)
+ matching_roles = [x for x in trust['roles']
+ if x['id'] == role_id]
+ if not matching_roles:
+ raise exception.RoleNotFound(role_id=role_id)
+ global_roles = self.identity_api.list_roles(context)
+ matching_roles = [x for x in global_roles
+ if x['id'] == role_id]
+ if matching_roles:
+ full_role = (identity.controllers.
+ RoleV3.wrap_member(context, matching_roles[0]))
+ return full_role
+ else:
+ raise exception.RoleNotFound(role_id=role_id)
diff --git a/keystone/trust/core.py b/keystone/trust/core.py
new file mode 100644
index 00000000..a9a15ff7
--- /dev/null
+++ b/keystone/trust/core.py
@@ -0,0 +1,63 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC
+#
+# 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.
+
+"""Main entry point into the Identity service."""
+
+from keystone.common import dependency
+from keystone.common import logging
+from keystone.common import manager
+from keystone.common import wsgi
+from keystone import config
+from keystone import exception
+
+
+CONF = config.CONF
+
+LOG = logging.getLogger(__name__)
+
+
+@dependency.provider('trust_api')
+class Manager(manager.Manager):
+ """Default pivot point for the Trust backend.
+
+ See :mod:`keystone.common.manager.Manager` for more details on how this
+ dynamically calls the backend.
+
+ """
+
+ def __init__(self):
+ super(Manager, self).__init__(CONF.trust.driver)
+
+
+class Driver(object):
+ def create_trust(self, trust_id, trust, roles):
+ """Create a new trust.
+
+ :returns: a new trust
+ """
+ raise exception.NotImplemented()
+
+ def get_trust(self, trust_id):
+ raise exception.NotImplemented()
+
+ def list_trusts(self):
+ raise exception.NotImplemented()
+
+ def list_trusts_for_trustee(self, trustee):
+ raise exception.NotImplemented()
+
+ def list_trusts_for_trustor(self, trustor):
+ raise exception.NotImplemented()
diff --git a/keystone/trust/routers.py b/keystone/trust/routers.py
new file mode 100644
index 00000000..2ed35ed0
--- /dev/null
+++ b/keystone/trust/routers.py
@@ -0,0 +1,58 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC
+#
+# 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.
+"""WSGI Routers for the Identity service."""
+from keystone.common import wsgi
+from keystone.trust import controllers
+from keystone.common import router
+
+
+def append_v3_routers(mapper, routers):
+ trust_controller = controllers.TrustV3()
+
+ mapper.connect('/trusts',
+ controller=trust_controller,
+ action='create_trust',
+ conditions=dict(method=['POST']))
+
+ mapper.connect('/trusts',
+ controller=trust_controller,
+ action='list_trusts',
+ conditions=dict(method=['GET']))
+
+ mapper.connect('/trusts/{trust_id}',
+ controller=trust_controller,
+ action='delete_trust',
+ conditions=dict(method=['DELETE']))
+
+ mapper.connect('/trusts/{trust_id}',
+ controller=trust_controller,
+ action='get_trust',
+ conditions=dict(method=['GET']))
+
+ mapper.connect('/trusts/{trust_id}/roles',
+ controller=trust_controller,
+ action='list_roles_for_trust',
+ conditions=dict(method=['GET']))
+
+ mapper.connect('/trusts/{trust_id}/roles/{role_id}',
+ controller=trust_controller,
+ action='check_role_for_trust',
+ conditions=dict(method=['HEAD']))
+
+ mapper.connect('/trusts/{trust_id}/roles/{role_id}',
+ controller=trust_controller,
+ action='get_role_for_trust',
+ conditions=dict(method=['GET']))