Ejemplo n.º 1
0
    def protected_get_user_by_username(cls, username):
        """ Retreives the User object for the given username, provided the
            username is that of the currently logged in user, or the
            currently logged in user is a mod.  If the username is not that
            of the currently logged in user, and the currently logged in user
            is not a mod, then an exception is raised.

        :param username:
            The username of the user to get
        :returns:
            The appropriate User object
        """
        if not cls.valid_username(username):
            raise BadRequestException('No or invalid username provided')
        current_user = cls.get_current_user(verified_email_required=False)
        if current_user is None:
            raise UnauthorizedException('User not logged in')
        elif current_user.username_lower == username.lower():
            return current_user
        elif current_user.is_mod:
            user = User.get_by_username(username)
            if user is None:
                raise BadRequestException('No user exists for username ' +
                                          username)
            return user
        else:
            raise ForbiddenException('Insufficient privilages')
Ejemplo n.º 2
0
    def PasswordReset(self, prm):
        user = User.get_by_email(prm.email)
        if user is None:
            raise BadRequestException("No user registered with that email")

        if not prm.set_password_url:
            raise BadRequestException("No set password url provided")

        # Send password reset email
        ok, msg = user.send_password_reset_email(prm.set_password_url)
        if not ok:
            raise ConflictException(msg)
        return prm
Ejemplo n.º 3
0
    def UpdateUser(self, spm):
        user = self.protected_get_user_by_username(spm.old_username)

        # Make sure new request params are acceptable
        invalid_params = dict()
        ok, msg = self.valid_username(spm.username)
        if not ok:
            invalid_params['username'] = msg
        if spm.password is not None and len(spm.password) > 0:
            if not user.check_password(spm.old_password):
                invalid_params['old_password'] = '******'
            ok, msg = self.valid_password(spm.password)
            if not ok:
                invalid_params['new_password'] = msg
        ok, msg = self.valid_email(spm.email)
        if not ok:
            invalid_params['email'] = msg
        if not spm.verification_url:
            invalid_params['verification_url'] = (
                'A verification url is required')
        if len(invalid_params.keys()) > 0:
            raise BadRequestException('|'.join([
                key + ':' + invalid_params[key]
                for key in invalid_params.keys()
            ]))

        # Update the user
        ok, info, spm.verification_email_sent = self.update_user_internal(
            user, spm.email, spm.username, spm.password, spm.verification_url)
        if not ok:
            raise ConflictException(info)

        return spm
Ejemplo n.º 4
0
    def Register(self, rm):
        # Validate request params
        invalid_params = dict()
        ok, msg = self.valid_username(rm.username)
        if not ok:
            invalid_params['username'] = msg
        ok, msg = self.valid_password(rm.password)
        if not ok:
            invalid_params['password'] = msg
        ok, msg = self.valid_email(rm.email)
        if not ok:
            invalid_params['email'] = msg
        if not rm.verification_url:
            invalid_params['verification_url'] = (
                'A verification url is required')
        if len(invalid_params.keys()) > 0:
            # Some params were invalid.  Return 400 response.
            raise BadRequestException('|'.join([
                key + ':' + invalid_params[key]
                for key in invalid_params.keys()
            ]))

        # Create the user with username auth id
        auth_id = self.get_local_auth_id(rm.username)
        ok, info = User.create_user(auth_id,
                                    password_raw=rm.password,
                                    unique_properties=[
                                        'email_pending',
                                        'username',
                                    ],
                                    email_pending=rm.email,
                                    username=rm.username,
                                    is_mod=False)
        if ok:
            # Success.  Add email auth id so that user can sign in
            # by email too
            user = info
            auth_id = self.get_local_auth_id(user.email_pending)
            ok, info = user.add_auth_id(auth_id)
            if not ok:
                logging.error('Failed to add email auth id [' + auth_id +
                              ' ] to username [' + user.username + ']')

            # Send email verification
            user.send_email_verification(rm.verification_url)
        else:
            # Failed to create new user.  Respond with conflicting properties
            # separated by a colon, converting auth_id to username
            info_set = set()
            for prop in info:
                if prop == 'auth_id':
                    info_set.add('username')
                else:
                    info_set.add(prop)
            raise ConflictException(':'.join(info_set))

        return rm
Ejemplo n.º 5
0
    def SendEmailVerification(self, sevm):
        user = self.protected_get_user_by_username(sevm.username)

        if not sevm.verification_url:
            raise BadRequestException("No verification url provided!")

        # Send email verification
        if not user.send_email_verification(sevm.verification_url):
            raise ConflictException('Too many verificaiton emails sent.')
        sevm.email = user.email_pending
        return sevm
