Ejemplo n.º 1
0
def password_recovery_request():
    """Start password recovery process.

    Shows a form to user and allows to request password dropping via email
    Recovery tokens are stored in local MySQL db 'invitations'
    """
    form = forms.PasswordRecoveryRequest()
    if form.validate_on_submit():
        # check if user exasts in database
        try:
            utils.neo4j_api_call(
                '/users', {"email": form.email.data}, 'GET')[0]
        except (KeyError, NotFound):
            flask.flash(
                'User with that email "%s" is not registered.' %
                form.email.data,
                'error')
            exc_type, exc_value, traceback = sys.exc_info()
            flask.current_app.log_exception((exc_type, exc_value, traceback))
        else:
            hash_code = str(uuid.uuid4())
            recovery_link = flask.url_for('password_recovery_finish',
                                          recovery_hash=hash_code)
            row_mysql_queries.save_recovery(form.email.data, hash_code, 0)
            msg = mail.Message(
                'Password recovery', recipients=[form.email.data])
            msg.body = flask.render_template('RecoveryPasswordEmail/body.txt',
                                             recovery_link=recovery_link)
            utils.send_msg(msg)
            flask.flash('Recovery request was sent successfully', 'info')
    if 'wrong_email' in flask.session:
        form.email.data = flask.session['wrong_email']
    return {'form': form}
Ejemplo n.º 2
0
def delete():
    """Delete user.

    Removes user from Keystone database.

    TODO(apugachev): pass user_id in path, make form empty just for CSRF sake.
    This provides better tracking via HTTPD logs.
    """
    form = forms.DeleteUserForm()
    if form.validate_on_submit():
        keystone_user = clients.admin_clients().keystone.users.get(
            form.user_id.data)
        if keystone_user.email:
            odb_user = utils.neo4j_api_call('/users',
                                            {"email": keystone_user.email},
                                            'GET')[0]
        else:
            odb_user_list = utils.neo4j_api_call('/users', method='GET')
            odb_user = filter(lambda x: x.username == keystone_user.name,
                              odb_user_list)
        utils.neo4j_api_call('/users/%s' % odb_user['id'], method='DELETE')
        roles = keystone_user.list_roles()
        for role in roles:
            clients.admin_clients().keystone.tenants.remove_user(
                role.tenant['id'], keystone_user, role.role['id'])
        keystone_user.delete()
        flask.flash('User was deleted.', 'success')
    else:
        flask.flash('User was not deleted', 'error')
    return flask.redirect(flask.url_for('.index'))
Ejemplo n.º 3
0
def password_recovery_finish(recovery_hash):
    """
    This will be called after user clicked link in email.
    """
    try:
        id, email, hash_code, complete = \
            row_mysql_queries.get_recovery_request_by_hash(recovery_hash)
    except TypeError:
        # db returns None
        flask.abort(404)
    if complete == 1:
        flask.flash('Password recovery token is expired', 'error')
        return flask.redirect(flask.url_for('dashboard'))
    odb_user = utils.neo4j_api_call('/users', {"email": email}, 'GET')[0]
    new_hash = str(uuid.uuid4())
    # set trash password in keystone
    keystone_user = utils.get_keystone_user_by_username(odb_user['username'])
    clients.admin_clients().keystone.users.update_password(keystone_user,
                                                           new_hash)
    # set trash password in odb
    utils.neo4j_api_call('/users', {
        'id': odb_user['id'],
        'login': odb_user['login'],
        'username': odb_user['username'],
        'email': odb_user['email'],
        'passwordHash': utils.create_hashed_password(new_hash)},
        'PUT')
    # send trash password back to user
    msg = mail.Message('Password recovery', recipients=[odb_user['email']])
    msg.body = flask.render_template('RecoveryPasswordFinishEmail/body.txt',
                                     new_pass=new_hash)
    
    utils.send_msg(msg)
    flask.flash('New password was sent to you', 'success')
    return flask.redirect(flask.url_for('dashboard'))
Ejemplo n.º 4
0
def delete():
    """Delete user.

    Removes user from Keystone database.

    TODO(apugachev): pass user_id in path, make form empty just for CSRF sake.
    This provides better tracking via HTTPD logs.
    """
    form = forms.DeleteUserForm()
    if form.validate_on_submit():
        keystone_user = clients.admin_clients().keystone.users.get(
            form.user_id.data)
        if keystone_user.email:
            odb_user = utils.neo4j_api_call('/users', {
                "email": keystone_user.email
            }, 'GET')[0]
        else:
            odb_user_list = utils.neo4j_api_call('/users', method='GET')
            odb_user = filter(
                lambda x: x.username == keystone_user.name,
                odb_user_list)
        utils.neo4j_api_call('/users/%s' % odb_user['id'], method='DELETE')
        roles = keystone_user.list_roles()
        for role in roles:
            clients.admin_clients().keystone.tenants.remove_user(
                role.tenant['id'], keystone_user, role.role['id'])
        keystone_user.delete()
        flask.flash('User was deleted.', 'success')
    else:
        flask.flash('User was not deleted', 'error')
    return flask.redirect(flask.url_for('.index'))
