Example #1
0
    def query_users(self, query, request):
        if not query:
            return

        try:
            bugzilla = Bugzilla(get_bugzilla_api_key(request.user))
        except BugzillaError as e:
            raise UserQueryError('Bugzilla error: %s' % e.msg)

        try:
            # We don't want to auto populate just any user because Bugzilla has
            # over 300,000 users and most of them aren't relevant to MozReview.
            #
            # So, we only auto import users if they have IRC nick syntax or
            # if the search matches them exactly.
            def user_relevant(u):
                if BZ_IRCNICK_RE.search(u['real_name']):
                    return True
                if u['email'] == query:
                    return True

                # This might allow too many users through. Let's not get too
                # attached to this.
                if u['real_name'] == query:
                    return True

                return False

            users = bugzilla.query_users(query)
            users['users'] = [u for u in users['users'] if user_relevant(u)]
            get_or_create_bugzilla_users(users)
        except BugzillaError as e:
            raise UserQueryError('Bugzilla error: %s' % e.msg)
Example #2
0
    def get_or_create_user(self, username, request):
        """Always check Bugzilla for updates."""
        username = username.strip()

        try:
            bugzilla = Bugzilla(get_bugzilla_api_key(request.user))
        except BugzillaUrlError:
            return None
        except BugzillaError:
            raise PermissionDenied

        user_data = bugzilla.get_user(username)

        if not user_data:
            raise self.bz_error_response(request)

        # Just store the results.
        get_or_create_bugzilla_users(user_data)

        try:
            return User.objects.get(username=username)
        except User.DoesNotExist:
            return None
Example #3
0
    def get_or_create_user(self, username, request):
        """Always check Bugzilla for updates."""
        username = username.strip()

        try:
            bugzilla = Bugzilla(get_bugzilla_api_key(request.user))
        except BugzillaUrlError:
            return None
        except BugzillaError:
            raise PermissionDenied

        user_data = bugzilla.get_user(username)

        if not user_data:
            raise self.bz_error_response(request)

        # Just store the results.
        get_or_create_bugzilla_users(user_data)

        try:
            return User.objects.get(username=username)
        except User.DoesNotExist:
            return None
Example #4
0
    def query_users(self, query, request):
        if not query:
            return

        try:
            bugzilla = Bugzilla(get_bugzilla_api_key(request.user))
        except BugzillaError as e:
            raise UserQueryError('Bugzilla error: %s' % e.msg)

        try:
            # We don't want to auto populate just any user because Bugzilla has
            # over 300,000 users and most of them aren't relevant to MozReview.
            #
            # So, we only auto import users if they have IRC nick syntax or
            # if the search matches them exactly.
            def user_relevant(u):
                if BMO_IRC_NICK_RE.search(u['real_name']):
                    return True
                if u['email'] == query:
                    return True

                # This might allow too many users through. Let's not get too
                # attached to this.
                if u['real_name'] == query:
                    return True

                return False

            users = bugzilla.query_users(query)
            users['users'] = [u for u in users['users'] if user_relevant(u)]
            logger.info(
                'importing Bugzilla users from query "%s": %s' %
                (query, ', '.join(sorted(u['email'] for u in users['users']))))
            get_or_create_bugzilla_users(users)
        except BugzillaError as e:
            raise UserQueryError('Bugzilla error: %s' % e.msg)
