def confirm_email(): code = request.values["code"] user = None new_email = None try: user, new_email, old_email = model.user.confirm_user_email(code) except model.DataModelException as ex: return index("", error_info=dict(reason="confirmerror", error_message=ex.message)) if new_email: send_email_changed(user.username, old_email, new_email) change_email_future = user_analytics.change_email(old_email, new_email) change_email_future.add_done_callback( build_error_callback("Change email failed")) success, _ = common_login(user.uuid) if not success: return index("", error_info=dict(reason="confirmerror", error_message="Could not perform login")) if model.user.has_user_prompts(user): return redirect(url_for("web.updateuser")) elif new_email: return redirect( url_for("web.user_view", path=user.username, tab="settings")) else: return redirect(url_for("web.index"))
def test_common_login(username, expect_success, app): uuid = model.get_namespace_uuid(username) with app.app_context(): success, headers = common_login(uuid) assert success == expect_success if success: assert QUAY_CSRF_UPDATED_HEADER_NAME in headers
def conduct_signin(username_or_email, password, invite_code=None): needs_email_verification = False invalid_credentials = False (found_user, error_message) = authentication.verify_and_link_user(username_or_email, password) if found_user: # If there is an attached invitation code, handle it here. This will mark the # user as verified if the code is valid. if invite_code: handle_invite_code(invite_code, found_user) success, headers = common_login(found_user.uuid) if success: return {"success": True}, 200, headers else: needs_email_verification = True else: invalid_credentials = True return ( { "needsEmailVerification": needs_email_verification, "invalidCredentials": invalid_credentials, "message": error_message, }, 403, None, )
def _perform_login(user_obj, service_name): """ Attempts to login the given user, returning the Flask result of whether the login succeeded. """ success, _ = common_login(user_obj.uuid) if success: if model.user.has_user_prompts(user_obj): return redirect(url_for("web.updateuser")) else: return redirect(url_for("web.index")) else: return _render_ologin_error( service_name, "Could not login. Account may be disabled")
def confirm_recovery(): code = request.values['code'] user = model.user.validate_reset_code(code) if user is not None: success, _ = common_login(user.uuid) if not success: message = 'Could not perform login.' return render_page_template_with_routedata('message.html', message=message) return redirect(url_for('web.user_view', path=user.username, tab='settings', action='password')) else: message = 'Invalid recovery code: This code is invalid or may have already been used.' return render_page_template_with_routedata('message.html', message=message)
def post(self): """ Verifies the signed in the user with the specified credentials. """ signin_data = request.get_json() password = signin_data["password"] username = get_authenticated_user().username (result, error_message) = authentication.confirm_existing_user(username, password) if not result: return {"message": error_message, "invalidCredentials": True,}, 403 success, headers = common_login(result.uuid) if not success: return {"message": "Could not verify user.",}, 403 return {"success": True}, 200, headers
def confirm_recovery(): code = request.values["code"] user = model.user.validate_reset_code(code) if user is not None: success, _ = common_login(user.uuid) if not success: message = "Could not perform login." return render_page_template_with_routedata("message.html", message=message) return redirect( url_for("web.user_view", path=user.username, tab="settings", action="password") ) else: message = "Invalid recovery code: This code is invalid or may have already been used." return render_page_template_with_routedata("message.html", message=message)
def _perform_login(user_obj, service_name): """ Attempts to login the given user, returning the Flask result of whether the login succeeded. """ success, _ = common_login(user_obj.uuid) if success: if model.user.has_user_prompts(user_obj): return redirect( url_for("web.updateuser", _scheme=app.config["PREFERRED_URL_SCHEME"], _external=True)) else: return redirect( url_for("web.index", _scheme=app.config["PREFERRED_URL_SCHEME"], _external=True)) else: return _render_ologin_error( service_name, "Could not login. Account may be disabled")
def user_initialize(): """ Create initial user in an empty database """ # Ensure that we are using database auth. if not features.USER_INITIALIZE: response = jsonify({ "message": "Cannot initialize user, FEATURE_USER_INITIALIZE is False" }) response.status_code = 400 return response # Ensure that we are using database auth. if app.config["AUTHENTICATION_TYPE"] != "Database": response = jsonify({ "message": "Cannot initialize user in a non-database auth system" }) response.status_code = 400 return response if has_users(): response = jsonify( {"message": "Cannot initialize user in a non-empty database"}) response.status_code = 400 return response user_data = request.get_json() try: prompts = model.user.get_default_user_prompts(features) new_user = model.user.create_user( user_data["username"], user_data["password"], user_data.get("email"), auto_verify=True, email_required=features.MAILING, is_possible_abuser=False, prompts=prompts, ) success, headers = common_login(new_user.uuid) if not success: response = jsonify( {"message": "Could not login. Failed to initialize user"}) response.status_code = 403 return response result = { "username": user_data["username"], "email": user_data.get("email"), "encrypted_password": authentication.encrypt_user_password( user_data["password"]).decode("ascii"), } if user_data.get("access_token"): model.oauth.create_application( new_user, "automation", "", "", client_id=user_data["username"], description= "Application token generated via /api/v1/user/initialize", ) scope = "org:admin repo:admin repo:create repo:read repo:write super:user user:admin user:read" created, access_token = model.oauth.create_user_access_token( new_user, user_data["username"], scope) result["access_token"] = access_token return (result, 200, headers) except model.user.DataModelException as ex: response = jsonify( {"message": "Failed to initialize user: " + str(ex)}) response.status_code = 400 return response
def post(self): """ Create a new user. """ if app.config["AUTHENTICATION_TYPE"] != "Database": abort(404) user_data = request.get_json() invite_code = user_data.get("invite_code", "") existing_user = model.user.get_nonrobot_user(user_data["username"]) if existing_user: raise request_error(message="The username already exists") # Ensure an e-mail address was specified if required. if features.MAILING and not user_data.get("email"): raise request_error(message="Email address is required") # If invite-only user creation is turned on and no invite code was sent, return an error. # Technically, this is handled by the can_create_user call below as well, but it makes # a nicer error. if features.INVITE_ONLY_USER_CREATION and not invite_code: raise request_error(message="Cannot create non-invited user") # Ensure that this user can be created. blacklisted_domains = app.config.get("BLACKLISTED_EMAIL_DOMAINS", []) if not can_create_user(user_data.get("email"), blacklisted_domains=blacklisted_domains): raise request_error( message="Creation of a user account for this e-mail is disabled; please contact an administrator" ) # If recaptcha is enabled, then verify the user is a human. if features.RECAPTCHA: recaptcha_response = user_data.get("recaptcha_response", "") result = recaptcha2.verify( app.config["RECAPTCHA_SECRET_KEY"], recaptcha_response, get_request_ip() ) if not result["success"]: return {"message": "Are you a bot? If not, please revalidate the captcha."}, 400 is_possible_abuser = ip_resolver.is_ip_possible_threat(get_request_ip()) try: prompts = model.user.get_default_user_prompts(features) new_user = model.user.create_user( user_data["username"], user_data["password"], user_data.get("email"), auto_verify=not features.MAILING, email_required=features.MAILING, is_possible_abuser=is_possible_abuser, prompts=prompts, ) email_address_confirmed = handle_invite_code(invite_code, new_user) if features.MAILING and not email_address_confirmed: confirmation_code = model.user.create_confirm_email_code(new_user) send_confirmation_email(new_user.username, new_user.email, confirmation_code) return {"awaiting_verification": True} else: success, headers = common_login(new_user.uuid) if not success: return {"message": "Could not login. Is your account inactive?"}, 403 return user_view(new_user), 200, headers except model.user.DataModelException as ex: raise request_error(exception=ex)
def put(self): """ Update a users details such as password or email. """ user = get_authenticated_user() user_data = request.get_json() previous_username = None headers = None try: if "password" in user_data: logger.debug("Changing password for user: %s", user.username) log_action("account_change_password", user.username) # Change the user's password. model.user.change_password(user, user_data["password"]) # Login again to reset their session cookie. success, headers = common_login(user.uuid) if not success: raise request_error(message="Could not perform login action") if features.MAILING: send_password_changed(user.username, user.email) if "invoice_email" in user_data: logger.debug("Changing invoice_email for user: %s", user.username) model.user.change_send_invoice_email(user, user_data["invoice_email"]) if features.CHANGE_TAG_EXPIRATION and "tag_expiration_s" in user_data: logger.debug("Changing user tag expiration to: %ss", user_data["tag_expiration_s"]) model.user.change_user_tag_expiration(user, user_data["tag_expiration_s"]) if ( "invoice_email_address" in user_data and user_data["invoice_email_address"] != user.invoice_email_address ): model.user.change_invoice_email_address(user, user_data["invoice_email_address"]) if "email" in user_data and user_data["email"] != user.email: new_email = user_data["email"] if model.user.find_user_by_email(new_email): # Email already used. raise request_error(message="E-mail address already used") if features.MAILING: logger.debug( "Sending email to change email address for user: %s", user.username ) confirmation_code = model.user.create_confirm_email_code( user, new_email=new_email ) send_change_email(user.username, user_data["email"], confirmation_code) else: model.user.update_email(user, new_email, auto_verify=not features.MAILING) if features.USER_METADATA: metadata = {} for field in ("given_name", "family_name", "company", "location"): if field in user_data: metadata[field] = user_data.get(field) if len(metadata) > 0: model.user.update_user_metadata(user, metadata) # Check for username rename. A username can be renamed if the feature is enabled OR the user # currently has a confirm_username prompt. if "username" in user_data: confirm_username = model.user.has_user_prompt(user, "confirm_username") new_username = user_data.get("username") previous_username = user.username rename_allowed = features.USER_RENAME or ( confirm_username and features.USERNAME_CONFIRMATION ) username_changing = new_username and new_username != previous_username if rename_allowed and username_changing: if model.user.get_user_or_org(new_username) is not None: # Username already used. raise request_error(message="Username is already in use") user = model.user.change_username(user.id, new_username) elif confirm_username: model.user.remove_user_prompt(user, "confirm_username") except model.user.InvalidPasswordException as ex: raise request_error(exception=ex) return user_view(user, previous_username=previous_username), 200, headers
def put(self): """ Update a users details such as password or email. """ user = get_authenticated_user() user_data = request.get_json() previous_username = None headers = None try: if 'password' in user_data: logger.debug('Changing password for user: %s', user.username) log_action('account_change_password', user.username) # Change the user's password. model.user.change_password(user, user_data['password']) # Login again to reset their session cookie. success, headers = common_login(user.uuid) if not success: raise request_error( message='Could not perform login action') if features.MAILING: send_password_changed(user.username, user.email) if 'invoice_email' in user_data: logger.debug('Changing invoice_email for user: %s', user.username) model.user.change_send_invoice_email( user, user_data['invoice_email']) if features.CHANGE_TAG_EXPIRATION and 'tag_expiration_s' in user_data: logger.debug('Changing user tag expiration to: %ss', user_data['tag_expiration_s']) model.user.change_user_tag_expiration( user, user_data['tag_expiration_s']) if ('invoice_email_address' in user_data and user_data['invoice_email_address'] != user.invoice_email_address): model.user.change_invoice_email_address( user, user_data['invoice_email_address']) if 'email' in user_data and user_data['email'] != user.email: new_email = user_data['email'] if model.user.find_user_by_email(new_email): # Email already used. raise request_error(message='E-mail address already used') if features.MAILING: logger.debug( 'Sending email to change email address for user: %s', user.username) confirmation_code = model.user.create_confirm_email_code( user, new_email=new_email) send_change_email(user.username, user_data['email'], confirmation_code) else: ua_future = user_analytics.change_email( user.email, new_email) ua_future.add_done_callback( build_error_callback('Change email failed')) model.user.update_email(user, new_email, auto_verify=not features.MAILING) if features.USER_METADATA: metadata = {} for field in ('given_name', 'family_name', 'company', 'location'): if field in user_data: metadata[field] = user_data.get(field) if len(metadata) > 0: model.user.update_user_metadata(user, metadata) ua_mdata_future = user_analytics.change_metadata( user.email, **metadata) ua_mdata_future.add_done_callback( build_error_callback('Change metadata failed')) # Check for username rename. A username can be renamed if the feature is enabled OR the user # currently has a confirm_username prompt. if 'username' in user_data: confirm_username = model.user.has_user_prompt( user, 'confirm_username') new_username = user_data.get('username') previous_username = user.username rename_allowed = (features.USER_RENAME or (confirm_username and features.USERNAME_CONFIRMATION)) username_changing = new_username and new_username != previous_username if rename_allowed and username_changing: if model.user.get_user_or_org(new_username) is not None: # Username already used. raise request_error( message='Username is already in use') user = model.user.change_username(user.id, new_username) username_future = user_analytics.change_username( user.email, new_username) username_future.add_done_callback( build_error_callback('Change username failed')) elif confirm_username: model.user.remove_user_prompt(user, 'confirm_username') except model.user.InvalidPasswordException, ex: raise request_error(exception=ex)