Ejemplo n.º 5
0
def password_recovery_request():
    """Start password recovery process.

    Shows a form to user and allows to request password dropping via email
    Recovery tokens are stored in local MySQL db 'invitations'
    """
    form = forms.PasswordRecoveryRequest()
    if form.validate_on_submit():
        # check if user exasts in database
        try:
            utils.neo4j_api_call('/users', {"email": form.email.data},
                                 'GET')[0]
        except (KeyError, NotFound):
            flask.flash(
                'User with that email "%s" is not registered.' %
                form.email.data, 'error')
            exc_type, exc_value, traceback = sys.exc_info()
            flask.current_app.log_exception((exc_type, exc_value, traceback))
        else:
            hash_code = str(uuid.uuid4())
            recovery_link = flask.url_for('password_recovery_finish',
                                          recovery_hash=hash_code)
            row_mysql_queries.save_recovery(form.email.data, hash_code, 0)
            msg = mail.Message('Password recovery',
                               recipients=[form.email.data])
            msg.body = flask.render_template('RecoveryPasswordEmail/body.txt',
                                             recovery_link=recovery_link)
            utils.send_msg(msg)
            flask.flash('Recovery request was sent successfully', 'info')
    if 'wrong_email' in flask.session:
        form.email.data = flask.session['wrong_email']
    return {'form': form}
Ejemplo n.º 6
0
def finish(invitation_hash):
    """Finish invitation process.

    Check everything, create user, redirect to logout
    (it wipes out session and redirects to login).
    """
    try:
        invitation_id, email, hash_code, complete, role = \
            row_mysql_queries.get_invitation_by_hash(invitation_hash)
    except TypeError:
        # hash code not found, None returned
        # TODO(apugachev) show form to typ e invitation token
        flask.flash('Invitation token not found.', 'error')
        return flask.redirect(flask.url_for('dashboard'))

    if complete == 1:
        flask.flash('Invitation token is already used.', 'error')
        return flask.redirect(flask.url_for('dashboard'))

    form = forms.InviteRegister()
    username = email.split("@")[0]
    form.email.data = email
    username_is_taken = False
    try:
        utils.neo4j_api_call('/users', {
            "email": email
        }, 'GET')[0]
        flask.flash(
            'This username is already taken. Please, choose another one.',
            'warning')
        # NOTE(apugachev) at the beginning 'username' is HiddenField
        # now we want to allow user to edit username
        # that's why bind()
        username_field = wtf.TextField(
            'Username', [wtf.Required()]).bind(form, 'username')
        form.username = username_field
        form._fields['username'] = username_field
        username_is_taken = True
    except Exception:
        # NOTE(apugachev) user not found, success;
        # TODO(apugachev) find out what exceptions can occur and what to do
        if form.validate_on_submit():
            new_odb_user = register_user(
                form.username.data, form.email.data, form.password.data, role)
            if new_odb_user is not None:
                row_mysql_queries.update_invitation(
                    invitation_id, email, hash_code)
                # NOTE(apugachev)no flash, it gets deleted on logout
                return flask.redirect(flask.url_for('logout'))
    form.username.data = username
    return {
        'form': form,
        'email': email,
        'username': username,
        'username_is_taken': username_is_taken
    }
Ejemplo n.º 7
0
def finish(invitation_hash):
    """Finish invitation process.

    Check everything, create user, redirect to logout
    (it wipes out session and redirects to login).
    """
    try:
        invitation_id, email, hash_code, complete, role = \
            row_mysql_queries.get_invitation_by_hash(invitation_hash)
    except TypeError:
        # hash code not found, None returned
        # TODO(apugachev) show form to typ e invitation token
        flask.flash('Invitation token not found.', 'error')
        return flask.redirect(flask.url_for('dashboard'))

    if complete == 1:
        flask.flash('Invitation token is already used.', 'error')
        return flask.redirect(flask.url_for('dashboard'))

    form = forms.InviteRegister()
    username = email.split("@")[0]
    form.email.data = email
    username_is_taken = False
    try:
        utils.neo4j_api_call('/users', {"email": email}, 'GET')[0]
        flask.flash(
            'This username is already taken. Please, choose another one.',
            'warning')
        # NOTE(apugachev) at the beginning 'username' is HiddenField
        # now we want to allow user to edit username
        # that's why bind()
        username_field = wtf.TextField('Username', [wtf.Required()]).bind(
            form, 'username')
        form.username = username_field
        form._fields['username'] = username_field
        username_is_taken = True
    except Exception:
        # NOTE(apugachev) user not found, success;
        # TODO(apugachev) find out what exceptions can occur and what to do
        if form.validate_on_submit():
            new_odb_user = register_user(form.username.data, form.email.data,
                                         form.password.data, role)
            if new_odb_user is not None:
                row_mysql_queries.update_invitation(invitation_id, email,
                                                    hash_code)
                # NOTE(apugachev)no flash, it gets deleted on logout
                return flask.redirect(flask.url_for('logout'))
    form.username.data = username
    return {
        'form': form,
        'email': email,
        'username': username,
        'username_is_taken': username_is_taken
    }