Ejemplo n.º 6
0
    def Login(self, lm):
        # Check existence of request params
        if lm.username_or_email is None or lm.password is None:
            raise BadRequestException('No username, email or password ' +
                                      'given')

        # Try to get the User
        auth_id = self.get_local_auth_id(lm.username_or_email)
        try:
            lm.user = User.get_by_auth_password(auth_id, lm.password)
        except InvalidAuthIdError:
            raise BadRequestException('Invalid credentials')
        except InvalidPasswordError:
            raise BadRequestException('Invalid credentials')
        user_id = lm.user.get_id()

        # Log in user with auth token
        lm.user_id_auth_token = self.create_user_id_auth_token(user_id)
        if lm.user_id_auth_token is None:
            raise ConflictException(
                'Encountered conflict when creating auth token')
        return lm
Ejemplo n.º 7
0
    def SetPassword(self, spm):
        # Check for valid new password
        ok, msg = self.valid_password(spm.new_password)
        if not ok:
            raise BadRequestException(msg)

        # Check for valid token + grab the user
        valid = User.validate_password_reset_token(spm.user_id, spm.token)
        if not valid:
            raise UnauthorizedException('Invalid token for setting password')
        user = User.get_by_id(spm.user_id)

        # Set password
        ok, info = self.update_user_internal(user, user.email_pending,
                                             user.username, spm.new_password)
        if ok:
            # Password set successfully
            User.delete_password_reset_token(spm.user_id, spm.token)
        else:
            raise BadRequestException('An unknown error occurred. Please try' +
                                      ' again later.')

        return spm
Ejemplo n.º 8
0
    def VerifyEmail(self, vem):
        # We require users to be logged in to verify email
        user = self.get_current_user(verified_email_required=False)
        if user is None:
            raise UnauthorizedException('Must be logged in to verify email')

        # Check for valid token
        user_id = user.get_id()
        valid = User.validate_verify_email_token(user_id, vem.token)
        if not valid:
            raise BadRequestException('Invalid token for verifying email')
        self.validate_email_internal(user)
        User.delete_verify_email_token(user_id, vem.token)
        return vem
Ejemplo n.º 9
0
    def GetUser(self, user_msg):
        # First, get the current user
        current_user = self.get_current_user(verified_email_required=False)
        if current_user is None:
            raise UnauthorizedException('Invalid credentials')

        if current_user.username == user_msg.username:
            return current_user
        elif current_user.is_mod:
            # Validate request params
            ok, msg = self.valid_username(user_msg.username)
            if not ok:
                raise BadRequestException('No or invalid username provided')

            user = User.get_by_username(user_msg.username)
            if user is None:
                raise NotFoundException('No user exists for username ' +
                                        user_msg.username)
            return user
        else:
            raise UnauthorizedException('Insufficient privilages')
