🔒️(saml) use eduPersonPrincipalName rather than NameID for sub
The NameID returned by the SAML server is actually transient so we can't use it as a sub. We'll use eduPersonPrincipalName both in sub and uid.
This commit is contained in:
@@ -131,7 +131,13 @@ oidc-test: ## open OIDC test client in browser
|
||||
@$(MAKE) down
|
||||
@$(MAKE) run
|
||||
python -mwebbrowser -n https://oidc-test-client.traefik.me
|
||||
.PHONY: oidc-test
|
||||
.phony: oidc-test
|
||||
|
||||
e2e-test: ## automated end-to-end test in browser
|
||||
@$(MAKE) down
|
||||
@$(MAKE) run
|
||||
TEST_E2E=1 pytest
|
||||
.phony: e2e-test
|
||||
|
||||
env.d/development/common:
|
||||
cp -n env.d/development/common.dist env.d/development/common
|
||||
|
||||
@@ -7,6 +7,7 @@ services:
|
||||
DOCKER_USER: ${DOCKER_USER:-1000}
|
||||
user: ${DOCKER_USER:-1000}
|
||||
image: oidc2fer:development
|
||||
pull_policy: never
|
||||
environment:
|
||||
PYLINTHOME: /app/.pylint.d
|
||||
BASE_URL: https://satosa.traefik.me
|
||||
|
||||
@@ -22,8 +22,9 @@ attributes:
|
||||
acr:
|
||||
openid:
|
||||
- acr
|
||||
eppn:
|
||||
saml:
|
||||
- eduPersonPrincipalName
|
||||
uid:
|
||||
openid:
|
||||
- uid
|
||||
saml:
|
||||
- eduPersonPrincipalName
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
module: satosa.micro_services.primary_identifier.PrimaryIdentifier
|
||||
name: PrimaryIdentifier
|
||||
config:
|
||||
# The ordered identifier candidates are searched in order
|
||||
# to find a candidate primary identifier. The search ends
|
||||
# when the first candidate is found. The identifier or attribute
|
||||
# names are the internal SATOSA names for the attributes as
|
||||
# defined in internal_attributes.yaml.
|
||||
ordered_identifier_candidates:
|
||||
- attribute_names: [eppn]
|
||||
|
||||
# The internal SATOSA attribute into which to place the primary
|
||||
# identifier value once found from the above configured ordered
|
||||
# candidates.
|
||||
primary_identifier: uid
|
||||
|
||||
# Whether or not to clear the input attributes after setting the
|
||||
# primary identifier value.
|
||||
clear_input_attributes: no
|
||||
|
||||
# Whether to replace subject_id with the constructed primary identifier
|
||||
replace_subject_id: yes
|
||||
@@ -12,6 +12,7 @@ FRONTEND_MODULES:
|
||||
- plugins/frontends/openid_connect_frontend.yaml
|
||||
- plugins/frontends/ping_frontend.yaml
|
||||
MICRO_SERVICES:
|
||||
- plugins/microservices/primary_identifier.yaml
|
||||
- plugins/microservices/static_attributes.yaml
|
||||
- plugins/microservices/attribute_processor.yaml
|
||||
LOGGING:
|
||||
|
||||
@@ -2,7 +2,7 @@ import json
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
from playwright.sync_api import Browser, BrowserContext, Page, expect
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
@@ -22,10 +22,8 @@ def renater_wayf(page):
|
||||
page.get_by_role("button", name="Sélection").click()
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
"TEST_E2E" not in os.environ, reason="Depends on app running locally"
|
||||
)
|
||||
def test_oidc_to_renater(page: Page):
|
||||
def oidc_to_renater(context: BrowserContext):
|
||||
with context.new_page() as page:
|
||||
page.goto("https://oidc-test-client.traefik.me")
|
||||
renater_wayf(page)
|
||||
renater_test_idp(page)
|
||||
@@ -33,6 +31,7 @@ def test_oidc_to_renater(page: Page):
|
||||
expect(page.locator("pre")).to_contain_text('"usual_name":"Dupont"')
|
||||
text = page.inner_text("pre")
|
||||
result = json.loads(text)
|
||||
|
||||
id_token = result["access_token_response"]["id_token"]
|
||||
assert {"acr": "eidas1"}.items() <= id_token.items()
|
||||
userinfo = result["userinfo"]
|
||||
@@ -42,6 +41,17 @@ def test_oidc_to_renater(page: Page):
|
||||
"uid": "etudiant1@test-renater.fr",
|
||||
"usual_name": "Dupont",
|
||||
}.items() <= userinfo.items()
|
||||
return id_token
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
"TEST_E2E" not in os.environ, reason="Depends on app running locally"
|
||||
)
|
||||
def test_oidc_to_renater(browser: Browser):
|
||||
id_token1 = oidc_to_renater(browser.new_context())
|
||||
id_token2 = oidc_to_renater(browser.new_context())
|
||||
|
||||
assert id_token1["sub"] == id_token2["sub"]
|
||||
|
||||
|
||||
def agent_connect_login(page: Page):
|
||||
@@ -51,10 +61,8 @@ def agent_connect_login(page: Page):
|
||||
page.get_by_test_id("interaction-connection-button").click()
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
"TEST_E2E_AC" not in os.environ, reason="Depends on staging deployment"
|
||||
)
|
||||
def test_agent_connect_to_renater(page: Page):
|
||||
def agent_connect_to_renater(context: BrowserContext):
|
||||
with context.new_page() as page:
|
||||
agent_connect_login(page)
|
||||
renater_wayf(page)
|
||||
renater_test_idp(page)
|
||||
@@ -68,3 +76,14 @@ def test_agent_connect_to_renater(page: Page):
|
||||
"uid": "etudiant1@test-renater.fr",
|
||||
"usual_name": "Dupont",
|
||||
}.items() <= result.items()
|
||||
return result
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
"TEST_E2E_AC" not in os.environ, reason="Depends on staging deployment"
|
||||
)
|
||||
def test_agent_connect_to_renater(browser: Browser):
|
||||
result1 = agent_connect_to_renater(browser.new_context())
|
||||
result2 = agent_connect_to_renater(browser.new_context())
|
||||
|
||||
assert result1["sub"] == result2["sub"]
|
||||
|
||||
Reference in New Issue
Block a user