Beispiel #1
0
def test_password_changes_user(client, logged_in_dummy_user):
    """Verify that password changes"""
    with fml_testing.mock_sends(
            UserUpdateV1({
                "msg": {
                    "agent": "dummy",
                    "user": "******",
                    "fields": ["password"]
                }
            })):
        result = client.post(
            '/user/dummy/settings/password',
            data={
                "username": "******",
                "current_password": "******",
                "password": "******",
                "password_confirm": "secretpw",
            },
        )
    assert_redirects_with_flash(
        result,
        expected_url="/",
        expected_message="Your password has been changed",
        expected_category="success",
    )
Beispiel #2
0
def test_user_edit_post(client, logged_in_dummy_user):
    """Test posting to the user edit page: /user/<username>/settings/profile/"""
    with fml_testing.mock_sends(
            UserUpdateV1({
                "msg": {
                    "agent":
                    "dummy",
                    "user":
                    "******",
                    "fields": [
                        'timezone',
                        'locale',
                        'ircnick',
                        'github',
                        'gitlab',
                        'rhbz_mail',
                    ],
                }
            })):
        result = client.post('/user/dummy/settings/profile/',
                             data=POST_CONTENTS)
    assert_redirects_with_flash(
        result,
        expected_url="/user/dummy/settings/profile/",
        expected_message=
        "Profile Updated: <a href=\"/user/dummy/\">view your profile</a>",
        expected_category="success",
    )
Beispiel #3
0
def _user_mod(ipa, form, user, details, redirect_to):
    with handle_form_errors(form):
        try:
            updated_user = User(
                ipa.user_mod(user.username, **details, all=True))
        except python_freeipa.exceptions.BadRequest as e:
            if e.message == 'no modifications to be performed':
                raise FormError("non_field_errors", e.message)
            else:
                app.logger.error(
                    f'An error happened while editing user {user.username}: {e.message}'
                )
                raise FormError("non_field_errors", e.message)
        flash(
            Markup(
                f'Profile Updated: <a href=\"{url_for("user", username=user.username)}\">'
                'view your profile</a>'),
            'success',
        )

        messaging.publish(
            UserUpdateV1({
                "msg": {
                    "agent": user.username,
                    "user": user.username,
                    "fields": user.diff_fields(updated_user),
                }
            }))

        return redirect(url_for(redirect_to, username=user.username))
def test_change_post(
    client, dummy_user, token_for_dummy_user, patched_lock_active, mocker
):
    logger = mocker.patch.object(current_app._get_current_object(), "logger")
    with fml_testing.mock_sends(
        UserUpdateV1(
            {"msg": {"agent": "dummy", "user": "******", "fields": ["password"]}}
        )
    ):
        result = client.post(
            f'/forgot-password/change?token={token_for_dummy_user}',
            data={"password": "******", "password_confirm": "newpassword"},
        )
    patched_lock_active["delete"].assert_called()
    assert_redirects_with_flash(
        result,
        expected_url="/",
        expected_message="Your password has been changed.",
        expected_category="success",
    )
    # Log message
    logger.info.assert_called_once()
    log_msg = logger.info.call_args[0][0]
    assert "dummy" in log_msg
    assert "newpassword" not in log_msg
Beispiel #5
0
def test_user_edit_post_no_change(client, logged_in_dummy_user):
    """Test posting to the user edit page and making no change"""
    # Do it once
    with fml_testing.mock_sends(
            UserUpdateV1({
                "msg": {
                    "agent":
                    "dummy",
                    "user":
                    "******",
                    "fields": [
                        'timezone',
                        'locale',
                        'ircnick',
                        'github',
                        'gitlab',
                        'rhbz_mail',
                    ],
                }
            })):
        result = client.post('/user/dummy/settings/profile/',
                             data=POST_CONTENTS)

    assert result.status_code == 302
    # Now do it again
    with fml_testing.mock_sends():
        result = client.post('/user/dummy/settings/profile/',
                             data=POST_CONTENTS)
    assert_form_generic_error(result, 'no modifications to be performed')
def test_change_post_with_otp(client, dummy_user, dummy_user_with_otp,
                              token_for_dummy_user, patched_lock_active):
    otp = get_otp(otp_secret_from_uri(dummy_user_with_otp.uri))
    with fml_testing.mock_sends(
            UserUpdateV1({
                "msg": {
                    "agent": "dummy",
                    "user": "******",
                    "fields": ["password"]
                }
            })):
        result = client.post(
            f'/forgot-password/change?token={token_for_dummy_user}',
            data={
                "password": "******",
                "password_confirm": "newpassword",
                "otp": otp,
            },
        )
    patched_lock_active["delete"].assert_called()
    assert_redirects_with_flash(
        result,
        expected_url="/",
        expected_message="Your password has been changed.",
        expected_category="success",
    )
