# Copyright 2017 The Forseti Security Authors. All rights reserved.
#
# 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.
""" Explain API. """
from builtins import object
from google.cloud.forseti.common.util import logger
LOGGER = logger.get_logger(__name__)
[docs]class Explainer(object):
"""Implements the Explain API."""
def __init__(self, config):
"""Initialize
Args:
config (object): ServiceConfig in server
"""
self.config = config
[docs] def list_resources(self, model_name, full_resource_name_prefix):
"""Lists resources by resource name prefix.
Args:
model_name (str): Model to operate on.
full_resource_name_prefix (ste): the prefix of the resource name
Returns:
list: list of Resources match the query
"""
LOGGER.debug('Listing resources, model_name = %s,'
' full_resource_name_prefix = %s',
model_name, full_resource_name_prefix)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
return data_access.list_resources_by_prefix(
session, full_resource_name_prefix)
[docs] def list_group_members(self, model_name, member_name_prefix):
"""Lists a member from the model.
Args:
model_name (str): Model to operate on.
member_name_prefix (str): the prefix of the member_name
Returns:
list: list of Members that match the query
"""
LOGGER.debug('Listing Group members, model_name = %s,'
' member_name_prefix = %s', model_name, member_name_prefix)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
return data_access.list_group_members(session, member_name_prefix)
[docs] def list_roles(self, model_name, role_name_prefix):
"""Lists the role in the model matching the prefix.
Args:
model_name (str): Model to operate on.
role_name_prefix (str): prefix of the role_name
Returns:
list: list of role_names that match the query
"""
LOGGER.info('Listing roles, model_name = %s,'
' role_name_prefix = %s', model_name, role_name_prefix)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
return data_access.list_roles_by_prefix(session, role_name_prefix)
[docs] def get_iam_policy(self, model_name, resource):
"""Gets the IAM policy for the resource.
Args:
model_name (str): Model to operate on.
resource (str): Resource to query
Returns:
dict: the IAM policy
"""
LOGGER.debug('Retrieving IAM policy, model_name = %s, resource = %s',
model_name, resource)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
return data_access.get_iam_policy(session, resource)
[docs] def check_iam_policy(self, model_name, resource, permission, identity):
"""Checks access according to IAM policy for the resource.
Args:
model_name (str): Model to operate on.
resource (str): Resource to check
permission (str): Permission to check
identity (str): Member to check
Returns:
bool: whether such access is allowed
"""
LOGGER.debug('Checking IAM policy, model_name = %s, resource = %s,'
' permission = %s, identity = %s',
model_name, resource, permission, identity)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
return data_access.check_iam_policy(
session, resource, permission, identity)
[docs] def explain_denied(self, model_name, member, resources, permissions, roles):
"""Provides information on granting a member access to a resource.
Args:
model_name (str): Model to operate on.
member (str): Member to query
resources (list): Resources to query
permissions (list): Permissions to query
roles (list): Roles to query
Returns:
list: list of tuples,
(overgranting,[(role_name,member_name,resource_name)])
"""
LOGGER.debug('Explaining how to grant access to a member,'
' model_name = %s, member = %s, resources = %s,'
' permissions = %s, roles = %s',
model_name, member, resources, permissions, roles)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
result = data_access.explain_denied(session,
member,
resources,
permissions,
roles)
return result
[docs] def explain_granted(self, model_name, member, resource, role, permission):
"""Provides information on why a member has access to a resource.
Args:
model_name (str): Model to operate on.
member (str): Member to query
resource (str): Resource to query
role (str): Role to query
permission (str): Permission to query
Returns:
tuples: (bindings, member_graph, resource_type_names)
bindings, the bindings to grant the access
member_graph, the graph to have member included in the binding
resource_type_names, the resource tree
"""
LOGGER.debug('Explaining why the member has access to a resource,'
' model_name = %s, member = %s, resource = %s,'
' permission = %s, role = %s',
model_name, member, resource, permission, role)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
result = data_access.explain_granted(session,
member,
resource,
role,
permission)
return result
[docs] def get_access_by_resources(self, model_name, resource_name,
permission_names, expand_groups):
"""Returns members who have access to the given resource.
Args:
model_name (str): Model to operate on.
resource_name (str): Resource name to query for.
permission_names (list): Permission names to query for.
expand_groups (bool): Whether to expand groups in policies.
Returns:
dict: role_member_mapping, <"role_name", "member_names">
"""
LOGGER.debug('Retrieving members that have access to the resource,'
' model_name = %s, resource_name = %s,'
' permission_names = %s, expand_groups = %s',
model_name, resource_name,
permission_names, expand_groups)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
mapping = data_access.query_access_by_resource(session,
resource_name,
permission_names,
expand_groups)
return mapping
[docs] def get_access_by_permissions(self, model_name, role_name, permission_name,
expand_groups, expand_resources):
"""Returns access tuples satisfying the permission or role.
Args:
model_name (str): Model to operate on.
role_name (str): Role name to query for.
permission_name (str): Permission name to query for.
expand_groups (bool): Whether to expand groups in policies.
expand_resources (bool): Whether to expand resources.
Yields:
tuple: Generator for (role, resource, members).
"""
LOGGER.debug('Retrieving access tuples that satisfy the role or'
' permission: model_name = %s, role_name = %s,'
' permission_name = %s, expand_groups = %s,'
' expand_resources = %s', model_name, role_name,
permission_name, expand_groups, expand_resources)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
for role, resource, members in (
data_access.query_access_by_permission(session,
role_name,
permission_name,
expand_groups,
expand_resources)):
yield role, resource, members
[docs] def get_access_by_members(self, model_name, member_name, permission_names,
expand_resources):
"""Returns access to resources for the provided member.
Args:
model_name (str): Model to operate on.
member_name (str): Member name to query
permission_names (list): Permission names to query for.
expand_resources (bool): Whether to expand resources.
Yields:
tuple: Generator for (role, resources).
"""
LOGGER.debug('Retrieving access to resources for a given member,'
' model_name = %s, member_name = %s,'
' permission_names = %s, expand_resources = %s',
model_name, member_name,
permission_names, expand_resources)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
for role, resources in data_access.query_access_by_member(
session, member_name, permission_names, expand_resources):
yield role, resources
[docs] def get_permissions_by_roles(self, model_name, role_names, role_prefixes):
"""Returns the permissions associated with the specified roles.
Args:
model_name (str): Model to operate on.
role_names (list): Role names to query for.
role_prefixes (list): Role name prefixes to query for
Yields:
tuple: Generator for (Role, Permission).
"""
LOGGER.debug('Retrieving the permissions associated with the'
' specified roles, model_name = %s, role_names = %s,'
' role_prefixes = %s',
model_name, role_names, role_prefixes)
model_manager = self.config.model_manager
scoped_session, data_access = model_manager.get(model_name)
with scoped_session as session:
for result in data_access.query_permissions_by_roles(
session, role_names, role_prefixes):
yield result