コード例 #1
0
 def test_get_tenant_with_user(self):
     """Test that the customer tenant is returned."""
     mock_request = self.request
     middleware = IdentityHeaderMiddleware()
     result = middleware.get_tenant(Tenant, "localhost", mock_request)
     self.assertEqual(result.schema_name,
                      create_schema_name(mock_request.user.account))
コード例 #2
0
ファイル: middleware.py プロジェクト: kahowell/insights-rbac
 def get_tenant(self, model, hostname, request):
     """Override the tenant selection logic."""
     connections["default"].set_schema_to_public()
     if request.user.account not in TENANTS:
         if request.user.system:
             try:
                 tenant = Tenant.objects.get(schema_name=create_schema_name(request.user.account))
             except Tenant.DoesNotExist:
                 raise Http404()
         else:
             tenant, created = Tenant.objects.get_or_create(schema_name=create_schema_name(request.user.account))
             if created:
                 seed_roles(tenant=tenant, update=False)
                 seed_group(tenant=tenant)
         TENANTS[request.user.account] = tenant
     return TENANTS[request.user.account]
コード例 #3
0
    def test_create_principal_on_approval(self):
        """Test that moving a car to approved creates a principal."""
        update_data = {"status": "approved"}
        tenant_schema = create_schema_name(self.request_2.target_account)
        principal_name = get_cross_principal_name(
            self.request_2.target_account, self.request_2.user_id)
        car_uuid = self.request_2.request_id
        url = reverse("cross-detail", kwargs={"pk": str(car_uuid)})
        tenant = Tenant.objects.get(schema_name=tenant_schema)

        client = APIClient()
        response = client.patch(url,
                                update_data,
                                format="json",
                                **self.associate_admin_request.META)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data.get("status"),
                         update_data.get("status"))

        with tenant_context(tenant):
            princ = Principal.objects.get(username__iexact=principal_name)
        self.assertEqual(princ.username, principal_name)
        self.assertEqual(princ.tenant, tenant)
        self.assertTrue(princ.cross_account)
コード例 #4
0
 def get_tenant(self, model, hostname, request):
     """Override the tenant selection logic."""
     connections["default"].set_schema_to_public()
     tenant_schema = create_schema_name(request.user.account)
     tenant = TENANTS.get_tenant(tenant_schema)
     if tenant is None:
         if request.user.system:
             try:
                 tenant = Tenant.objects.get(schema_name=tenant_schema)
             except Tenant.DoesNotExist:
                 raise Http404()
         else:
             with transaction.atomic():
                 try:
                     tenant = Tenant.objects.get(schema_name=tenant_schema)
                 except Tenant.DoesNotExist:
                     cursor = transaction.get_connection().cursor()
                     cursor.execute("LOCK TABLE public.api_tenant in SHARE ROW EXCLUSIVE MODE")
                     tenant, created = Tenant.objects.get_or_create(schema_name=tenant_schema)
                     if created:
                         seed_permissions(tenant=tenant)
                         seed_roles(tenant=tenant)
                         seed_group(tenant=tenant)
         TENANTS.save_tenant(tenant)
     return tenant
コード例 #5
0
ファイル: middleware.py プロジェクト: mkanoor/insights-rbac
    def process_request(self, request):  # noqa: C901
        """Process request for identity middleware.

        Args:
            request (object): The request object

        """
        if is_no_auth(request):
            request.user = User('', '')
            return
        try:
            rh_auth_header, json_rh_auth = extract_header(request, self.header)
            username = json_rh_auth.get('identity', {}).get('user',
                                                            {}).get('username')
            account = json_rh_auth.get('identity', {}).get('account_number')
            is_admin = json_rh_auth.get('identity',
                                        {}).get('user', {}).get('is_org_admin')
        except (KeyError, JSONDecodeError) as decode_err:
            logger.error('Could not obtain identity on request.')
            raise decode_err
        except binascii.Error as error:
            logger.error('Could not decode header: %s.', error)
            raise error
        if (username and account):
            # Get request ID
            req_id = request.META.get(RH_INSIGHTS_REQUEST_ID)
            # Check for customer creation & user creation
            try:
                schema_name = create_schema_name(account)
                tenant = Tenant.objects.filter(schema_name=schema_name).get()
            except Tenant.DoesNotExist:
                tenant = IdentityHeaderMiddleware._create_tenant(account)

            try:
                user = User.objects.get(username__iexact=username)
            except User.DoesNotExist:
                user = IdentityHeaderMiddleware._create_user(
                    username, tenant, request)

            with tenant_context(tenant):
                try:
                    Principal.objects.get(username__iexact=username)
                except Principal.DoesNotExist:
                    Principal.objects.create(username=username)
                    logger.info('Created new principal %s for account %s.',
                                username, account)

            user.identity_header = {
                'encoded': rh_auth_header,
                'decoded': json_rh_auth
            }
            user.admin = is_admin
            user.account = account
            user.req_id = req_id
            if not is_admin:
                user.access = IdentityHeaderMiddleware._get_access_for_user(
                    username, tenant)
            request.user = user
