Esempio n. 1
0
        def _check_groups(*args, **kwargs):
            request = _find_httprequest(args)
            mrp = request.mozreview_profile

            if not mrp:
                # This should never happen since webapi_login_required
                # should mean they are authenticated and our middleware
                # has added the profile to the request. Check it just
                # to make sure nothing went wrong with the middleware.
                logger.error(
                    'No MozReviewUserProfile for authenticated user: %s',
                    request.user.id)
                return PERMISSION_DENIED

            if not mrp.ldap_username:
                logger.info(
                    'No ldap_username for user: %s when '
                    'attempting to access protected resource', request.user.id)
                return PERMISSION_DENIED.with_message(
                    'You are not associated with an ldap account')

            for group in groups:
                if not mrp.has_scm_ldap_group(group):
                    logger.info(
                        'Missing group membership for user: %s '
                        'when attempting to access protected '
                        'resource', request.user.id)
                    return PERMISSION_DENIED.with_message(
                        'You do not have the required ldap permissions')

            return view_func(*args, **kwargs)
Esempio n. 2
0
    def create(self,
               request,
               username,
               email,
               password,
               first_name='',
               last_name='',
               local_site=None,
               *args,
               **kwargs):
        """Create a user

        This functionality is limited to superusers.
        """
        if (not request.user.is_superuser
                and not request.user.has_perm('auth.add_user')):
            return PERMISSION_DENIED.with_message(
                'You do not have permission to create users.')

        if local_site:
            return PERMISSION_DENIED.with_message(
                'This API is not available for local sites.')

        try:
            validate_email(email)
        except ValidationError as e:
            return INVALID_FORM_DATA, {
                'fields': {
                    'email': [six.text_type(e)]
                },
            }

        try:
            # We wrap this in a transaction.atomic block because attempting to
            # create a user with a username that already exists will generate
            # an IntegrityError and break the current transaction.
            #
            # Unit tests wrap each test case in a transaction.atomic block as
            # well. If this is block is not here, the test case's transaction
            # will break and cause errors during test teardown.
            with transaction.atomic():
                user = User.objects.create_user(username,
                                                email,
                                                password,
                                                first_name=first_name,
                                                last_name=last_name)
        except IntegrityError:
            return INVALID_FORM_DATA, {
                'fields': {
                    'username': [
                        'A user with the requested username already exists.',
                    ]
                }
            }

        return 201, {
            self.item_result_key: user,
        }
Esempio n. 3
0
    def create(self, request, username, email, password, first_name='',
               last_name='', local_site=None, *args, **kwargs):
        """Create a new user.

        The user will be allowed to authenticate into Review Board with the
        given username and password.

        Only administrators or those with the ``auth.add_user`` permission
        will be able to create users.

        This API cannot be used on :term:`Local Sites`.
        """
        if (not request.user.is_superuser and
            not request.user.has_perm('auth.add_user')):
            return PERMISSION_DENIED.with_message(
                'You do not have permission to create users.')

        if local_site:
            return PERMISSION_DENIED.with_message(
                'This API is not available for local sites.')

        try:
            validate_email(email)
        except ValidationError as e:
            return INVALID_FORM_DATA, {
                'fields': {
                    'email': [six.text_type(e)]
                },
            }

        try:
            # We wrap this in a transaction.atomic block because attempting to
            # create a user with a username that already exists will generate
            # an IntegrityError and break the current transaction.
            #
            # Unit tests wrap each test case in a transaction.atomic block as
            # well. If this is block is not here, the test case's transaction
            # will break and cause errors during test teardown.
            with transaction.atomic():
                user = User.objects.create_user(username, email, password,
                                                first_name=first_name,
                                                last_name=last_name)
        except IntegrityError:
            return INVALID_FORM_DATA, {
                'fields': {
                    'username': [
                        'A user with the requested username already exists.',
                    ]
                }
            }

        return 201, {
            self.item_result_key: user,
        }