Ejemplo n.º 8
0
def _login(username, password):
    try:
        odb_user = utils.neo4j_api_call('/users', {
            "email": username,
        }, 'GET')[0]
    except NotFound:
        # NOTE(apugachev) ODB returns 404 for non-existing email, lol.
        return False
    if not (odb_user['passwordHash'] ==
            utils.create_hashed_password(password)):
        return False
    username = odb_user['username']
    # NOTE(apugachev)
    # odb username is Keystone user name
    # password is the same as Keystone password
    try:
        clients.create_unscoped(username, password)
    except Unauthorized:
        return False
    flask.session['user'] = (
        flask.session['keystone_unscoped']['access']['user'])
    flask.g.is_authenticated = True
    flask.flash('You were logged in successfully.', 'success')
    user_tenants = utils.user_tenants_list(
        utils.get_keystone_user_by_username(username))
    flask.session['tenants'] = user_tenants
    # NOTE(apugachev)
    # Principal identity name is Keystone user id
    principal.identity_changed.send(
        focus.app,
        identity=principal.Identity(
            flask.session['keystone_unscoped'][
                'access']['user']['id']))
    return True
Ejemplo n.º 9
0
def configured_hostname():
    '''
    Set hostname to use in all links set via email.
    '''
    form = forms.ConfigureHostnameForm()
    if form.validate_on_submit():
        # save
        row_mysql_queries.set_configured_hostname(form.hostname.data)
        # send
        username = flask.session['user']['username']
        email = utils.neo4j_api_call(
            '/users/?username=%s' % username)[0]['email']
        msg = mail.Message(
            'New Hostname Confiured',
            recipients=[email])
        msg.body = flask.render_template(
            'ConfigureHostnameEmail/body.txt')
        utils.send_msg(msg)
        # notify
        flask.flash('Hostname %s configured' % form.hostname.data, 'success')
        # redirect
        return flask.redirect(flask.url_for('.configured_hostname'))
    return {
        'form': form,
        'title': 'Focus URL',
        'subtitle': 'Network address of Altai UI',
    }
Ejemplo n.º 10
0
def _login(username, password):
    try:
        odb_user = utils.neo4j_api_call('/users', {
            "email": username,
        }, 'GET')[0]
    except NotFound:
        # NOTE(apugachev) ODB returns 404 for non-existing email, lol.
        return False
    if not (odb_user['passwordHash']
            == utils.create_hashed_password(password)):
        return False
    username = odb_user['username']
    # NOTE(apugachev)
    # odb username is Keystone user name
    # password is the same as Keystone password
    try:
        clients.create_unscoped(username, password)
    except Unauthorized:
        return False
    flask.session['user'] = (
        flask.session['keystone_unscoped']['access']['user'])
    flask.g.is_authenticated = True
    flask.flash('You were logged in successfully.', 'success')
    user_tenants = utils.user_tenants_list(
        utils.get_keystone_user_by_username(username))
    flask.session['tenants'] = user_tenants
    # NOTE(apugachev)
    # Principal identity name is Keystone user id
    principal.identity_changed.send(
        focus.app,
        identity=principal.Identity(
            flask.session['keystone_unscoped']['access']['user']['id']))
    return True
Ejemplo n.º 11
0
def _register_in_ODB(username, email, password):
    """Register user in ODB.

    API 'create_user' call to ODB, then read new user from ODB and \
    returns it.
    """
    # new user
    utils.neo4j_api_call(
        '/users', {
            "login": "",
            "username": username,
            "email": email,
            "passwordHash": utils.create_hashed_password(password),
        }, 'POST')

    # return fresh user
    user = utils.neo4j_api_call('/users', {"email": email}, 'GET')[0]
    return user
Ejemplo n.º 12
0
def _register_in_ODB(username, email, password):
    """Register user in ODB.

    API 'create_user' call to ODB, then read new user from ODB and \
    returns it.
    """
    # new user
    utils.neo4j_api_call('/users', {
        "login": "",
        "username": username,
        "email": email,
        "passwordHash": utils.create_hashed_password(password),
    }, 'POST')

    # return fresh user
    user = utils.neo4j_api_call('/users', {
        "email": email
    }, 'GET')[0]
    return user
