def test_user_private(client, logged_in_dummy_user, make_user): """A user with fasIsPrivate should be anonymized as much as possible.""" make_user("testuser") ipa_admin.user_mod("testuser", fasisprivate=True) result = client.get('/user/testuser/') assert result.status_code == 200 page = BeautifulSoup(result.data, 'html.parser') # print(page.prettify()) user_fullname = page.select_one("#user_fullname") assert user_fullname is not None assert user_fullname.get_text(strip=True) == "testuser" user_attributes = page.select_one("ul#user_attributes") assert user_attributes is not None assert len(user_attributes.find_all("li")) == 0
def dummy_user_with_gpg_key(client, dummy_user): ipa_admin.user_mod(a_uid="dummy", fasgpgkeyid=["dummygpgkeyid"])
def activate_account(): register_url = f"{url_for('.root')}?tab=register" token_string = request.args.get('token') if not token_string: flash(_('No token provided, please check your email validation link.'), 'warning') return redirect(register_url) try: token = read_token(token_string, audience=Audience.email_validation) except jwt.exceptions.DecodeError: flash(_("The token is invalid, please register again."), "warning") return redirect(register_url) except jwt.exceptions.ExpiredSignatureError: flash(_("This token is no longer valid, please register again."), "warning") return redirect(register_url) try: user = User(ipa_admin.stageuser_show(token["sub"])["result"]) except python_freeipa.exceptions.NotFound: flash(_("This user cannot be found, please register again."), "warning") return redirect(register_url) token_mail = token["mail"] if not user.mail == token_mail: current_app.logger.error( f'User {user.username} tried to validate a token for address {token_mail} while they ' f'are registered with address {user.mail}, something fishy may be going on.' ) flash( _("The username and the email address don't match the token you used, " "please register again."), "warning", ) return redirect(register_url) form = PasswordSetForm() if form.validate_on_submit(): with handle_form_errors(form): password = form.password.data # First we activate the stage user try: ipa_admin.stageuser_activate(user.username) except python_freeipa.exceptions.FreeIPAError as e: current_app.logger.error( f'An unhandled error {e.__class__.__name__} happened while activating ' f'stage user {user.username}: {e.message}') raise FormError( "non_field_errors", _("Something went wrong while creating your account, " "please try again later."), ) # User activation succeeded. Send signal. user_registered.send(user, request=request._get_current_object()) # Now we set the password. try: # First, set it as an admin. This will mark it as expired. ipa_admin.user_mod(user.username, userpassword=password) # And now we set it again as the user, so it is not expired any more. ipa = untouched_ipa_client(current_app) ipa.change_password(user.username, new_password=password, old_password=password) except python_freeipa.exceptions.PWChangePolicyError as e: # The user is active but the password does not match the policy. # Tell the user what's going to happen. flash( _( 'Your account has been created, but the password you chose 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', ) return redirect(url_for(".root")) except python_freeipa.exceptions.ValidationError as e: # for example: invalid username. We don't know which field to link it to _handle_registration_validation_error(user.username, e) except python_freeipa.exceptions.FreeIPAError as e: current_app.logger.error( f'An unhandled error {e.__class__.__name__} happened while changing initial ' f'password for user {user.username}: {e.message}') # At this point the user has been activated, they can't register again. Send them to # the login page with an appropriate warning. flash( _( 'Your account has been created, but an error occurred while setting your ' 'password (%(message)s). You may need to change it after logging in.', message=e.message, ), 'warning', ) return redirect(url_for(".root")) # Try to log them in directly, so they don't have to type their password again. try: ipa = maybe_ipa_login(current_app, session, user.username, password) except python_freeipa.exceptions.FreeIPAError: ipa = None if ipa: flash( _( 'Congratulations, your account has been created! Welcome, %(name)s.', name=user.name, ), 'success', ) else: # No shortcut for you, you'll have to login properly (maybe the password is # expired). flash( _('Congratulations, your account has been created! Go ahead and sign in ' 'to proceed.'), 'success', ) return redirect(url_for('.root')) return render_template('registration-activation.html', user=user, 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 = 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)