コード例 #6
0
    def create_principal(self, target_account, user_id):
        """Create a cross account principal in the target account."""
        # Principal would have the pattern acctxxx-123456.
        principal_name = f"{target_account}-{user_id}"
        tenant_schema = create_schema_name(target_account)
        with tenant_context(Tenant.objects.get(schema_name=tenant_schema)):
            cross_account_principal = Principal.objects.get_or_create(
                username=principal_name, cross_account=True)

        return cross_account_principal
コード例 #7
0
 def setUp(self):
     """Set up middleware tests."""
     super().setUp()
     self.user_data = self._create_user_data()
     self.customer = self._create_customer_data()
     self.schema_name = create_schema_name(self.customer['account_id'])
     self.request_context = self._create_request_context(
         self.customer, self.user_data, create_customer=False)
     self.request = self.request_context['request']
     self.request.path = '/api/v1/providers/'
     self.request.META['QUERY_STRING'] = ''
コード例 #8
0
 def setUp(self):
     """Set up middleware tests."""
     super().setUp()
     self.user_data = self._create_user_data()
     self.customer = self._create_customer_data()
     self.schema_name = create_schema_name(self.customer["account_id"])
     self.request_context = self._create_request_context(
         self.customer, self.user_data, create_customer=False)
     self.request = self.request_context["request"]
     self.request.path = "/api/v1/providers/"
     self.request.META["QUERY_STRING"] = ""
コード例 #9
0
def create_cross_principal(target_account, user_id):
    """Create a cross account principal in the target account."""
    # Principal would have the pattern acctxxx-123456.
    principal_name = get_cross_principal_name(target_account, user_id)
    tenant_schema = create_schema_name(target_account)
    associate_tenant = Tenant.objects.get(schema_name=tenant_schema)
    cross_account_principal = create_principal_with_tenant(principal_name, tenant_schema, associate_tenant)

    # Create the principal in public schema
    create_principal_with_tenant(principal_name, "public", associate_tenant)

    return cross_account_principal
コード例 #10
0
    def process_request(self, request):  # noqa: C901
        """Process request for csrf checks.

        Args:
            request (object): The request object

        """
        if is_no_auth(request):
            request.user = User('', '')
            return
        try:
            json_rh_auth = extract_header(request, self.header)
            username = json_rh_auth['identity']['user']['username']
            email = json_rh_auth['identity']['user']['email']
            account = json_rh_auth['identity']['account_number']
        except (KeyError, JSONDecodeError):
            logger.warning('Could not obtain identity on request.')
            return
        if (username and email and account):
            # Check for customer creation & user creation
            query_string = ''
            if request.META['QUERY_STRING']:
                query_string = '?{}'.format(request.META['QUERY_STRING'])
            logger.info(f'API: {request.path}{query_string}'  # pylint: disable=W1203
                        f' -- ACCOUNT: {account} USER: {username}')
            try:
                schema_name = create_schema_name(account)
                tenant = Tenant.objects.filter(schema_name=schema_name).get()
            except Tenant.DoesNotExist:
                tenant = IdentityHeaderMiddleware._create_tenant(account)

            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                user = IdentityHeaderMiddleware._create_user(
                    username, email, tenant, request)
            request.user = user

            # Temporarily add principals based on API interaction
            with tenant_context(tenant):
                try:
                    Principal.objects.get(username=username)
                except Principal.DoesNotExist:
                    try:
                        with transaction.atomic():
                            principal = Principal(username=username,
                                                  email=email)
                            principal.save()
                            logger.info(
                                'Created new principal for account_id %s.',
                                account)
                    except IntegrityError:
                        pass