Ejemplo n.º 13
0
def invite():
    """Send invitation.

    Admins are allowed to invite admins and members, members - only members.
    """
    masks = row_mysql_queries.get_masks()
    form = forms.Invite()
    if form.validate_on_submit():
        # Check if required conf setting exists
        _conf = flask.current_app.config
        if not 'KEYSTONE_CONF' in _conf or not 'NEO4J_API_URL' in _conf:
            raise Exception("""No required settings:
            KEYSTONE_CONF or NEO4J_API_URL, invitations wasn't sent""", "")
        user_email = form.email.data
        if not utils.username_is_taken(user_email):
            try:
                utils.neo4j_api_call('/users', {
                    "email": user_email
                }, 'GET')[0]
                flask.flash(
                    'User with email "%s" is already registered' % user_email,
                    'error')
            except (KeyError, NotFound):
                # NOTE(apugachev) success, user does not exist
                hash_code = str(uuid.uuid4())
                domain = user_email.split('@')[-1]
                if (domain,) not in masks:
                    flask.flash('Not allowed email mask')
                else:
                    row_mysql_queries.save_invitation(
                        user_email, hash_code, form.role.data)
                    invite_link = flask.url_for('.finish', invitation_hash=hash_code)
                    msg = mail.Message('Invitation', recipients=[user_email])
                    msg.body = flask.render_template(
                        'invitations/email_body.txt', invite_link=invite_link)
                    utils.send_msg(msg)
                    flask.flash('Invitation sent successfully', 'info')
    return {
        'form': form,
        'masks': masks,
        'title': bp.name.replace('_', ' ').capitalize(),
        'subtitle': 'Send invitation'
    }
Ejemplo n.º 14
0
def invite():
    """Send invitation.

    Admins are allowed to invite admins and members, members - only members.
    """
    masks = row_mysql_queries.get_masks()
    form = forms.Invite()
    if form.validate_on_submit():
        # Check if required conf setting exists
        _conf = flask.current_app.config
        if not 'KEYSTONE_CONF' in _conf or not 'NEO4J_API_URL' in _conf:
            raise Exception(
                """No required settings:
            KEYSTONE_CONF or NEO4J_API_URL, invitations wasn't sent""", "")
        user_email = form.email.data
        if not utils.username_is_taken(user_email):
            try:
                utils.neo4j_api_call('/users', {"email": user_email}, 'GET')[0]
                flask.flash(
                    'User with email "%s" is already registered' % user_email,
                    'error')
            except (KeyError, NotFound):
                # NOTE(apugachev) success, user does not exist
                hash_code = str(uuid.uuid4())
                domain = user_email.split('@')[-1]
                if (domain, ) not in masks:
                    flask.flash('Not allowed email mask')
                else:
                    row_mysql_queries.save_invitation(user_email, hash_code,
                                                      form.role.data)
                    invite_link = flask.url_for('.finish',
                                                invitation_hash=hash_code)
                    msg = mail.Message('Invitation', recipients=[user_email])
                    msg.body = flask.render_template(
                        'invitations/email_body.txt', invite_link=invite_link)
                    utils.send_msg(msg)
                    flask.flash('Invitation sent successfully', 'info')
    return {
        'form': form,
        'masks': masks,
        'title': bp.name.replace('_', ' ').capitalize(),
        'subtitle': 'Send invitation'
    }
Ejemplo n.º 15
0
def password_recovery_finish(recovery_hash):
    """
    This will be called after user clicked link in email.
    """
    try:
        id, email, hash_code, complete = \
            row_mysql_queries.get_recovery_request_by_hash(recovery_hash)
    except TypeError:
        # db returns None
        flask.abort(404)
    if complete == 1:
        flask.flash('Password recovery token is expired', 'error')
        return flask.redirect(flask.url_for('dashboard'))
    odb_user = utils.neo4j_api_call('/users', {"email": email}, 'GET')[0]
    new_hash = str(uuid.uuid4())
    # set trash password in keystone
    keystone_user = utils.get_keystone_user_by_username(odb_user['username'])
    clients.admin_clients().keystone.users.update_password(
        keystone_user, new_hash)
    # set trash password in odb
    utils.neo4j_api_call(
        '/users', {
            'id': odb_user['id'],
            'login': odb_user['login'],
            'username': odb_user['username'],
            'email': odb_user['email'],
            'passwordHash': utils.create_hashed_password(new_hash)
        }, 'PUT')
    # send trash password back to user
    msg = mail.Message('Password recovery', recipients=[odb_user['email']])
    msg.body = flask.render_template('RecoveryPasswordFinishEmail/body.txt',
                                     new_pass=new_hash)

    utils.send_msg(msg)
    flask.flash('New password was sent to you', 'success')
    return flask.redirect(flask.url_for('dashboard'))