Example #5
0
    def authenticate_api_key(self, username, api_key):
        """Authenticate a user from a username and API key.

        This is intended to be used by the Web API and not a user-facing
        login form. We enforce that the user already exists and has an
        API key - not necessarily the same API key - on file. The API key
        passed in is only used for authentication: all subsequent communication
        with Bugzilla should be performed using the API key on file.

        We require the user already exist in the database because having
        the user go through the browser-facing login flow is the most sane
        (and secure) way to obtain an API key. We don't want to store the
        API key provided to us from the client because API keys obtained by
        the browser login may have special permissions not granted to normal
        API keys.
        """
        username = username.strip()

        try:
            bugzilla = Bugzilla()
        except BugzillaUrlError:
            logging.warn('Login failure for user %s: Bugzilla URL not set.' %
                         username)

        try:
            valid = bugzilla.valid_api_key(username, api_key)
        except BugzillaError as e:
            logging.error('Login failure for user %s: %s' % (username, e))
            return None

        if not valid:
            logging.error('Login failure for user %s: invalid API key' %
                          username)
            assert bugzilla.base_url.endswith('/')
            raise BugzillaAPIKeyNeededError(
                    bugzilla.base_url + 'userprefs.cgi?tab=apikey')

        # Assign the API key to the Bugzilla connection so the user info
        # lookup uses it.
        # TODO can we skip valid_api_key() and just get user info straight up?
        bugzilla.api_key = api_key

        try:
            user_data = bugzilla.get_user(username)
        except BugzillaError as e:
            logging.error('Login failure for user %s: unable to retrieve '
                          'Bugzilla user info: %s' % (username, e))
            return None

        if not user_data:
            logging.warning('Could not retrieve user info for %s after '
                            'validating API key' % username)
            return None

        bz_user = user_data['users'][0]

        try:
            bum = BugzillaUserMap.objects.get(bugzilla_user_id=bz_user['id'])
            user = bum.user
        except BugzillaUserMap.DoesNotExist:
            logging.warning('Login failure for user %s: API key valid but '
                            'user missing from database' % username)
            raise WebLoginNeededError()

        if not user.is_active:
            logging.error('Login failure for user %s: user not active' %
                          username)
            return None

        # We require a local API key to be on file, as it will be used for
        # subsequent requests.
        if not get_bugzilla_api_key(user):
            logging.warning('Login failure for user %s: no API key in '
                            'database' % username)
            raise WebLoginNeededError()

        return user
Example #6
0
    def authenticate_api_key(self, username, api_key):
        """Authenticate a user from a username and API key.

        This is intended to be used by the Web API and not a user-facing
        login form. We enforce that the user already exists and has an
        API key - not necessarily the same API key - on file. The API key
        passed in is only used for authentication: all subsequent communication
        with Bugzilla should be performed using the API key on file.

        We require the user already exist in the database because having
        the user go through the browser-facing login flow is the most sane
        (and secure) way to obtain an API key. We don't want to store the
        API key provided to us from the client because API keys obtained by
        the browser login may have special permissions not granted to normal
        API keys.
        """
        username = username.strip()

        logger.info('Login attempt (apikey) for user %s: ' % username)

        try:
            bugzilla = Bugzilla()
        except BugzillaUrlError:
            logger.warn('Login failure (apikey) for user %s: Bugzilla URL '
                        'not set.' % username)

        try:
            valid = bugzilla.valid_api_key(username, api_key)
        except BugzillaError as e:
            logger.error('Login failure (apikey) for user %s: %s' %
                         (username, e))
            return None

        if not valid:
            logger.error('Login failure for user %s: invalid API key' %
                         username)
            assert bugzilla.base_url.endswith('/')
            raise BugzillaAPIKeyNeededError(bugzilla.base_url +
                                            'userprefs.cgi?tab=apikey')

        # Assign the API key to the Bugzilla connection so the user info
        # lookup uses it.
        # TODO can we skip valid_api_key() and just get user info straight up?
        bugzilla.api_key = api_key

        try:
            user_data = bugzilla.get_user(username)
        except BugzillaError as e:
            logger.error('Login failure (apikey) for user %s: unable to '
                         'retrieve Bugzilla user info: %s' % (username, e))
            return None

        if not user_data:
            logger.warning('Could not retrieve user info for %s after '
                           'validating API key' % username)
            return None

        bz_user = user_data['users'][0]

        try:
            bum = BugzillaUserMap.objects.get(bugzilla_user_id=bz_user['id'])
            user = bum.user
        except BugzillaUserMap.DoesNotExist:
            logger.warning('Login failure for user %s: API key valid but '
                           'user missing from database' % username)
            raise WebLoginNeededError()

        if not user.is_active:
            logger.error('Login failure (apikey) for user %s: user not '
                         'active' % username)
            return None

        # We require a local API key to be on file, as it will be used for
        # subsequent requests.
        if not get_bugzilla_api_key(user):
            logger.warning('Login failure for user %s: no API key in '
                           'database' % username)
            raise WebLoginNeededError()

        logger.info('Login successful (apikey) for user %s: ' % username)

        return user