コード例 #11
0
ファイル: view.py プロジェクト: kylape/insights-rbac
    def validate_and_get_input_for_creation(self, request_data):
        """Validate the create api input."""
        target_account = request_data.get("target_account")
        start_date = request_data.get("start_date")
        end_date = request_data.get("end_date")
        roles = request_data.get("roles")
        if None in [target_account, start_date, end_date, roles]:
            self.throw_validation_error(
                "cross-account-create",
                f"{PARAMS_FOR_CREATION} must be all specified.")

        try:
            start_date = datetime.strptime(start_date, "%m/%d/%Y")
            end_date = datetime.strptime(end_date, "%m/%d/%Y")
        except ValueError:
            raise self.throw_validation_error(
                "cross-account-create",
                "start_date or end_date does not match format: '%m/%d/%Y'.")

        if start_date > (datetime.now() + timedelta(60)):
            raise self.throw_validation_error(
                "cross-account-create",
                "Start date must be within 60 days of today.")

        if end_date - start_date > timedelta(365):
            raise self.throw_validation_error(
                "cross-account-create",
                "Access duration may not be longer than one year.")

        with tenant_context(Tenant.objects.get(schema_name="public")):
            for role in roles:
                try:
                    Role.objects.get(display_name=role)
                except Role.DoesNotExist:
                    raise self.throw_validation_error(
                        "cross-account-create",
                        f"Role '{role}' does not exist.")

        try:
            tenant_schema_name = create_schema_name(target_account)
            Tenant.objects.get(schema_name=tenant_schema_name)
        except Tenant.DoesNotExist:
            raise self.throw_validation_error(
                "cross-account-create",
                f"Account '{target_account}' does not exist.")

        request_data["start_date"] = start_date
        request_data["end_date"] = end_date
        request_data["user_id"] = self.request.user.user_id
        request_data["roles"] = [{"display_name": role} for role in roles]
コード例 #12
0
 def setUp(self):
     """Set up middleware tests."""
     super().setUp()
     self.user_data = self._create_user_data()
     self.customer = self._create_customer_data()
     self.schema_name = create_schema_name(self.customer["account_id"])
     self.request_context = self._create_request_context(
         self.customer, self.user_data, create_customer=False)
     self.request = self.request_context["request"]
     self.request.path = "/api/v1/providers/"
     user = User()
     user.username = self.user_data["username"]
     user.account = self.customer_data["account_id"]
     self.request.user = user
コード例 #13
0
 def setUp(self):
     """Set up middleware tests."""
     super().setUp()
     self.user_data = self._create_user_data()
     self.customer = self._create_customer_data()
     self.schema_name = create_schema_name(self.customer['account_id'])
     self.request_context = self._create_request_context(
         self.customer, self.user_data)
     request = self.request_context['request']
     request.path = '/api/v1/providers/'
     serializer = UserSerializer(data=self.user_data,
                                 context=self.request_context)
     if serializer.is_valid(raise_exception=True):
         user = serializer.save()
         request.user = user
コード例 #14
0
    def _create_customer(cls, account, create_tenant=True):
        """Create a customer.

        Args:
            account (str): The account identifier

        Returns:
            (Customer) The created customer

        """
        connection.set_schema_to_public()
        schema_name = create_schema_name(account)
        tenant = None
        if create_tenant:
            tenant = Tenant(schema_name=schema_name)
            tenant.save()
        return tenant
コード例 #15
0
    def validate_and_format_input(self, request_data):
        """Validate the create api input."""
        for field in PARAMS_FOR_CREATION:
            if not request_data.__contains__(field):
                self.throw_validation_error("cross-account-request", f"Field {field} must be specified.")

        target_account = request_data.get("target_account")
        try:
            tenant_schema_name = create_schema_name(target_account)
            Tenant.objects.get(schema_name=tenant_schema_name)
        except Tenant.DoesNotExist:
            raise self.throw_validation_error("cross-account-request", f"Account '{target_account}' does not exist.")

        with tenant_context(Tenant.objects.get(schema_name="public")):
            request_data["roles"] = self.format_roles(request_data.get("roles"))

        request_data["user_id"] = self.request.user.user_id
