Skip to content

Instantly share code, notes, and snippets.

@Gerg
Last active December 10, 2025 19:11
Show Gist options
  • Select an option

  • Save Gerg/6051804e04ccd01f4e429b0c5e911168 to your computer and use it in GitHub Desktop.

Select an option

Save Gerg/6051804e04ccd01f4e429b0c5e911168 to your computer and use it in GitHub Desktop.
🤖 Script to inflate UAA access token by adding user to long-named groups
#!/usr/bin/env python3
"""
Script to create a large number of UAA groups and assign them to a user
to inflate their JWT access token size beyond 8KB.
Note that clients can filter what scopes are included in the token. You
may need to add "poetic-token-bloat-*" as a wildcard scope to the client
requesting the token.
🤖 This script was generated with Gemini 3 Pro, with some light modification
by Greg Cobb to make it actually work"""
import sys
import subprocess
import argparse
# Prefix to identify groups created by this script
PREFIX = "poetic-token-bloat-"
# A selection of verses (Public Domain) - "The Raven" by Edgar Allan Poe
# Used to generate deterministic, artistic group names
VERSES = [
"once-upon-a-midnight-dreary-while-i-pondered-weak-and-weary",
"over-many-a-quaint-and-curious-volume-of-forgotten-lore",
"while-i-nodded-nearly-napping-suddenly-there-came-a-tapping",
"as-of-some-one-gently-rapping-rapping-at-my-chamber-door",
"tis-some-visitor-i-muttered-tapping-at-my-chamber-door",
"only-this-and-nothing-more",
"ah-distinctly-i-remember-it-was-in-the-bleak-december",
"and-each-separate-dying-ember-wrought-its-ghost-upon-the-floor",
"eagerly-i-wished-the-morrow-vainly-i-had-sought-to-borrow",
"from-my-books-surcease-of-sorrow-sorrow-for-the-lost-lenore",
"for-the-rare-and-radiant-maiden-whom-the-angels-name-lenore",
"nameless-here-for-evermore",
"and-the-silken-sad-uncertain-rustling-of-each-purple-curtain",
"thrilled-me-filled-me-with-fantastic-terrors-never-felt-before",
"so-that-now-to-still-the-beating-of-my-heart-i-stood-repeating",
"tis-some-visitor-entreating-entrance-at-my-chamber-door",
"some-late-visitor-entreating-entrance-at-my-chamber-door",
"this-it-is-and-nothing-more",
"presently-my-soul-grew-stronger-hesitating-then-no-longer",
"sir-said-i-or-madam-truly-your-forgiveness-i-implore",
"but-the-fact-is-i-was-napping-and-so-gently-you-came-rapping",
"and-so-faintly-you-came-tapping-tapping-at-my-chamber-door",
"that-i-scarce-was-sure-i-heard-you-here-i-opened-wide-the-door",
"darkness-there-and-nothing-more",
"deep-into-that-darkness-peering-long-i-stood-there-wondering-fearing",
"doubting-dreaming-dreams-no-mortal-ever-dared-to-dream-before",
"but-the-silence-was-unbroken-and-the-stillness-gave-no-token",
"and-the-only-word-there-spoken-was-the-whispered-word-lenore",
"this-i-whispered-and-an-echo-murmured-back-the-word-lenore",
"merely-this-and-nothing-more",
"back-into-the-chamber-turning-all-my-soul-within-me-burning",
"soon-again-i-heard-a-tapping-somewhat-louder-than-before",
"surely-said-i-surely-that-is-something-at-my-window-lattice",
"let-me-see-then-what-thereat-is-and-this-mystery-explore",
"let-my-heart-be-still-a-moment-and-this-mystery-explore",
"tis-the-wind-and-nothing-more",
"open-here-i-flung-the-shutter-when-with-many-a-flirt-and-flutter",
"in-there-stepped-a-stately-raven-of-the-saintly-days-of-yore",
"not-the-least-obeisance-made-he-not-a-minute-stopped-or-stayed-he",
"but-with-mien-of-lord-or-lady-perched-above-my-chamber-door",
"perched-upon-a-bust-of-pallas-just-above-my-chamber-door",
"perched-and-sat-and-nothing-more",
"then-this-ebony-bird-beguiling-my-sad-fancy-into-smiling",
"by-the-grave-and-stern-decorum-of-the-countenance-it-wore",
"though-thy-crest-be-shorn-and-shaven-thou-i-said-art-sure-no-craven",
"ghastly-grim-and-ancient-raven-wandering-from-the-nightly-shore",
"tell-me-what-thy-lordly-name-is-on-the-night-s-plutonian-shore",
"quoth-the-raven-nevermore",
"much-i-marvelled-this-ungainly-fowl-to-hear-discourse-so-plainly",
"though-its-answer-little-meaning-little-relevancy-bore",
"for-we-cannot-help-agreeing-that-no-living-human-being",
"ever-yet-was-blessed-with-seeing-bird-above-his-chamber-door",
"bird-or-beast-upon-the-sculptured-bust-above-his-chamber-door",
"with-such-name-as-nevermore"
]
def run_uaac(args):
"""Executes a uaac command and suppresses expected errors."""
try:
# Check if the group/member already exists by capturing stderr
result = subprocess.run(
["uaac"] + args,
capture_output=True,
text=True,
check=False
)
if result.returncode != 0:
# We ignore specific errors that indicate idempotency
err = result.stderr.lower()
if "already exists" in err or \
"already a member" in err or \
"scim resource already exists" in err:
return True # Treated as success (idempotent)
print(f"Error running 'uaac {' '.join(args)}': {
result.stderr.strip()}")
return False
return True
except FileNotFoundError:
print("Error: 'uaac' command not found. Is it installed and on your PATH?")
sys.exit(1)
def generate_groups(target_kb=9):
"""Generates a list of group names until the target size is reached."""
groups = []
current_bytes = 0
target_bytes = target_kb * 1024
max_group_length = 250 # UAA limit is 255, leaving room for unique suffix
# Repeat verses if we run out
i = 0
while current_bytes < target_bytes:
verse = VERSES[i % len(VERSES)]
# Calculate how many times to repeat the verse to fill the group name
# Account for prefix length
base_name = f"{PREFIX}{verse}"
# If verse is too short, repeat it
while len(base_name) < max_group_length - 10: # buffer for suffix
base_name += f"-{verse}"
# Trim to max length if needed
base_name = base_name[:max_group_length]
# Add a counter to ensure uniqueness if we loop
suffix = f"-{i}" if i >= len(VERSES) else ""
# Ensure suffix fits
if len(base_name) + len(suffix) > 255:
base_name = base_name[:255-len(suffix)]
group_name = f"{base_name}{suffix}"
groups.append(group_name)
current_bytes += len(group_name)
i += 1
return groups
def get_existing_poetic_groups():
"""Fetches all existing groups that match the poetic prefix."""
try:
result = subprocess.run(
["uaac", "groups"],
capture_output=True,
text=True,
check=False
)
if result.returncode != 0:
print(f"Error listing groups: {result.stderr.strip()}")
return []
groups = []
for line in result.stdout.splitlines():
# In 'uaac groups' output, group names are keys (less indented)
# e.g. " my-group-name"
# followed by indented properties " id: ..."
stripped = line.strip()
if stripped.startswith(PREFIX):
# Ensure it's a group name line and not a property value
# Simple check: does it start with the prefix?
groups.append(stripped)
return list(set(groups))
except FileNotFoundError:
print("Error: 'uaac' command not found.")
sys.exit(1)
def cleanup():
"""Removes all groups created by this script."""
print("🧹 Searching for existing poetic groups to clean up...")
# Find existing groups using 'uaac groups'
groups = get_existing_poetic_groups()
if not groups:
print("No poetic groups found.")
return
print(f"Found {len(groups)} groups to delete.")
count = 0
for group in groups:
if run_uaac(["group", "delete", group]):
pass
count += 1
if count % 10 == 0:
print(f" Processed {count}/{len(groups)} deletion attempts...")
print("Cleanup complete.")
def main():
"""Main function to parse args and run group creation or cleanup."""
parser = argparse.ArgumentParser(
description="Inflate UAA token size with poetic groups."
)
parser.add_argument(
"username",
nargs="?",
help="The UAA username to assign groups to"
)
parser.add_argument(
"--cleanup",
action="store_true",
help="Remove the groups created by this script"
)
args = parser.parse_args()
if args.cleanup:
cleanup()
return
username = args.username
if not username:
if sys.stdin.isatty():
username = input("Enter username: ").strip()
else:
# Try reading from pipe
username = sys.stdin.readline().strip()
if not username:
print("Error: Username is required.")
sys.exit(1)
print(f"generating groups for user '{username}'...")
groups = generate_groups(target_kb=9)
print(f"Plan: Create {len(groups)} groups.")
success_count = 0
for i, group in enumerate(groups):
if run_uaac(["group", "add", group]):
if run_uaac(["member", "add", group, username]):
success_count += 1
if (i + 1) % 10 == 0:
print(f" Processed {i + 1}/{len(groups)} groups...")
print(f"\nDone! User '{username}' assigned to {
success_count} poetic groups.")
print("Token size should now exceed 8KB limits.")
if __name__ == "__main__":
main()
# ==============================================================================
# MIT License
#
# Copyright (c) 2025 Greg Cobb
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ==============================================================================
# ==============================================================================
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment