Exemple #1
0
def can_modify_members(user: str, user_groups: List[str],
                       group_info: Optional[Any]) -> bool:
    # No users can modify members on restricted groups
    if group_info and group_info.restricted:
        return False

    if can_admin_all(user, user_groups):
        return True

    if is_in_group(
            user,
            user_groups,
        [
            *config.get("groups.can_admin_restricted", []),
            *config.get("dynamic_config.groups.can_admin_restricted", []),
        ],
    ):
        return True

    if is_in_group(
            user,
            user_groups,
        [
            *config.get("groups.can_modify_members", []),
            *config.get("dynamic_config.groups.can_modify_members", []),
        ],
    ):
        return True
    return False
Exemple #2
0
def can_edit_attributes(
    user: str, user_groups: List[str], group_info: Optional[Any]
) -> bool:
    if can_admin_all(user, user_groups):
        return True

    if is_in_group(user, user_groups, config.get("groups.can_admin_restricted", [])):
        return True
    if is_in_group(user, user_groups, config.get("groups.can_edit_attributes", [])):
        return True
    return False
Exemple #3
0
def can_admin_policies(user: str, user_groups: List[str]) -> bool:
    if can_admin_all(user, user_groups):
        return True
    if is_in_group(user, user_groups,
                   config.get("groups.can_admin_policies", [])):
        return True
    return False
Exemple #4
0
def can_admin_all(user: str, user_groups: List[str]):
    application_admin = config.get("application_admin")
    if application_admin:
        if user == application_admin or application_admin in user_groups:
            return True
    if is_in_group(user, user_groups, config.get("groups.can_admin", [])):
        return True
    return False
Exemple #5
0
def can_edit_dynamic_config(
    user: str,
    user_groups: List[str],
) -> bool:
    if can_admin_all(user, user_groups):
        return True
    if is_in_group(user, user_groups, config.get("groups.can_edit_config", [])):
        return True
    return False
Exemple #6
0
def can_edit_sensitive_attributes(user: str, user_groups: List[str],
                                  group_info: Optional[Any]) -> bool:
    if can_admin_all(user, user_groups):
        return True
    if is_in_group(
            user,
            user_groups,
        [
            *config.get("groups.can_edit_sensitive_attributes", []),
            *config.get("dynamic_config.groups.can_edit_sensitive_attributes",
                        []),
        ],
    ):
        return True
    return False
Exemple #7
0
def can_delete_roles(
    user: str,
    user_groups: List[str],
) -> bool:
    if can_admin_all(user, user_groups):
        return True
    if is_in_group(
            user,
            user_groups,
        [
            *config.get("groups.can_delete_roles", []),
            *config.get("dynamic_config.groups.can_delete_roles", []),
        ],
    ):
        return True
    return False
Exemple #8
0
def can_delete_iam_principals(
    user: str,
    user_groups: List[str],
) -> bool:
    if can_admin_all(user, user_groups):
        return True
    if is_in_group(
            user,
            user_groups,
        [
            # TODO: Officially deprecate groups.can_delete_roles config key
            *config.get("groups.can_delete_roles", []),
            # TODO: Officially deprecate dynamic_config.groups.can_delete_roles config key
            *config.get("dynamic_config.groups.can_delete_roles", []),
            *config.get("groups.can_delete_iam_principals", []),
            *config.get("dynamic_config.groups.can_delete_iam_principals", []),
        ],
    ):
        return True
    return False
Exemple #9
0
    async def get(self):
        """
        Provide information about site configuration for the frontend
        :return:
        """
        is_contractor = config.config_plugin().is_contractor(self.user)
        site_config = {
            "consoleme_logo": await get_random_security_logo(),
            "google_tracking_uri": config.get("google_analytics.tracking_url"),
            "documentation_url": config.get("documentation_page"),
            "support_contact": config.get("support_contact"),
            "support_chat_url": config.get("support_chat_url"),
            "security_logo": config.get("security_logo.image"),
            "security_url": config.get("security_logo.url"),
        }

        user_profile = {
            "site_config":
            site_config,
            "user":
            self.user,
            "can_logout":
            config.get("auth.set_auth_cookie"),
            "is_contractor":
            is_contractor,
            "employee_photo_url":
            config.config_plugin().get_employee_photo_url(self.user),
            "employee_info_url":
            config.config_plugin().get_employee_info_url(self.user),
            "authorization": {
                "can_edit_policies":
                can_admin_policies(self.user, self.groups),
                "can_create_roles": can_create_roles(self.user, self.groups),
                "can_delete_roles": can_delete_roles(self.user, self.groups),
            },
            "pages": {
                "header": {
                    "custom_header_message_title":
                    config.get("headers.custom_header_message.title", ""),
                    "custom_header_message_text":
                    config.get("headers.custom_header_message.text", ""),
                },
                "groups": {
                    "enabled": config.get("headers.group_access.enabled",
                                          False)
                },
                "users": {
                    "enabled": config.get("headers.group_access.enabled",
                                          False)
                },
                "policies": {
                    "enabled":
                    config.get("headers.policies.enabled", True)
                    and not is_contractor
                },
                "self_service": {
                    "enabled":
                    config.get("enable_self_service", True)
                    and not is_contractor
                },
                "api_health": {
                    "enabled":
                    is_in_group(
                        self.user,
                        self.groups,
                        config.get("groups.can_edit_health_alert", []),
                    )
                },
                "audit": {
                    "enabled":
                    is_in_group(self.user, self.groups,
                                config.get("groups.can_audit", []))
                },
                "config": {
                    "enabled": can_edit_dynamic_config(self.user, self.groups)
                },
            },
            "accounts":
            await get_account_id_to_name_mapping(),
        }

        self.set_header("Content-Type", "application/json")
        self.write(user_profile)
Exemple #10
0
    async def get(self):
        """
        Provide information about site configuration for the frontend
        :return:
        """
        is_contractor = config.config_plugin().is_contractor(self.user)
        site_config = {
            "consoleme_logo": await get_random_security_logo(),
            "google_analytics": {
                "tracking_id": config.get("google_analytics.tracking_id"),
                "options": config.get("google_analytics.options", {}),
            },
            "documentation_url": config.get(
                "documentation_page", "https://hawkins.gitbook.io/consoleme/"
            ),
            "support_contact": config.get("support_contact"),
            "support_chat_url": config.get(
                "support_chat_url", "https://discord.com/invite/nQVpNGGkYu"
            ),
            "security_logo": config.get("security_logo.image"),
            "security_url": config.get("security_logo.url"),
            # If site_config.landing_url is set, users will be redirected to the landing URL after authenticating
            # on the frontend.
            "landing_url": config.get("site_config.landing_url"),
            "temp_policy_support": config.get("policies.temp_policy_support"),
            "notifications": {
                "enabled": config.get("site_config.notifications.enabled"),
                "request_interval": config.get(
                    "site_config.notifications.request_interval", 60
                ),
            },
            "cloudtrail_denies_policy_generation": config.get(
                "celery.cache_cloudtrail_denies.enabled", False
            ),
        }

        custom_page_header: Dict[str, str] = await get_custom_page_header(
            self.user, self.groups
        )
        user_profile = {
            "site_config": site_config,
            "user": self.user,
            "can_logout": config.get("auth.set_auth_cookie", False),
            "is_contractor": is_contractor,
            "employee_photo_url": config.config_plugin().get_employee_photo_url(
                self.user
            ),
            "employee_info_url": config.config_plugin().get_employee_info_url(
                self.user
            ),
            "authorization": {
                "can_edit_policies": can_admin_policies(self.user, self.groups),
                "can_create_roles": can_create_roles(self.user, self.groups),
                "can_delete_iam_principals": can_delete_iam_principals(
                    self.user, self.groups
                ),
            },
            "pages": {
                "header": {
                    "custom_header_message_title": custom_page_header.get(
                        "custom_header_message_title", ""
                    ),
                    "custom_header_message_text": custom_page_header.get(
                        "custom_header_message_text", ""
                    ),
                    "custom_header_message_route": custom_page_header.get(
                        "custom_header_message_route", ""
                    ),
                },
                "groups": {
                    "enabled": config.get("headers.group_access.enabled", False)
                },
                "users": {"enabled": config.get("headers.group_access.enabled", False)},
                "policies": {
                    "enabled": config.get("headers.policies.enabled", True)
                    and not is_contractor
                },
                "self_service": {
                    "enabled": config.get("enable_self_service", True)
                    and not is_contractor
                },
                "api_health": {
                    "enabled": is_in_group(
                        self.user,
                        self.groups,
                        config.get("groups.can_edit_health_alert", []),
                    )
                },
                "audit": {
                    "enabled": is_in_group(
                        self.user, self.groups, config.get("groups.can_audit", [])
                    )
                },
                "config": {"enabled": can_edit_dynamic_config(self.user, self.groups)},
            },
            "accounts": await get_account_id_to_name_mapping(),
        }

        self.set_header("Content-Type", "application/json")
        self.write(user_profile)