Beispiel #7
0
    def test_user_update_v1(self):
        """
        Test UserUpdateV1

        The expected message here is:

        {
        "body": {
            "msg": {
            "agent": "dudemcpants",
            "user": "******",
            "fields": ["firstname", "lastname", "gpgkeyid"]
            }
        },
        "headers": {
            "fedora_messaging_schema": "noggin.user.update.v1",
            "fedora_messaging_severity": 20,
            "sent-at": "2020-03-02T08:53:38+00:00"
        },
        "id": "c795df0d-3a95-47a9-85c4-7fabf3129ddf",
        "queue": null,
        "topic": "fas.user.update"
        }

        """

        msg = UserUpdateV1({
            "msg": {
                "agent": "dudemcpants",
                "user": "******",
                "fields": ["firstname", "lastname", "gpgkeyid"],
            }
        })
        msg.validate()

        msg_dump = json.loads(message.dumps(msg))
        assert msg_dump["body"]["msg"]["agent"] == "dudemcpants"
        assert msg_dump["body"]["msg"]["user"] == "testuser"
        assert msg_dump["body"]["msg"]["fields"] == [
            "firstname",
            "lastname",
            "gpgkeyid",
        ]
        assert msg_dump["headers"][
            "fedora_messaging_schema"] == "noggin.user.update.v1"
        assert msg_dump["topic"] == "fas.user.update"
Beispiel #8
0
def test_user_settings_keys_post(client, logged_in_dummy_user):
    """Test posting to the user edit page: /user/<username>/settings/keys/"""
    with fml_testing.mock_sends(
            UserUpdateV1({
                "msg": {
                    "agent": "dummy",
                    "user": "******",
                    "fields": ['sshpubkeys']
                }
            })):
        result = client.post('/user/dummy/settings/keys/',
                             data=POST_CONTENTS_KEYS)
    assert_redirects_with_flash(
        result,
        expected_url="/user/dummy/settings/keys/",
        expected_message=
        "Profile Updated: <a href=\"/user/dummy/\">view your profile</a>",
        expected_category="success",
    )
Beispiel #9
0
def test_user_settings_keys_post_no_change(client, logged_in_dummy_user):
    """Test posting to the user edit page and making no change"""
    # Do it once
    with fml_testing.mock_sends(
            UserUpdateV1({
                "msg": {
                    "agent": "dummy",
                    "user": "******",
                    "fields": ['sshpubkeys']
                }
            })):
        result = client.post('/user/dummy/settings/keys/',
                             data=POST_CONTENTS_KEYS)

    assert result.status_code == 302
    # Now do it again
    with fml_testing.mock_sends():
        result = client.post('/user/dummy/settings/keys/',
                             data=POST_CONTENTS_KEYS)
    assert_form_generic_error(result, 'no modifications to be performed')
Beispiel #10
0
def test_user_settings_keys_post_whitespace(client, logged_in_dummy_user):
    """Test adding an SSH key with whitespace"""
    post_contents = POST_CONTENTS_KEYS.copy()
    post_contents["sshpubkeys-0"] = f" {post_contents['sshpubkeys-0']} \n "
    with fml_testing.mock_sends(
            UserUpdateV1({
                "msg": {
                    "agent": "dummy",
                    "user": "******",
                    "fields": ['sshpubkeys']
                }
            })):
        result = client.post('/user/dummy/settings/keys/', data=post_contents)
        assert_redirects_with_flash(
            result,
            expected_url="/user/dummy/settings/keys/",
            expected_message=
            "Profile Updated: <a href=\"/user/dummy/\">view your profile</a>",
            expected_category="success",
        )
    user = User(ipa_admin.user_show("dummy")["result"])
    assert user.sshpubkeys == [POST_CONTENTS_KEYS["sshpubkeys-0"]]
Beispiel #11
0
def _validate_change_pw_form(form, username, ipa=None):
    if ipa is None:
        ipa = untouched_ipa_client(current_app)

    current_password = form.current_password.data
    password = form.password.data
    otp = form.otp.data

    res = None
    try:
        res = ipa.change_password(username, password, current_password, otp)
    except python_freeipa.exceptions.PWChangeInvalidPassword:
        form.current_password.errors.append(
            _("The old password or username is not correct"))
    except python_freeipa.exceptions.PWChangePolicyError as e:
        form.password.errors.append(e.policy_error)
    except python_freeipa.exceptions.FreeIPAError as e:
        # If we made it here, we hit something weird not caught above. We didn't
        # bomb out, but we don't have IPA creds, either.
        current_app.logger.error(
            f'An unhandled error {e.__class__.__name__} happened while reseting '
            f'the password for user {username}: {e.message}')
        form.non_field_errors.errors.append(_('Could not change password.'))

    if res and res.ok:
        flash(_('Your password has been changed'), 'success')
        current_app.logger.info(f'Password for {username} was changed')
        messaging.publish(
            UserUpdateV1({
                "msg": {
                    "agent": username,
                    "user": username,
                    "fields": ["password"]
                }
            }))
    return res
Beispiel #12
0
def forgot_password_change():
    token = request.args.get('token')
    if not token:
        flash('No token provided, please request one.', 'warning')
        return redirect(url_for('.forgot_password_ask'))
    try:
        token_data = read_token(token, audience=Audience.password_reset)
    except jwt.exceptions.DecodeError:
        flash(_("The token is invalid, please request a new one."), "warning")
        return redirect(url_for('.forgot_password_ask'))
    username = token_data["sub"]
    lock = PasswordResetLock(username)
    valid_until = lock.valid_until()
    now = datetime.datetime.now()
    if valid_until is None or now > valid_until:
        lock.delete()
        flash(_("The token has expired, please request a new one."), "warning")
        return redirect(url_for('.forgot_password_ask'))
    user = User(ipa_admin.user_show(a_uid=username)['result'])
    if user.last_password_change != token_data["lpc"]:
        lock.delete()
        flash(
            _("Your password has been changed since you requested this token, please request "
              "a new one."),
            "warning",
        )
        return redirect(url_for('.forgot_password_ask'))

    form = NewPasswordForm()
    if form.validate_on_submit():
        password = form.password.data
        # Generate a random temporary number.
        temp_password = ''.join(
            random.choices(string.ascii_letters + string.digits, k=24))
        try:
            # Force change password to the random password, so that the password is not actually
            # changed to the given one in case the next step fails (because the OTP is wrong for
            # example)
            ipa_admin.user_mod(username, userpassword=temp_password)
            # Change the password as the user, so it's not expired.
            ipa = untouched_ipa_client(current_app)
            ipa.change_password(
                username,
                new_password=password,
                old_password=temp_password,
                otp=form.otp.data,
            )
        except python_freeipa.exceptions.PWChangePolicyError as e:
            lock.delete()
            flash(
                _(
                    'Your password has been changed, but it does not comply with the policy '
                    '(%(policy_error)s) and has thus been set as expired. You will be asked to '
                    'change it after logging in.',
                    policy_error=e.policy_error,
                ),
                'warning',
            )
            current_app.logger.info(
                f"Password for {username} was changed to a non-compliant password after "
                f"completing the forgotten password process.")
            # Send them to the login page, they will have to change their password
            # after login.
            return redirect(url_for('.root'))
        except python_freeipa.exceptions.PWChangeInvalidPassword:
            # The provided OTP was wrong
            current_app.logger.info(
                f"Password for {username} was changed to a random string because "
                f"the OTP token they provided was wrong.")
            # Oh noes, the token is now invalid since the user's password was changed! Let's
            # re-generate a token so they can keep going.
            user = User(ipa_admin.user_show(a_uid=username)['result'])
            token = make_token(
                {
                    "sub": user.username,
                    "lpc": user.last_password_change
                },
                audience=Audience.password_reset,
            )
            form.otp.errors.append(_("Incorrect value."))
        except python_freeipa.exceptions.FreeIPAError as e:
            # If we made it here, we hit something weird not caught above.
            current_app.logger.error(
                f'An unhandled error {e.__class__.__name__} happened while reseting '
                f'the password for user {username}: {e.message}')
            form.non_field_errors.errors.append(
                _('Could not change password, please try again.'))
        else:
            lock.delete()
            flash(_('Your password has been changed.'), 'success')
            current_app.logger.info(
                f"Password for {username} was changed after completing the forgotten "
                f"password process.")
            messaging.publish(
                UserUpdateV1({
                    "msg": {
                        "agent": username,
                        "user": username,
                        "fields": ["password"],
                    }
                }))
            return redirect(url_for('.root'))
    return render_template('forgot-password-change.html',
                           username=username,
                           form=form,
                           token=token)