Ejemplo n.º 10
0
    def SocialLogin(self, slm):
        if slm.provider is None or slm.access_token is None:
            raise BadRequestException('No provider or access token given')
        # Fetch the user info
        social_id = None
        url = PROVIDER_URLS.get(slm.provider.lower())
        if url is None:
            raise BadRequestException('Unknown provider')
        url = url.format(urlencode({'access_token': slm.access_token}))
        result = urlfetch.fetch(url)
        if result.status_code == 200:
            body = json.loads(result.content)
            social_id = body.get('id')
            # Determine if email provided, if any, is verified
            if slm.provider.lower() == 'facebook':
                # Can assume Facebook emails are verified:
                # http://stackoverflow.com/questions/14280535
                # /is-it-possible-to-check-if-an-email-is-confirmed-on-facebook
                verified = True
            elif slm.provider.lower() == 'google':
                verified = body.get('verified_email')
            else:
                logging.error('Unexpected provider: ' + slm.provider)
                raise BadRequestException('Unknown provider')
            # Grab the social email and create a username based on the email
            # with most non-alphanumeric characters removed
            social_email = body.get('email')
            username = None
            if social_email:
                username = social_email.split('@')[0]
                username = re.sub('[^a-zA-Z0-9_-]+', '', username)
                if len(username) > 17:
                    username = username[:17]
            if not username:
                username = '******'
            if not verified:
                # Don't actually use the social email if it is not verified
                social_email = None

        if social_id:
            # Need to fetch the user id associated with this social id
            # + email, or create a new user if one does not yet exist

            # Check if a user with this social id already exists
            auth_id = '{0}:{1}'.format(slm.provider.lower(), social_id)
            slm.user = User.get_by_auth_id(auth_id)
            if slm.user is None:
                # Social id not in use. Try getting user by verified email
                # to see if we can add social login with an existing user
                if social_email is not None:
                    slm.user = User.get_by_email_verified(social_email)
                if slm.user is None:
                    # Email not in use either. Create a new user.

                    # Try creating a new user by varying the username
                    for num in range(1000):
                        suffix = ''
                        if num > 0:
                            suffix = str(num)
                        this_username = username + suffix
                        unique_properties = ['username']
                        if social_email is not None:
                            unique_properties.append('email_verified')

                        ok, info = User.create_user(
                            auth_id,
                            unique_properties=unique_properties,
                            email_verified=social_email,
                            email_pending=social_email,
                            username=this_username,
                            is_mod=False)
                        if ok:
                            slm.user = info
                            break
                        elif ('email' in info and social_email is not None):
                            # Looks like the social email is in use after all.
                            # This could happen, for instance, if a user tried
                            # to double register at the same time.
                            raise ConflictException(
                                'Email [' + social_email +
                                '] for this account' + ' is already in use. ' +
                                'Did you accidentally try to login twice, ' +
                                'or have you not verified your email address' +
                                ' yet?')
                    else:
                        # Failed to create an account after 1000 tries
                        raise ConflictException(
                            'Encountered conflict when creating new account.')
                else:
                    # Email is in use, but social_id is not.
                    # If the User has a password, we require it before
                    # adding the social auth id to the User
                    if slm.user.has_password:
                        if not slm.password:
                            # Need a password, but none provided
                            slm.password_required = True
                            return slm
                        if not slm.user.check_password(slm.password):
                            # Need a password, but provided password invalid
                            raise UnauthorizedException('Invalid credentials')

                    # Now add the social auth id
                    ok, info = slm.user.add_auth_id(auth_id)
                    if ok:
                        slm.user = info
                    else:
                        raise ConflictException(
                            'Encountered conflict when adding auth id to ' +
                            'existing account, conflicting properties: ' +
                            str(info))

            if (social_email
                    and slm.user.email_pending_lower == social_email.lower()
                    and slm.user.email_verified_lower != social_email.lower()):
                # Email is now verified by social login
                slm.user = self.validate_email_internal(slm.user)

            # Create auth token
            slm.user_id_auth_token = self.create_user_id_auth_token(
                slm.user.get_id())
            if slm.user_id_auth_token is None:
                raise ConflictException(
                    'Encountered conflict when creating auth token')
        else:
            raise BadRequestException('Access token did not provide valid id')

        return slm
Ejemplo n.º 11
0
    def Register(self, rm):
        # Validate request params
        invalid_params = dict()
        ok, msg = self.valid_username(rm.username)
        if not ok:
            invalid_params['username'] = msg
        ok, msg = self.valid_password(rm.password)
        if not ok:
            invalid_params['password'] = msg
        ok, msg = self.valid_email(rm.email)
        if not ok:
            invalid_params['email'] = msg
        if (config.USE_ACCESS_TOKENS
                and not User.validate_access_token(rm.access_token)):
            invalid_params['access_token'] = 'Invalid access token'
        if not rm.verification_url:
            invalid_params['verification_url'] = (
                'A verification url is required')
        if len(invalid_params.keys()) > 0:
            # Some params were invalid.  Return 400 response.
            raise BadRequestException('|'.join([
                key + ':' + invalid_params[key]
                for key in invalid_params.keys()
            ]))

        # Create the user with username auth id
        auth_id = self.get_local_auth_id(rm.username)
        ok, info = User.create_user(auth_id,
                                    password_raw=rm.password,
                                    unique_properties=[
                                        'email_pending',
                                        'username',
                                    ],
                                    email_pending=rm.email,
                                    username=rm.username,
                                    is_mod=False)
        if ok:
            # Success.  Add email auth id so that user can sign in
            # by email too
            user = info
            auth_id = self.get_local_auth_id(user.email_pending)
            ok, info = user.add_auth_id(auth_id)
            if not ok:
                logging.error('Failed to add email auth id [' + auth_id +
                              ' ] to username [' + user.username + ']')

            # Send email verification
            user.send_email_verification(rm.verification_url)

            if config.USE_ACCESS_TOKENS:
                User.delete_access_token(rm.access_token)

            # Do any extra stuff needed upon user creation
            try:
                custom.user_created(user, rm.data)
            except:
                logging.error('Exception hit performing custom user created ' +
                              'work.  Stack trace:\n{s}'.format(
                                  s=traceback.format_exc()))

        else:
            # Failed to create new user.  Respond with conflicting properties
            # separated by a colon, converting auth_id to username
            info_set = set()
            for prop in info:
                if prop == 'auth_id':
                    info_set.add('username')
                else:
                    info_set.add(prop)
            raise ConflictException(':'.join(info_set))

        return rm