Esempio n. 4
0
        def _check_groups(*args, **kwargs):
            request = _find_httprequest(args)
            mrp = request.mozreview_profile

            if not mrp:
                # This should never happen since webapi_login_required
                # should mean they are authenticated and our middleware
                # has added the profile to the request. Check it just
                # to make sure nothing went wrong with the middleware.
                logging.error('No MozReviewUserProfile for authenticated user')
                return PERMISSION_DENIED

            if not mrp.ldap_username:
                return PERMISSION_DENIED.with_message(
                    'You are not associated with an ldap account')

            for group in groups:
                if not mrp.has_scm_ldap_group(group):
                    return PERMISSION_DENIED.with_message(
                        'You do not have the required ldap permissions')

            return view_func(*args, **kwargs)
    def create(self, request, parent_request_id, reviewers, *args, **kwargs):
        try:
            parent_rr = ReviewRequest.objects.get(pk=parent_request_id)
        except ReviewRequest.DoesNotExist:
            return DOES_NOT_EXIST

        if not (parent_rr.is_accessible_by(request.user)
                or parent_rr.is_mutable_by(request.user)):
            return PERMISSION_DENIED

        if not is_parent(parent_rr):
            return NOT_PARENT

        # Validate and expand the new reviewer list.

        bugzilla = Bugzilla(get_bugzilla_api_key(request.user))
        child_reviewers = json.loads(reviewers)
        invalid_reviewers = []
        for child_rrid in child_reviewers:
            users = []
            for username in child_reviewers[child_rrid]:
                try:
                    users.append(bugzilla.get_user_from_irc_nick(username))
                except User.DoesNotExist:
                    invalid_reviewers.append(username)
            child_reviewers[child_rrid] = users

        if invalid_reviewers:
            # Because this isn't called through Review Board's built-in
            # backbone system, it's dramatically simpler to return just the
            # intended error message instead of categorising the errors by
            # field.
            if len(invalid_reviewers) == 1:
                return INVALID_FORM_DATA.with_message(
                    "The reviewer '%s' was not found" % invalid_reviewers[0])
            else:
                return INVALID_FORM_DATA.with_message(
                    "The reviewers '%s' were not found" %
                    "', '".join(invalid_reviewers))

        # Review Board only supports the submitter updating a review
        # request.  In order for this to work, we publish these changes
        # in Review Board under the review submitter's account, and
        # set an extra_data field which instructs our bugzilla
        # connector to use this request's user when adjusting flags.
        #
        # Updating the review request requires creating a draft and
        # publishing it, so we have to be careful to not overwrite
        # existing drafts.

        try:
            with transaction.atomic():
                for rr in itertools.chain([parent_rr],
                                          gen_child_rrs(parent_rr)):
                    if rr.get_draft() is not None:
                        return REVIEW_REQUEST_UPDATE_NOT_ALLOWED.with_message(
                            "Unable to update reviewers as the review "
                            "request has pending changes (the patch author "
                            "has a draft)")

                try:
                    for child_rr in gen_child_rrs(parent_rr):
                        if str(child_rr.id) in child_reviewers:
                            if not child_rr.is_accessible_by(request.user):
                                return PERMISSION_DENIED.with_message(
                                    "You do not have permission to update "
                                    "reviewers on review request %s" %
                                    child_rr.id)

                            draft = ReviewRequestDraft.create(child_rr)
                            draft.target_people.clear()
                            for user in child_reviewers[str(child_rr.id)]:
                                draft.target_people.add(user)

                    set_publish_as(parent_rr, request.user)
                    parent_rr_draft = ReviewRequestDraft.create(parent_rr)
                    update_parent_rr_reviewers(parent_rr_draft)
                    parent_rr.publish(user=parent_rr.submitter)
                finally:
                    clear_publish_as(parent_rr)

        except PublishError as e:
            logging.error("failed to update reviewers on %s: %s" %
                          (parent_rr.id, str(e)))
            return PUBLISH_ERROR.with_message(str(e))

        return 200, {}
Esempio n. 6
0
    def update(self, request, local_site=None, *args, **kwargs):
        """Update information on a user.

        Users can update their own ``email``, ``first_name``, and ``last_name``
        information.

        Administrators or those with the ``auth.change_user`` permission can
        update those along with ``is_active``. When setting ``is_active`` to
        ``False``, the user will not be able to log in through standard
        credentials or API tokens. (Note that this does not delete their
        password or API tokens. It simply blocks the ability to log in.)

        .. note::
           This API cannot be used on :term:`Local Sites`.

        Version Added::
            3.0.16
        """
        if local_site:
            return PERMISSION_DENIED.with_message(
                'This API is not available for local sites.')

        try:
            user = self.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not self.has_modify_permissions(request, user):
            return self.get_no_access_error(request)

        has_global_modify_permissions = \
            self.has_global_modify_permissions(request.user)
        backend = get_enabled_auth_backends()[0]

        updated_fields = set()
        invalid_fields = {}

        # Validate the fields that the user wants to set.
        if 'email' in kwargs:
            if backend.supports_change_email:
                email = kwargs['email']

                try:
                    validate_email(email)
                except ValidationError as e:
                    invalid_fields['email'] = e.messages
            else:
                invalid_fields['email'] = [
                    'The configured auth backend does not allow e-mail '
                    'addresses to be changed.'
                ]

        if not backend.supports_change_name:
            for field in ('first_name', 'last_name'):
                if field in kwargs:
                    invalid_fields[field] = [
                        'The configured auth backend does not allow names '
                        'to be changed.'
                    ]

        if 'is_active' in kwargs and not has_global_modify_permissions:
            invalid_fields['is_active'] = [
                'This field can only be set by administrators and users '
                'with the auth.change_user permission.'
            ]

        if invalid_fields:
            return INVALID_FORM_DATA, {
                'fields': invalid_fields,
            }

        # Set any affected fields.
        for field in ('first_name', 'last_name', 'email', 'is_active'):
            value = kwargs.get(field)

            if value is not None:
                old_value = getattr(user, field)

                if old_value != value:
                    setattr(user, field, value)
                    updated_fields.add(field)

        # Notify the auth backend, so any server-side state can be changed.
        if updated_fields:
            if ('first_name' in updated_fields
                    or 'last_name' in updated_fields):
                try:
                    backend.update_name(user)
                except Exception as e:
                    logger.exception(
                        'Error when calling update_name for auth backend '
                        '%r for user ID %s: %s', backend, user.pk, e)

            if 'email' in updated_fields:
                try:
                    backend.update_email(user)
                except Exception as e:
                    logger.exception(
                        'Error when calling update_email for auth backend '
                        '%r for user ID %s: %s', backend, user.pk, e)

            user.save(update_fields=updated_fields)

        return 200, {
            self.item_result_key: user,
        }
Esempio n. 7
0
    def create(self,
               request,
               username,
               email,
               password,
               first_name='',
               last_name='',
               local_site=None,
               *args,
               **kwargs):
        """Create a new user.

        The user will be allowed to authenticate into Review Board with the
        given username and password.

        Only administrators or those with the ``auth.add_user`` permission
        will be able to create users.

        This API cannot be used on :term:`Local Sites`.
        """
        if (not request.user.is_superuser
                and not request.user.has_perm('auth.add_user')):
            return PERMISSION_DENIED.with_message(
                'You do not have permission to create users.')

        if local_site:
            return PERMISSION_DENIED.with_message(
                'This API is not available for local sites.')

        try:
            validate_email(email)
        except ValidationError as e:
            return INVALID_FORM_DATA, {
                'fields': {
                    'email': e.messages,
                },
            }

        try:
            # We wrap this in a transaction.atomic block because attempting to
            # create a user with a username that already exists will generate
            # an IntegrityError and break the current transaction.
            #
            # Unit tests wrap each test case in a transaction.atomic block as
            # well. If this is block is not here, the test case's transaction
            # will break and cause errors during test teardown.
            with transaction.atomic():
                user = User.objects.create_user(username,
                                                email,
                                                password,
                                                first_name=first_name,
                                                last_name=last_name)
        except IntegrityError:
            return INVALID_FORM_DATA, {
                'fields': {
                    'username': [
                        'A user with the requested username already exists.',
                    ]
                }
            }

        return 201, {
            self.item_result_key: user,
        }
    def create(self, request, parent_request_id, reviewers, *args, **kwargs):
        try:
            parent_rr = ReviewRequest.objects.get(pk=parent_request_id)
        except ReviewRequest.DoesNotExist:
            return DOES_NOT_EXIST

        if not (parent_rr.is_accessible_by(request.user)
                or parent_rr.is_mutable_by(request.user)):
            return PERMISSION_DENIED

        if not is_parent(parent_rr):
            return NOT_PARENT

        # Validate and expand the new reviewer list.

        bugzilla = Bugzilla(get_bugzilla_api_key(request.user))
        child_reviewers = json.loads(reviewers)
        invalid_reviewers = []
        for child_rrid in child_reviewers:
            users = []
            for username in child_reviewers[child_rrid]:
                try:
                    users.append(bugzilla.get_user_from_irc_nick(username))
                except User.DoesNotExist:
                    invalid_reviewers.append(username)
            child_reviewers[child_rrid] = users

        if invalid_reviewers:
            # Because this isn't called through Review Board's built-in
            # backbone system, it's dramatically simpler to return just the
            # intended error message instead of categorising the errors by
            # field.
            if len(invalid_reviewers) == 1:
                return INVALID_FORM_DATA.with_message(
                    "The reviewer '%s' was not found" % invalid_reviewers[0])
            else:
                return INVALID_FORM_DATA.with_message(
                    "The reviewers '%s' were not found"
                    % "', '".join(invalid_reviewers))

        # Review Board only supports the submitter updating a review
        # request.  In order for this to work, we publish these changes
        # in Review Board under the review submitter's account, and
        # set an extra_data field which instructs our bugzilla
        # connector to use this request's user when adjusting flags.
        #
        # Updating the review request requires creating a draft and
        # publishing it, so we have to be careful to not overwrite
        # existing drafts.

        try:
            with transaction.atomic():
                for rr in itertools.chain([parent_rr],
                                          gen_child_rrs(parent_rr)):
                    if rr.get_draft() is not None:
                        return REVIEW_REQUEST_UPDATE_NOT_ALLOWED.with_message(
                            "Unable to update reviewers as the review "
                            "request has pending changes (the patch author "
                            "has a draft)")

                try:
                    for child_rr in gen_child_rrs(parent_rr):
                        if str(child_rr.id) in child_reviewers:
                            if not child_rr.is_accessible_by(request.user):
                                return PERMISSION_DENIED.with_message(
                                    "You do not have permission to update "
                                    "reviewers on review request %s"
                                    % child_rr.id)

                            draft = ReviewRequestDraft.create(child_rr)
                            draft.target_people.clear()
                            for user in child_reviewers[str(child_rr.id)]:
                                draft.target_people.add(user)

                    set_publish_as(parent_rr, request.user)
                    parent_rr_draft = ReviewRequestDraft.create(parent_rr)
                    update_parent_rr_reviewers(parent_rr_draft)
                    parent_rr.publish(user=parent_rr.submitter)
                finally:
                    clear_publish_as(parent_rr)

        except PublishError as e:
                logging.error("failed to update reviewers on %s: %s"
                              % (parent_rr.id, str(e)))
                return PUBLISH_ERROR.with_message(str(e))

        return 200, {}