Skip to content

Commit 61babc4

Browse files
committed
fix: correct Heimdall principal claims pattern for client IDs
Change the client ID pattern from 'clients@{client_id}' to '{client_id}@Clients' to match the Auth0 convention used in the platform. - Updated JWT generation script to use correct suffix removal - Fixed Python JWT generator to handle @Clients suffix - Updated all YAML playbooks with corrected principal patterns Related: LFXV2-922 🤖 Generated with [GitHub Copilot](https://github.com/features/copilot) (via Zed) Signed-off-by: Eric Searcy <[email protected]>
1 parent 725d97d commit 61babc4

File tree

9 files changed

+35
-67
lines changed

9 files changed

+35
-67
lines changed

playbooks/committees/base_committees/buf_committees.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ buf_committees:
1414
url: {{ environ.COMMITTEES_URL | default("http://lfx-v2-committee-service.lfx.svc.cluster.local:8080/committees") }}
1515
method: POST
1616
headers:
17-
Authorization: !jwt bearer=true,aud=lfx-v2-committee-service,principal=clients@m2m_helper
17+
Authorization: !jwt bearer=true,aud=lfx-v2-committee-service,principal=m2m_helper@clients
1818
steps:
1919
- json:
2020
name: Governing Board
@@ -60,7 +60,7 @@ buf_board_members:
6060
url: !sub "{{ environ.COMMITTEES_URL | default('http://lfx-v2-committee-service.lfx.svc.cluster.local:8080/committees') }}/${ buf_committees.steps[?json.name == 'Governing Board']._response.uid | [0] }/members?v=1"
6161
method: POST
6262
headers:
63-
Authorization: !jwt bearer=true,aud=lfx-v2-committee-service,principal=clients@m2m_helper
63+
Authorization: !jwt bearer=true,aud=lfx-v2-committee-service,principal=m2m_helper@clients
6464
steps:
6565
{% for i in range(8) %}
6666
- json:

playbooks/projects/base_projects/1_tlf.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ base_projects:
77
url: {{ environ.PROJECTS_URL | default("http://lfx-v2-project-service.lfx.svc.cluster.local:8080/projects") }}
88
method: POST
99
headers:
10-
Authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
10+
Authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
1111
steps:
1212
- json:
1313
slug: tlf

playbooks/projects/base_projects/2_incorporated.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extra_incorporated:
1010
url: {{ environ.PROJECTS_URL | default("http://lfx-v2-project-service.lfx.svc.cluster.local:8080/projects") }}
1111
method: POST
1212
headers:
13-
Authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
13+
Authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
1414
steps:
1515
{% for outer in range(12) %}
1616
{% set project_name = fake.catch_phrase().title() %}

playbooks/projects/base_projects/3_umbrellas.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sample_umbrella_buf:
77
url: {{ environ.PROJECTS_URL | default("http://lfx-v2-project-service.lfx.svc.cluster.local:8080/projects") }}
88
method: POST
99
headers:
10-
Authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
10+
Authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
1111
steps:
1212
- json:
1313
slug: buf
@@ -49,7 +49,7 @@ sample_umbrella_iubp:
4949
url: {{ environ.PROJECTS_URL | default("http://lfx-v2-project-service.lfx.svc.cluster.local:8080/projects") }}
5050
method: POST
5151
headers:
52-
Authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
52+
Authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
5353
steps:
5454
- json:
5555
slug: industry-umbrella-branded-projects-iubp

playbooks/projects/extra_projects/n_depth.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ n_depth:
1515
url: {{ environ.PROJECTS_URL | default("http://lfx-v2-project-service.lfx.svc.cluster.local:8080/projects") }}
1616
method: POST
1717
headers:
18-
Authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
18+
Authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
1919
steps:
2020
{% set project_name = fake.catch_phrase().title() %}
2121
- json:

playbooks/projects/root_project_access/global_groups.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ global_groups:
2929
object: "team:project_super_admins"
3030
# A M2M principal from lfx-v2-helm's values.yaml
3131
# (authelia.authelia_client_generation.clients).
32-
- user: "user:clients@lfx_m2m"
32+
- user: "user:lfx_m2m@clients"
3333
relation: member
3434
object: "team:project_super_admins"
3535
# Attach the global group with the above members to the ROOT

playbooks/v1_meetings/umbrella_board_meeting/board_meeting.yaml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ buf_board_meeting_create:
3636
action: created
3737
headers:
3838
authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal={{ fake.user_name() }},email={{ fake.email() }}
39-
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
39+
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
4040
data:
4141
{% set meeting_id = fake.pyint(min_value=10000000000, max_value=99999999999) %}
4242
{# Calculate initial meeting time based on `total_past_meetings`. #}
@@ -162,7 +162,7 @@ buf_board_meeting_committee_participants_create:
162162
action: created
163163
headers:
164164
authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal={{ fake.user_name() }},email={{ fake.email() }}
165-
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
165+
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
166166
data:
167167
# Renamed from `registrant_id` in v1.
168168
id: "{{ fake.uuid4() }}"
@@ -256,7 +256,7 @@ buf_board_past_meeting_{{ past_meeting_index }}_create:
256256
action: created
257257
headers:
258258
authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal={{ fake.user_name() }},email={{ fake.email() }}
259-
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
259+
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
260260
data:
261261
# Renamed from `meeting_and_occurrence_id` in v1.
262262
id: "{{ meeting_id }}-{{ occurrence_id }}"
@@ -354,7 +354,7 @@ buf_board_past_meeting_{{ past_meeting_index }}_recording_create:
354354
action: created
355355
headers:
356356
authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal={{ fake.user_name() }},email={{ fake.email() }}
357-
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
357+
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
358358
data:
359359
# Renamed from `meeting_and_occurrence_id` in v1.
360360
id: "{{ meeting_id }}-{{ occurrence_id }}"
@@ -454,7 +454,7 @@ buf_board_past_meeting_{{ past_meeting_index }}_transcript_create:
454454
action: created
455455
headers:
456456
authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal={{ fake.user_name() }},email={{ fake.email() }}
457-
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
457+
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
458458
data:
459459
# Renamed from `meeting_and_occurrence_id` in v1.
460460
id: "{{ meeting_id }}-{{ occurrence_id }}"
@@ -547,7 +547,7 @@ buf_board_past_meeting_{{ past_meeting_index }}_summary_create:
547547
action: created
548548
headers:
549549
authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal={{ fake.user_name() }},email={{ fake.email() }}
550-
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
550+
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
551551
data:
552552
summary_details:
553553
{% for i in range(fake.pyint(min_value=8, max_value=12)) %}
@@ -639,7 +639,7 @@ buf_board_past_meeting_{{ past_meeting_index }}_participants_create:
639639
action: created
640640
headers:
641641
authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal={{ fake.user_name() }},email={{ fake.email() }}
642-
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
642+
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
643643
data:
644644
# v2 attributes for convenience.
645645
is_invited: true
@@ -728,7 +728,7 @@ buf_board_past_meeting_{{ past_meeting_index }}_participant_guests_create:
728728
action: created
729729
headers:
730730
authorization: !jwt bearer=true,aud=lfx-v2-project-service,principal={{ fake.user_name() }},email={{ fake.email() }}
731-
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=clients@m2m_helper
731+
x-on-behalf-of: !jwt bearer=true,aud=lfx-v2-project-service,principal=m2m_helper@clients
732732
data:
733733
# v2 attributes for convenience.
734734
is_invited: false

scripts/mock-heimdall-jwt.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jwt encode \
4040
--jti "$(uuidgen)" \
4141
--payload "aud=$aud" \
4242
--payload "iss=heimdall" \
43-
--payload "sub=${principal#clients@}" \
43+
--payload "sub=${principal%@clients}" \
4444
--payload "principal=$principal" \
4545
--secret "@${pem_temp_dir}/signer.pem" \
4646
"${payload}"

src/lfx_v2_mockdata/__init__.py

Lines changed: 18 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,7 @@ class UploadMockDataArgs(BaseModel):
8181
)
8282
jinja_env: contextvars.ContextVar[Environment] = contextvars.ContextVar("jinja_env")
8383
args: contextvars.ContextVar[UploadMockDataArgs] = contextvars.ContextVar("args")
84-
retries_remaining: contextvars.ContextVar[int] = contextvars.ContextVar(
85-
"retries_remaining"
86-
)
84+
retries_remaining: contextvars.ContextVar[int] = contextvars.ContextVar("retries_remaining")
8785

8886
# NATS connection variables.
8987
nats_client: None | NatsClient = None
@@ -180,9 +178,7 @@ def evaluate(self):
180178
# Attempt to evaluate expression against data context.
181179
value = jmespath.search(self.expression, data_context)
182180
if value is None:
183-
raise AttributeError(
184-
f"JMESPath expression '{self.expression}' not found in data"
185-
)
181+
raise AttributeError(f"JMESPath expression '{self.expression}' not found in data")
186182
return value
187183

188184

@@ -246,9 +242,7 @@ def replace_placeholder(match):
246242
# Attempt to evaluate expression against data context.
247243
value = jmespath.search(expression, data_context)
248244
if value is None:
249-
raise AttributeError(
250-
f"JMESPath expression '{expression}' not found in data"
251-
)
245+
raise AttributeError(f"JMESPath expression '{expression}' not found in data")
252246
return str(value)
253247

254248
# Find and replace all ${...} patterns with their evaluated values.
@@ -263,7 +257,7 @@ class JWTGenerator(yaml.YAMLObject):
263257
Arguments are passed as key=value pairs separated by commas.
264258
265259
Example:
266-
!jwt aud=lfx-v2-project-service,principal=clients@m2m_helper,\\
260+
!jwt aud=lfx-v2-project-service,principal=m2m_helper@clients,\
267261
268262
"""
269263

@@ -331,7 +325,7 @@ def generate_jwt(self) -> str:
331325
payload = {
332326
"aud": audience,
333327
"iss": "heimdall",
334-
"sub": principal.replace("clients@", ""), # Remove clients@ prefix.
328+
"sub": principal.replace("@clients", ""), # Remove @clients suffix.
335329
"principal": principal,
336330
"exp": now_int + 300, # 5 minutes expiry.
337331
"nbf": now_int, # Valid from now.
@@ -349,9 +343,7 @@ def generate_jwt(self) -> str:
349343
)
350344
# Ensure we have an RSA private key for PS256 algorithm.
351345
if not isinstance(loaded_key, rsa.RSAPrivateKey):
352-
raise ValueError(
353-
"JWT signing requires an RSA private key for PS256 algorithm"
354-
)
346+
raise ValueError("JWT signing requires an RSA private key for PS256 algorithm")
355347
private_key = loaded_key
356348
except Exception as e:
357349
raise ValueError(f"Failed to load RSA private key: {e}") from e
@@ -385,9 +377,7 @@ def _get_key_id(self, cli_args) -> str:
385377
return _jwks_kid_cache
386378

387379
# Fetch from Heimdall JWKS endpoint.
388-
jwks_url = (
389-
"http://lfx-platform-heimdall.lfx.svc.cluster.local:4457/.well-known/jwks"
390-
)
380+
jwks_url = "http://lfx-platform-heimdall.lfx.svc.cluster.local:4457/.well-known/jwks"
391381
try:
392382
response = requests.get(jwks_url, timeout=10)
393383
response.raise_for_status()
@@ -542,9 +532,7 @@ def yaml_render(template_dir, yaml_file):
542532
env.globals["fake"] = fake
543533
env.globals["timedelta"] = datetime.timedelta
544534
env.globals["now_z"] = (
545-
lambda: datetime.datetime.now(datetime.UTC)
546-
.isoformat("T")
547-
.replace("+00:00", "Z")
535+
lambda: datetime.datetime.now(datetime.UTC).isoformat("T").replace("+00:00", "Z")
548536
)
549537
env.globals["slug_from_project_name"] = slug_from_project_name
550538
# Store the environment in the context for use by the !include
@@ -755,9 +743,7 @@ def run_http_request_playbook(name: str, playbook: dict) -> None:
755743
except AttributeError as e:
756744
if cli_args.dry_run:
757745
if cli_args.force:
758-
logger.error(
759-
"Error processing playbook", error=str(e), playbook=name
760-
)
746+
logger.error("Error processing playbook", error=str(e), playbook=name)
761747
step_payload["_response"] = {}
762748
continue
763749
else:
@@ -766,9 +752,7 @@ def run_http_request_playbook(name: str, playbook: dict) -> None:
766752
if retries_remaining.get() > 0:
767753
continue
768754
if cli_args.force:
769-
logger.error(
770-
"Error processing playbook", error=str(e), playbook=name
771-
)
755+
logger.error("Error processing playbook", error=str(e), playbook=name)
772756
continue
773757
raise
774758
if request_data is None and "raw" in step_payload:
@@ -808,9 +792,7 @@ def run_http_request_playbook(name: str, playbook: dict) -> None:
808792
step_payload["_response"] = r_dict
809793
except json.decoder.JSONDecodeError as e:
810794
if cli_args.force:
811-
logger.error(
812-
"Failed to parse response as JSON", error=str(e), playbook=name
813-
)
795+
logger.error("Failed to parse response as JSON", error=str(e), playbook=name)
814796
# Add a placeholder response to prevent re-running.
815797
step_payload["_response"] = {}
816798
continue
@@ -866,9 +848,7 @@ async def run_nats_publish_playbook(name: str, playbook: dict) -> None:
866848
except AttributeError as e:
867849
if cli_args.dry_run:
868850
if cli_args.force:
869-
logger.error(
870-
"Error processing playbook", error=str(e), playbook=name
871-
)
851+
logger.error("Error processing playbook", error=str(e), playbook=name)
872852
step_payload["_response"] = {}
873853
continue
874854
else:
@@ -877,9 +857,7 @@ async def run_nats_publish_playbook(name: str, playbook: dict) -> None:
877857
if retries_remaining.get() > 0:
878858
continue
879859
if cli_args.force:
880-
logger.error(
881-
"Error processing playbook", error=str(e), playbook=name
882-
)
860+
logger.error("Error processing playbook", error=str(e), playbook=name)
883861
continue
884862
raise
885863
elif "raw" in step_payload:
@@ -978,9 +956,7 @@ async def run_nats_kv_put_playbook(name: str, playbook: dict) -> None:
978956
except AttributeError as e:
979957
if cli_args.dry_run:
980958
if cli_args.force:
981-
logger.error(
982-
"Error processing playbook", error=str(e), playbook=name
983-
)
959+
logger.error("Error processing playbook", error=str(e), playbook=name)
984960
step_payload["_response"] = {}
985961
continue
986962
else:
@@ -989,9 +965,7 @@ async def run_nats_kv_put_playbook(name: str, playbook: dict) -> None:
989965
if retries_remaining.get() > 0:
990966
continue
991967
if cli_args.force:
992-
logger.error(
993-
"Error processing playbook", error=str(e), playbook=name
994-
)
968+
logger.error("Error processing playbook", error=str(e), playbook=name)
995969
continue
996970
raise
997971
elif "raw" in step_payload:
@@ -1076,9 +1050,7 @@ async def run_nats_request_playbook(name: str, playbook: dict) -> None:
10761050
except AttributeError as e:
10771051
if cli_args.dry_run:
10781052
if cli_args.force:
1079-
logger.error(
1080-
"Error processing playbook", error=str(e), playbook=name
1081-
)
1053+
logger.error("Error processing playbook", error=str(e), playbook=name)
10821054
step_payload["_response"] = {}
10831055
continue
10841056
else:
@@ -1087,9 +1059,7 @@ async def run_nats_request_playbook(name: str, playbook: dict) -> None:
10871059
if retries_remaining.get() > 0:
10881060
continue
10891061
if cli_args.force:
1090-
logger.error(
1091-
"Error processing playbook", error=str(e), playbook=name
1092-
)
1062+
logger.error("Error processing playbook", error=str(e), playbook=name)
10931063
continue
10941064
raise
10951065
elif "raw" in step_payload:
@@ -1115,9 +1085,7 @@ async def run_nats_request_playbook(name: str, playbook: dict) -> None:
11151085
)
11161086

11171087
try:
1118-
response = await nats_client.request(
1119-
params.subject, data, timeout=params.timeout
1120-
)
1088+
response = await nats_client.request(params.subject, data, timeout=params.timeout)
11211089
# Parse the response data and store it.
11221090
try:
11231091
response_data = json.loads(response.data.decode())

0 commit comments

Comments
 (0)