def _get_and_link_federated_user_info(self, username, email, internal_create=False): db_user = model.user.verify_federated_login(self._federated_service, username) if not db_user: # Fetch list of blacklisted domains blacklisted_domains = model.config.app_config.get( "BLACKLISTED_EMAIL_DOMAINS") # We must create the user in our db. Check to see if this is allowed (except for internal # creation, which is always allowed). if not internal_create and not can_create_user( email, blacklisted_domains): return (None, DISABLED_MESSAGE) valid_username = None for valid_username in generate_valid_usernames(username): if model.user.is_username_unique(valid_username): break if not valid_username: logger.error("Unable to pick a username for user: %s", username) return ( None, "Unable to pick a username. Please report this to your administrator.", ) prompts = model.user.get_default_user_prompts(features) try: db_user = model.user.create_federated_user( valid_username, email, self._federated_service, username, set_password_notification=False, email_required=self._requires_email, confirm_username=features.USERNAME_CONFIRMATION, prompts=prompts, ) except model.InvalidEmailAddressException as iae: return (None, str(iae)) else: # Update the db attributes from the federated service. if email and db_user.email != email: db_user.email = email db_user.save() return (db_user, None)
def test_can_create_user(open_creation, invite_only, email, has_invite, can_create, blacklisting_enabled, app): # Mock list of blacklisted domains blacklisted_domains = ['blacklisted.com', 'blacklisted.org'] if has_invite: inviter = model.user.get_user('devtable') team = model.team.get_organization_team('buynlarge', 'owners') model.team.add_or_invite_to_team(inviter, team, email=email) with patch('features.USER_CREATION', open_creation): with patch('features.INVITE_ONLY_USER_CREATION', invite_only): with patch('features.BLACKLISTED_EMAILS', blacklisting_enabled): if email and any(domain in email.lower() for domain in blacklisted_domains) and not blacklisting_enabled: can_create = True # blacklisted domains can be used, if blacklisting is disabled assert can_create_user(email, blacklisted_domains) == can_create
def test_can_create_user(open_creation, invite_only, email, has_invite, can_create, blacklisting_enabled, app): # Mock list of blacklisted domains blacklisted_domains = ["blacklisted.com", "blacklisted.org"] if has_invite: inviter = model.user.get_user("devtable") team = model.team.get_organization_team("buynlarge", "owners") model.team.add_or_invite_to_team(inviter, team, email=email) with patch("features.USER_CREATION", open_creation): with patch("features.INVITE_ONLY_USER_CREATION", invite_only): with patch("features.BLACKLISTED_EMAILS", blacklisting_enabled): if (email and any(domain in email.lower() for domain in blacklisted_domains) and not blacklisting_enabled): can_create = ( True # blacklisted domains can be used, if blacklisting is disabled ) assert can_create_user(email, blacklisted_domains) == can_create
def _conduct_oauth_login(auth_system, login_service, lid, lusername, lemail, metadata=None, captcha_verified=False): """ Conducts login from the result of an OAuth service's login flow and returns the status of the login, as well as the followup step. """ service_id = login_service.service_id() service_name = login_service.service_name() # Check for an existing account *bound to this service*. If found, conduct login of that account # and redirect. user_obj = model.user.verify_federated_login(service_id, lid) if user_obj is not None: return _oauthresult(user_obj=user_obj, service_name=service_name) # If the login service has a bound field name, and we have a defined internal auth type that is # not the database, then search for an existing account with that matching field. This allows # users to setup SSO while also being backed by something like LDAP. bound_field_name = login_service.login_binding_field() if auth_system.federated_service is not None and bound_field_name is not None: # Perform lookup. logger.debug('Got oauth bind field name of "%s"', bound_field_name) lookup_value = None if bound_field_name == "sub": lookup_value = lid elif bound_field_name == "username": lookup_value = lusername elif bound_field_name == "email": lookup_value = lemail if lookup_value is None: logger.error("Missing lookup value for OAuth login") return _oauthresult( service_name=service_name, error_message="Configuration error in this provider") (user_obj, err) = auth_system.link_user(lookup_value) if err is not None: logger.debug("%s %s not found: %s", bound_field_name, lookup_value, err) msg = "%s %s not found in backing auth system" % (bound_field_name, lookup_value) return _oauthresult(service_name=service_name, error_message=msg) # Found an existing user. Bind their internal auth account to this service as well. result = _attach_service(login_service, user_obj, lid, lusername) if result.error_message is not None: return result return _oauthresult(user_obj=user_obj, service_name=service_name) # Otherwise, we need to create a new user account. blacklisted_domains = app.config.get("BLACKLISTED_EMAIL_DOMAINS", []) if not can_create_user(lemail, blacklisted_domains=blacklisted_domains): error_message = "User creation is disabled. Please contact your administrator" return _oauthresult(service_name=service_name, error_message=error_message) if features.RECAPTCHA and not captcha_verified: return _oauthresult(service_name=service_name, requires_verification=True) # Try to create the user try: # Generate a valid username. new_username = None for valid in generate_valid_usernames(lusername): if model.user.get_user_or_org(valid): continue new_username = valid break requires_password = auth_system.requires_distinct_cli_password prompts = model.user.get_default_user_prompts(features) user_obj = model.user.create_federated_user( new_username, lemail, service_id, lid, set_password_notification=requires_password, metadata=metadata or {}, confirm_username=features.USERNAME_CONFIRMATION, prompts=prompts, email_required=features.MAILING, ) # Success, tell analytics analytics.track(user_obj.username, "register", {"service": service_name.lower()}) return _oauthresult(user_obj=user_obj, service_name=service_name) except model.InvalidEmailAddressException: message = ("The e-mail address {0} is already associated " "with an existing {1} account. \n" "Please log in with your username and password and " "associate your {2} account to use it in the future.") message = message.format(lemail, app.config["REGISTRY_TITLE_SHORT"], service_name) return _oauthresult(service_name=service_name, error_message=message, register_redirect=True) except model.DataModelException as ex: return _oauthresult(service_name=service_name, error_message=str(ex))
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)