def create_federated_user( username, email, service_id, service_ident, set_password_notification, metadata={}, email_required=True, confirm_username=True, prompts=tuple(), ): prompts = set(prompts) if confirm_username: prompts.add(UserPromptTypes.CONFIRM_USERNAME) new_user = create_user_noverify(username, email, email_required=email_required, prompts=prompts) new_user.verified = True new_user.save() FederatedLogin.create( user=new_user, service=_get_login_service(service_id), service_ident=service_ident, metadata_json=json.dumps(metadata), ) if set_password_notification: notification.create_notification("password_required", new_user) return new_user
def convert_user_to_organization(user_obj, admin_user): if user_obj.robot: raise DataModelException("Cannot convert a robot into an organization") with db_transaction(): # Change the user to an organization and disable this account for login. user_obj.organization = True user_obj.password_hash = None user_obj.save() # Clear any federated auth pointing to this user. FederatedLogin.delete().where( FederatedLogin.user == user_obj).execute() # Delete any user-specific permissions on repositories. (RepositoryPermission.delete().where( RepositoryPermission.user == user_obj).execute()) # Create a team for the owners owners_team = team.create_team("owners", user_obj, "admin") # Add the user who will admin the org to the owners team team.add_user_to_team(admin_user, owners_team) return user_obj
def create_robot(robot_shortname, parent, description="", unstructured_metadata=None): (username_valid, username_issue) = validate_username(robot_shortname) if not username_valid: raise InvalidRobotException( "The name for the robot '%s' is invalid: %s" % (robot_shortname, username_issue) ) username = format_robot_username(parent.username, robot_shortname) try: User.get(User.username == username) msg = "Existing robot with name: %s" % username logger.info(msg) raise InvalidRobotException(msg) except User.DoesNotExist: pass service = LoginService.get(name="quayrobot") try: with db_transaction(): created = User.create(username=username, email=str(uuid.uuid4()), robot=True) token = random_string_generator(length=64)() RobotAccountToken.create(robot_account=created, token=token, fully_migrated=True) FederatedLogin.create( user=created, service=service, service_ident="robot:%s" % created.id ) RobotAccountMetadata.create( robot_account=created, description=description[0:255], unstructured_json=unstructured_metadata or {}, ) return created, token except Exception as ex: raise DataModelException(ex.message)
def detach_external_login(user, service_name): try: service = LoginService.get(name=service_name) except LoginService.DoesNotExist: return FederatedLogin.delete().where(FederatedLogin.user == user, FederatedLogin.service == service).execute()
def attach_federated_login(user, service_id, service_ident, metadata=None): service = _get_login_service(service_id) FederatedLogin.create( user=user, service=service, service_ident=service_ident, metadata_json=json.dumps(metadata or {}), ) return user
def test_mark_namespace_for_deletion(initialized_db): def create_transaction(db): return db.transaction() # Create a user and then mark it for deletion. user = create_user_noverify("foobar", "*****@*****.**", email_required=False) # Add some robots. create_robot("foo", user) create_robot("bar", user) assert lookup_robot("foobar+foo") is not None assert lookup_robot("foobar+bar") is not None assert len(list(list_namespace_robots("foobar"))) == 2 # Add some federated user links. attach_federated_login(user, "google", "someusername") attach_federated_login(user, "github", "someusername") assert FederatedLogin.select().where( FederatedLogin.user == user).count() == 2 assert FederatedLogin.select().where( FederatedLogin.service_ident == "someusername").exists() # Mark the user for deletion. queue = WorkQueue("testgcnamespace", create_transaction) mark_namespace_for_deletion(user, [], queue) # Ensure the older user is still in the DB. older_user = User.get(id=user.id) assert older_user.username != "foobar" # Ensure the robots are deleted. with pytest.raises(InvalidRobotException): assert lookup_robot("foobar+foo") with pytest.raises(InvalidRobotException): assert lookup_robot("foobar+bar") assert len(list(list_namespace_robots(older_user.username))) == 0 # Ensure the federated logins are gone. assert FederatedLogin.select().where( FederatedLogin.user == user).count() == 0 assert (not FederatedLogin.select().where( FederatedLogin.service_ident == "someusername").exists()) # Ensure we can create a user with the same namespace again. new_user = create_user_noverify("foobar", "*****@*****.**", email_required=False) assert new_user.id != user.id # Ensure the older user is still in the DB. assert User.get(id=user.id).username != "foobar"
def list_federated_logins(user): selected = FederatedLogin.select(FederatedLogin.service_ident, LoginService.name, FederatedLogin.metadata_json) joined = selected.join(LoginService) return joined.where(LoginService.name != "quayrobot", FederatedLogin.user == user)
def regenerate_robot_token(robot_shortname, parent): robot_username = format_robot_username(parent.username, robot_shortname) robot, metadata = lookup_robot_and_metadata(robot_username) password = random_string_generator(length=64)() robot.email = str(uuid4()) robot.uuid = str(uuid4()) service = LoginService.get(name="quayrobot") login = FederatedLogin.get(FederatedLogin.user == robot, FederatedLogin.service == service) login.service_ident = "robot:%s" % (robot.id) try: token_data = RobotAccountToken.get(robot_account=robot) except RobotAccountToken.DoesNotExist: token_data = RobotAccountToken.create(robot_account=robot) token_data.token = password with db_transaction(): token_data.save() login.save() robot.save() return robot, password, metadata
def _delete_user_linked_data(user): if user.organization: # Delete the organization's teams. with db_transaction(): for team in Team.select().where(Team.organization == user): team.delete_instance(recursive=True) # Delete any OAuth approvals and tokens associated with the user. with db_transaction(): for app in OAuthApplication.select().where( OAuthApplication.organization == user): app.delete_instance(recursive=True) else: # Remove the user from any teams in which they are a member. TeamMember.delete().where(TeamMember.user == user).execute() # Delete any repository buildtriggers where the user is the connected user. with db_transaction(): triggers = RepositoryBuildTrigger.select().where( RepositoryBuildTrigger.connected_user == user) for trigger in triggers: trigger.delete_instance(recursive=True, delete_nullable=False) with db_transaction(): quotas = namespacequota.get_namespace_quota_list(user.username) for quota in quotas: namespacequota.delete_namespace_quota(quota) # Delete any mirrors with robots owned by this user. with db_transaction(): robots = list(list_namespace_robots(user.username)) RepoMirrorConfig.delete().where( RepoMirrorConfig.internal_robot << robots).execute() # Delete any robots owned by this user. with db_transaction(): robots = list(list_namespace_robots(user.username)) for robot in robots: robot.delete_instance(recursive=True, delete_nullable=True) # Null out any service key approvals. We technically lose information here, but its better than # falling and only occurs if a superuser is being deleted. ServiceKeyApproval.update(approver=None).where( ServiceKeyApproval.approver == user).execute() # Delete any federated user links. FederatedLogin.delete().where(FederatedLogin.user == user).execute()
def get_federated_logins(user_ids, service_name): """ Returns all federated logins for the given user ids under the given external service. """ if not user_ids: return [] return (FederatedLogin.select().join(User).switch(FederatedLogin).join( LoginService).where(FederatedLogin.user << user_ids, LoginService.name == service_name))
def upgrade(tables, tester, progress_reporter): op = ProgressWrapper(original_op, progress_reporter) # ### commands auto generated by Alembic - please adjust! ### op.drop_index("oauthaccesstoken_refresh_token", table_name="oauthaccesstoken") op.drop_column(u"oauthaccesstoken", "refresh_token") op.drop_column("accesstoken", "code") op.drop_column("appspecificauthtoken", "token_code") op.drop_column("oauthaccesstoken", "access_token") op.drop_column("oauthapplication", "client_secret") op.drop_column("oauthauthorizationcode", "code") op.drop_column("repositorybuildtrigger", "private_key") op.drop_column("repositorybuildtrigger", "auth_token") # ### end Alembic commands ### # Overwrite all plaintext robot credentials. from app import app if app.config.get("SETUP_COMPLETE", False) or tester.is_testing(): while True: try: robot_account_token = RobotAccountToken.get(fully_migrated=False) logger.debug("Found robot account token %s migrate", robot_account_token.id) robot_account = robot_account_token.robot_account assert robot_account.robot result = ( User.update(email=str(uuid.uuid4())) .where( User.id == robot_account.id, User.robot == True, User.uuid == robot_account.uuid, ) .execute() ) assert result == 1 try: federated_login = FederatedLogin.get(user=robot_account) assert federated_login.service.name == "quayrobot" federated_login.service_ident = "robot:%s" % robot_account.id federated_login.save() except FederatedLogin.DoesNotExist: pass robot_account_token.fully_migrated = True robot_account_token.save() logger.debug("Finished migrating robot account token %s", robot_account_token.id) except RobotAccountToken.DoesNotExist: break
def get_federated_team_member_mapping(team, login_service_name): """ Returns a dict of all federated IDs for all team members in the team whose users are bound to the login service within the given name. The dictionary is from federated service identifier (username) to their Quay User table ID. """ login_service = LoginService.get(name=login_service_name) query = (FederatedLogin.select( FederatedLogin.service_ident, User.id).join(User).join(TeamMember).join(Team).where( Team.id == team, User.robot == False, FederatedLogin.service == login_service)) return dict(query.tuples())
def verify_federated_login(service_id, service_ident): try: found = (FederatedLogin.select( FederatedLogin, User).join(LoginService).switch(FederatedLogin).join(User).where( FederatedLogin.service_ident == service_ident, LoginService.name == service_id).get()) # Mark that the user was accessed. _basequery.update_last_accessed(found.user) return found.user except FederatedLogin.DoesNotExist: return None
def upgrade(tables, tester, progress_reporter): op = ProgressWrapper(original_op, progress_reporter) # ### commands auto generated by Alembic - please adjust! ### op.drop_index("oauthaccesstoken_refresh_token", table_name="oauthaccesstoken") op.drop_column(u"oauthaccesstoken", "refresh_token") op.drop_column("accesstoken", "code") op.drop_column("appspecificauthtoken", "token_code") op.drop_column("oauthaccesstoken", "access_token") op.drop_column("oauthapplication", "client_secret") op.drop_column("oauthauthorizationcode", "code") op.drop_column("repositorybuildtrigger", "private_key") op.drop_column("repositorybuildtrigger", "auth_token") # ### end Alembic commands ### # Overwrite all plaintext robot credentials. from app import app if app.config.get("SETUP_COMPLETE", False) or tester.is_testing(): while True: try: robot_account_token = RobotAccountToken.get( fully_migrated=False) robot_account = robot_account_token.robot_account robot_account.email = str(uuid.uuid4()) robot_account.save() federated_login = FederatedLogin.get(user=robot_account) federated_login.service_ident = "robot:%s" % robot_account.id federated_login.save() robot_account_token.fully_migrated = True robot_account_token.save() except RobotAccountToken.DoesNotExist: break
def upgrade(tables, tester, progress_reporter): op = ProgressWrapper(original_op, progress_reporter) # ### commands auto generated by Alembic - please adjust! ### op.drop_index('oauthaccesstoken_refresh_token', table_name='oauthaccesstoken') op.drop_column(u'oauthaccesstoken', 'refresh_token') op.drop_column('accesstoken', 'code') op.drop_column('appspecificauthtoken', 'token_code') op.drop_column('oauthaccesstoken', 'access_token') op.drop_column('oauthapplication', 'client_secret') op.drop_column('oauthauthorizationcode', 'code') op.drop_column('repositorybuildtrigger', 'private_key') op.drop_column('repositorybuildtrigger', 'auth_token') # ### end Alembic commands ### # Overwrite all plaintext robot credentials. while True: try: robot_account_token = RobotAccountToken.get(fully_migrated=False) robot_account = robot_account_token.robot_account robot_account.email = str(uuid.uuid4()) robot_account.save() federated_login = FederatedLogin.get(user=robot_account) federated_login.service_ident = 'robot:%s' % robot_account.id federated_login.save() robot_account_token.fully_migrated = True robot_account_token.save() except RobotAccountToken.DoesNotExist: break