コード例 #16
0
    def validate_and_format_input(self, request_data, partial=False):
        """Validate the create api input."""
        target_account = request_data.get("target_account")

        if target_account:
            try:
                tenant_schema_name = create_schema_name(target_account)
                Tenant.objects.get(schema_name=tenant_schema_name)
            except Tenant.DoesNotExist:
                raise self.throw_validation_error(
                    "cross-account-request",
                    f"Account '{target_account}' does not exist.")

        request_data["user_id"] = self.request.user.user_id
        if "roles" in request_data:
            with tenant_context(Tenant.objects.get(schema_name="public")):
                request_data["roles"] = self.format_roles(
                    request_data.get("roles"))
コード例 #17
0
def create_cross_principal(target_account, user_id):
    """Create a cross account principal in the target account."""
    # Principal would have the pattern acctxxx-123456.
    principal_name = get_cross_principal_name(target_account, user_id)
    tenant_schema = create_schema_name(target_account)
    tenant = Tenant.objects.get(schema_name=tenant_schema)
    with tenant_context(tenant):
        cross_account_principal, _ = Principal.objects.get_or_create(
            username=principal_name, cross_account=True)

        # NOTE: after we ensure/enforce all object have a tenant_id FK, we can add tenant=tenant
        # to the get_or_create. We cannot currently, because records without would fail the GET
        # and would create duplicate records. This ensures we temporarily do an update if
        # obj.tenant_id is NULL
        if not cross_account_principal.tenant:
            cross_account_principal.tenant = tenant
            cross_account_principal.save()

    return cross_account_principal
コード例 #18
0
    def _create_tenant(account):
        """Create a tenant.

        Args:
            account (str): The account identifier

        Returns:
            (Tenant) The created tenant

        """
        schema_name = create_schema_name(account)
        try:
            with transaction.atomic():
                tenant = Tenant(schema_name=schema_name)
                tenant.save()
                logger.info('Created new tenant from account_id %s.', account)
        except IntegrityError:
            tenant = Tenant.objects.filter(schema_name=schema_name).get()

        return tenant
コード例 #19
0
    def process_request(self, request):  # pylint: disable=R1710
        """Process request for identity middleware.

        Args:
            request (object): The request object

        """
        # Get request ID
        request.req_id = request.META.get(RH_INSIGHTS_REQUEST_ID)

        if any([request.path.startswith(prefix) for prefix in settings.INTERNAL_API_PATH_PREFIXES]):
            # This request is for a private API endpoint
            return

        if is_no_auth(request):
            return
        user = User()
        try:
            _, json_rh_auth = extract_header(request, self.header)
            user.account = json_rh_auth.get("identity", {})["account_number"]
            user_info = json_rh_auth.get("identity", {}).get("user", {})
            user.username = user_info["username"]
            user.admin = user_info.get("is_org_admin")
            user.internal = user_info.get("is_internal")
            user.user_id = user_info.get("user_id")
            user.system = False
            if not user.admin:
                try:
                    schema_name = create_schema_name(user.account)
                    tenant = Tenant.objects.filter(schema_name=schema_name).get()
                except Tenant.DoesNotExist:
                    request.user = user
                    tenant = self.get_tenant(model=None, hostname=None, request=request)

                user.access = IdentityHeaderMiddleware._get_access_for_user(user.username, tenant)
            # Cross account request check
            internal = json_rh_auth.get("identity", {}).get("internal", {})
            if internal != {}:
                cross_account = internal.get("cross_access", False)
                if cross_account:
                    if not (user.internal and user_info.get("email").endswith("@redhat.com")):
                        logger.error("Cross accout request permission denied. Requester is not internal user.")
                        return HttpResponseUnauthorizedRequest()
                    user.username = f"{user.account}-{user.user_id}"
        except (KeyError, JSONDecodeError):
            request_psk = request.META.get(RH_RBAC_PSK)
            account = request.META.get(RH_RBAC_ACCOUNT)
            client_id = request.META.get(RH_RBAC_CLIENT_ID)
            has_system_auth_headers = request_psk and account and client_id

            if has_system_auth_headers and validate_psk(request_psk, client_id):
                user.username = client_id
                user.account = account
                user.admin = True
                user.system = True
            else:
                logger.error("Could not obtain identity on request.")
                return HttpResponseUnauthorizedRequest()
        except binascii.Error as error:
            logger.error("Could not decode header: %s.", error)
            raise error
        if user.username and user.account:
            request.user = user

            super().process_request(request)
            # We are now in the database context of the tenant
            assert request.tenant