def test_ipa_untouched_client(client): with client.session_transaction() as sess: ipa = untouched_ipa_client(current_app) assert ipa is not None assert 'securitas_session' not in sess assert 'securitas_ipa_server_hostname' not in sess assert 'securitas_username' not in sess
def _validate_change_pw_form(form, username, ipa=None): if ipa is None: ipa = untouched_ipa_client(app) current_password = form.current_password.data password = form.password.data res = None try: res = ipa.change_password(username, password, current_password) 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. app.logger.error( f'An unhandled error {e.__class__.__name__} happened while reseting ' f'the password for user {username}: {e.message}') form.errors['non_field_errors'] = ['Could not change password.'] if res and res.ok: flash('Your password has been changed', 'success') app.logger.info(f'Password for {username} was changed') return res
def password_reset(): if request.method == 'GET': return render_template('password-reset.html') username = request.form.get('username') current_password = request.form.get('current_password') password = request.form.get('password') password_confirm = request.form.get('password_confirm') if not all([username, current_password, password, password_confirm]): flash('Please fill in all fields to reset your password', 'red') return redirect(url_for('password_reset')) if password != password_confirm: flash('Password and confirmation did not match.', 'red') return redirect(url_for('password_reset')) ipa = untouched_ipa_client(app) res = None try: res = ipa.change_password(username, password, current_password) except python_freeipa.exceptions.PWChangePolicyError as e: flash( 'Failed to reset your password (policy error): %s' % str(e.policy_error), 'red') return redirect(url_for('password_reset')) except python_freeipa.exceptions.PWChangeInvalidPassword: flash( 'Failed to reset your password (invalid current password).', 'red') return redirect(url_for('password_reset')) except python_freeipa.exceptions.FreeIPAError as e: flash('Failed to reset your password: %s' % str(e), 'red') return redirect(url_for('password_reset')) if res and res.ok: flash('Your password has been changed, ' \ 'please try to log in with the new one now.', 'green') return redirect(url_for('root')) # If we made it here, we hit something weird not caught above. We didn't # bomb out, but we don't have a valid/good response from IPA. Boot the user # back to /. flash('Something went wrong and your password might not have been ' \ 'changed. Please try again, or report the issue to the system ' \ 'administrator.', 'red') return redirect(url_for('root'))
def _make_user(name): now = datetime.datetime.utcnow().replace(microsecond=0) password = f'{name}_password' ipa_admin.user_add( name, name.title(), 'User', f'{name.title()} User', user_password=password, login_shell='/bin/bash', fascreationtime=f"{now.isoformat()}Z", ) ipa = untouched_ipa_client(app) ipa.change_password(name, password, password) created_users.append(name)
def register(): first_name = request.form.get('first_name') last_name = request.form.get('last_name') username = request.form.get('username') password = request.form.get('password') password_confirm = request.form.get('password_confirm') if not all([first_name, last_name, username, password, password_confirm]): flash('Please fill in all fields to register an account.', 'red') return redirect(url_for('root')) if password != password_confirm: flash('Password and confirmation did not match.', 'red') return redirect(url_for('root')) try: ipa_admin.user_add( username, first_name, last_name, '%s %s' % (first_name, last_name), # TODO ??? user_password=password, login_shell='/bin/bash') # Now we fake a password change, so that it's not immediately expired. # This also logs the user in right away. ipa = untouched_ipa_client(app) ipa.change_password(username, password, password) except python_freeipa.exceptions.FreeIPAError as e: print(e) flash( 'An error occurred while creating the account, please try again.', 'red') return redirect(url_for('root')) flash( 'Congratulations, you now have an account! Go ahead and sign in to ' \ 'proceed.', 'green') return redirect(url_for('root'))
def test_change_recent_password_change( client, dummy_user, dummy_group, token_for_dummy_user, no_password_min_time, patched_lock_active, ): ipa_admin.group_add_member("dummy-group", users="dummy") ipa = untouched_ipa_client(current_app) ipa.change_password("dummy", "dummy_password", "dummy_password") result = client.get(f'/forgot-password/change?token={token_for_dummy_user}') patched_lock_active["delete"].assert_called_once() assert_redirects_with_flash( result, expected_url="/forgot-password/ask", expected_message=( "Your password has been changed since you requested this token, please " "request a new one." ), expected_category="warning", )
def register(): form = RegisterUserForm() if form.validate_on_submit(): username = form.username.data password = form.password.data now = datetime.datetime.utcnow().replace(microsecond=0) # First, create the user. try: ipa_admin.user_add( username, form.firstname.data, form.lastname.data, f'{form.firstname.data} {form.lastname.data}', # TODO ??? user_password=password, login_shell='/bin/bash', fascreationtime=f"{now.isoformat()}Z", faslocale=guess_locale(), fastimezone=app.config["USER_DEFAULTS"]["user_timezone"], ) except python_freeipa.exceptions.DuplicateEntry as e: # the username already exists form.username.errors.append(e.message) except python_freeipa.exceptions.ValidationError as e: # for example: invalid username. We don't know which field to link it to if e.message.startswith("invalid 'login': "******"invalid 'login': ") :]) else: app.logger.error( f'An unhandled invalid value happened while registering user ' f'{username}: {e.message}' ) form.errors['non_field_errors'] = [e.message] except python_freeipa.exceptions.FreeIPAError as e: app.logger.error( f'An unhandled error {e.__class__.__name__} happened while registering user ' f'{username}: {e.message}' ) form.errors['non_field_errors'] = [ 'An error occurred while creating the account, please try again.' ] else: # User creation succeeded. Now we fake a password change, so that it's not immediately # expired. This also logs the user in right away. try: ipa = untouched_ipa_client(app) ipa.change_password(username, password, password) except python_freeipa.exceptions.PWChangePolicyError as e: # The user is created but the password does not match the policy. Alert the user # and ask them to change their password. flash( f'Your account has been created, but the password you chose does not comply ' f'with the policy ({e.policy_error}) and has thus been set as expired. ' f'You will be asked to change it after logging in.', 'warning', ) # Send them to the login page, they will have to change their password # after login. return redirect(url_for('login')) except python_freeipa.exceptions.FreeIPAError as e: app.logger.error( f'An unhandled error {e.__class__.__name__} happened while changing initial ' f'password for user {username}: {e.message}' ) # At this point the user has been created, they can't register again. Send them to # the login page with an appropriate warning. flash( f'Your account has been created, but an error occurred while setting your ' f'password ({e.message}). You may need to change it after logging in.', 'warning', ) return redirect(url_for('login')) else: flash( 'Congratulations, you now have an account! Go ahead and sign in to proceed.', 'success', ) return redirect(url_for('root')) return render_template('register.html', register_form=form)
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 = jwt.decode(token, app.config["SECRET_KEY"], algorithms=["HS256"]) 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["username"] 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 = ipa_admin.user_show(username) if user["krblastpwdchange"] != token_data["last_change"]: 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 try: ipa_admin.user_mod(username, userpassword=password) # Change the password as the user, so it's not expired. ipa = untouched_ipa_client(app) ipa.change_password(username, password, password) except python_freeipa.exceptions.PWChangePolicyError as e: lock.delete() flash( f'Your password has been changed, but it does not comply with ' f'the policy ({e.policy_error}) and has thus been set as expired. ' f'You will be asked to change it after logging in.', 'warning', ) 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('login')) except python_freeipa.exceptions.FreeIPAError as e: # If we made it here, we hit something weird not caught above. app.logger.error( f'An unhandled error {e.__class__.__name__} happened while reseting ' f'the password for user {username}: {e.message}') form.errors['non_field_errors'] = [ 'Could not change password, please try again.' ] else: lock.delete() flash('Your password has been changed.', 'success') app.logger.info( f"Password for {username} was changed after completing the forgotten " f"password process.") return redirect(url_for('root')) return render_template('forgot-password-change.html', username=username, form=form, token=token)