Exemple #11
0
    async def put(self):
        """
        Allows an "authorized user" (Any user the notification is intended for) to mark the notification as read/unread
        or hidden/unhidden for themselves or all other notification recipients

        :return:
        """
        change = ConsoleMeNotificationUpdateRequest.parse_raw(
            self.request.body)
        errors = []

        for untrusted_notification in change.notifications:
            notification = await fetch_notification(
                untrusted_notification.predictable_id)
            if not notification:
                errors.append("Unable to find matching notification")
                continue
            authorized = is_in_group(self.user, self.groups,
                                     notification.users_or_groups)
            if not authorized:
                errors.append(
                    f"Unauthorized because user is not associated with notification: {notification.predictable_id}"
                )
                continue
            if (change.action == ConsoleMeNotificationUpdateAction.
                    toggle_read_for_current_user):
                if self.user in notification.read_by_users:
                    # Mark as unread
                    notification.read_by_users.remove(self.user)
                else:
                    # Mark as read
                    notification.read_by_users.append(self.user)
            elif (change.action ==
                  ConsoleMeNotificationUpdateAction.toggle_read_for_all_users):
                # Mark or unmark notification as `read_by_all`.  If unmarked,
                # ConsoleMe will fall back to `notification.read_by_user` to determine if
                # a given user has read the notification
                notification.read_by_all = not notification.read_by_all
            elif (change.action == ConsoleMeNotificationUpdateAction.
                  toggle_hidden_for_current_user):
                if self.user in notification.hidden_for_users:
                    # Unmark as hidden
                    notification.hidden_for_users.remove(self.user)
                else:
                    # Mark as hidden
                    notification.hidden_for_users.append(self.user)
            elif (change.action == ConsoleMeNotificationUpdateAction.
                  toggle_hidden_for_all_users):
                # Mark or unmark as "Hidden for all users". If unmarked, falls back to `hidden_for_users.read_by_user`
                # to determine whether to show the notification to a given user
                notification.hidden_for_all = not notification.hidden_for_all
            else:
                raise Exception("Unknown or unsupported change action.")
            await write_notification(notification)
        try:
            # Retrieve and return updated notifications for user
            notification_response: GetNotificationsForUserResponse = (
                await get_notifications_for_user(self.user,
                                                 self.groups,
                                                 force_refresh=True))
            notifications: List[
                ConsoleMeUserNotification] = notification_response.notifications
            response = WebResponse(
                status="success",
                status_code=200,
                data={
                    "unreadNotificationCount":
                    notification_response.unread_count,
                    "notifications": notifications,
                },
            )
            self.write(response.json())
        except Exception as e:
            sentry_sdk.capture_exception()
            self.set_status(500)
            response = WebResponse(status=Status2.error,
                                   status_code=500,
                                   errors=[str(e)],
                                   data=[])
            self.write(response.json())
            return