Skip to content

Support PIN code in OOB IdP authentication#23

Open
aaearon wants to merge 8 commits intopspete:devfrom
aaearon:fix/oob-idp-pin
Open

Support PIN code in OOB IdP authentication#23
aaearon wants to merge 8 commits intopspete:devfrom
aaearon:fix/oob-idp-pin

Conversation

@aaearon
Copy link
Copy Markdown
Contributor

@aaearon aaearon commented Apr 10, 2026

Description

Tenants configured to require a PIN code after external IdP authentication hang forever in New-IDSession. After the user logs in to the IdP, the browser displays a PIN that must be submitted to /Security/AdvanceAuthentication, but the existing OOB IdP branch only handles the polling variant via /Security/OobAuthStatus, so users see the PIN with no way to enter it.

This PR adds a new branch in New-IDSession that detects IdpOobAuthPinRequired on the Start-Authentication response, prompts the user for the PIN (as a SecureString, matching Get-MechanismAnswer conventions), and submits it with the OOBAUTHPIN mechanism id and the IdpLoginSessionId from the start-auth response. The submission is wrapped in the same try/catch + Clear-AdvanceAuthentication contract used by Start-AdvanceAuthentication, and the response is validated (Summary = LoginSuccess, Token present) before flowing into the existing session-output path.

Reference: ark-sdk-pythonark_sdk_python/auth/identity/ark_identity.py (__perform_pin_code_idp_authentication), the same project cited by the existing OOB IdP code.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Documentation update

How Has This Been Tested?

  • New Context 'OOB IdP Authentication' in Tests/New-IDSession.Tests.ps1 covering:

    • PIN happy path: browser launch, secure PIN prompt, correct body shape (OOBAUTHPIN / IdpLoginSessionId / Answer), no OobAuthStatus call, Start-AdvanceAuthentication bypassed.
    • PIN error handling: API error invokes Clear-AdvanceAuthentication and re-throws; non-LoginSuccess summary and missing Token are rejected with cleanup.
    • Polling regression: the existing non-PIN path still calls OobAuthStatus and does not prompt.
  • Full suite run: Invoke-Pester ./Tests2789 passed, 2 failed. Both failures (Out-QRImage, Start-AdvanceAuthentication cleanup) are pre-existing Linux/WSL path issues in files not touched by this PR, last modified in 2024 (7eda428).

  • Pester test(s) update required

  • Pester test(s) updated

  • Pester test(s) passing

Checklist:

  • My code follows the style guidelines of this project
  • I have followed the contributing guidelines.
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new test failures or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have opened & linked a related issue
  • I have linked a related issue

aaearon added 6 commits April 10, 2026 12:23
covers the PIN-required variant of OOB IdP authentication: prompts the
user for the PIN shown in the browser after IdP login, posts it to
AdvanceAuthentication with the OOBAUTHPIN mechanism and IdpLoginSessionId.
adds regression tests for the existing polling (non-PIN) path.
some tenants are configured to display a PIN code in the browser
after external IdP login. New-IDSession now detects the
IdpOobAuthPinRequired flag on the Start-Authentication response,
prompts the user for the PIN, and completes the session via
AdvanceAuthentication using the OOBAUTHPIN mechanism and
IdpLoginSessionId. previous tenants hung forever in the OobAuthStatus
polling loop with no way to enter the PIN.

reference: ark-sdk-python __perform_pin_code_idp_authentication
entry under unreleased/Fixed for the new PIN-confirmation variant of
OOB IdP authentication in New-IDSession.
exercises the new branch's cleanup + response validation: API error
during PIN submission calls Clear-AdvanceAuthentication and re-throws;
a non-LoginSuccess summary or missing token is rejected with cleanup.
mirrors the error-handling contract of Start-AdvanceAuthentication:
on any failure at the PIN submission stage, Clear-AdvanceAuthentication
is invoked to clean up the in-progress session and the original error
is re-thrown. a successful response is additionally validated to have
Summary=LoginSuccess and a Token before flowing into the downstream
session output path.
adds a description paragraph to both the markdown source and the
generated help file covering the new PIN-required OOB IdP variant,
so Get-Help output explains the behaviour users see at runtime.
Copilot AI review requested due to automatic review settings April 10, 2026 10:52
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes New-IDSession hanging for tenants that require a post-IdP PIN entry during OOB IdP authentication by adding a dedicated PIN submission path and documenting the behavior.

Changes:

  • Add IdpOobAuthPinRequired handling in New-IDSession to prompt for a PIN (secure input) and submit it via /Security/AdvanceAuthentication using OOBAUTHPIN.
  • Add Pester coverage for PIN-required and polling (non-PIN) OOB IdP authentication paths, including cleanup-on-error behavior.
  • Update command help/docs and changelog to describe the new PIN-required flow.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Tests/New-IDSession.Tests.ps1 Adds Pester tests covering OOB IdP PIN-required flow, error handling/cleanup, and polling regression protection.
IdentityCommand/Public/New-IDSession.ps1 Implements PIN-required branch for OOB IdP authentication and keeps polling behavior for non-PIN tenants.
IdentityCommand/en-US/IdentityCommand-help.xml Documents PIN prompt behavior for tenants requiring a PIN after external IdP authentication.
docs/collections/_commands/New-IDSession.md Adds documentation note about PIN-required tenants and the interactive prompt.
CHANGELOG.md Records the fix for PIN-required OOB IdP authentication hanging.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Start-Sleep 2
$OobPinAuthRequest = @{ }
$OobPinAuthRequest['Method'] = 'POST'
$OobPinAuthRequest['Uri'] = "$tenant_url/Security/AdvanceAuthentication"
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the OOB IdP PIN flow, the request URI is built from the local $tenant_url. If Start-Authentication returns PodFqdn, it updates $ISPSSSession.tenant_url and subsequent calls should target that redirected pod; using the original $tenant_url can break the flow. Build the AdvanceAuthentication (and other OOB IdP) URIs from $ISPSSSession.tenant_url instead.

Suggested change
$OobPinAuthRequest['Uri'] = "$tenant_url/Security/AdvanceAuthentication"
$OobPinAuthRequest['Uri'] = "$($ISPSSSession.tenant_url)/Security/AdvanceAuthentication"

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in 28a0e91. The PIN branch now builds the AdvanceAuthentication URI from $ISPSSSession.tenant_url so any PodFqdn redirect performed by Start-Authentication is honoured. Added a regression test in d62ba79 that mutates the session tenant_url in the Start-Authentication mock and asserts the PIN request targets the redirected host.

Comment on lines +139 to +140
#Undocumented endpoint for checking the IdpLoginSessionId's status. Sniffed out from the ark-sdk-python project
$OobAuthStatusRequest['Uri'] = "$tenant_url/Security/OobAuthStatus"
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OOB IdP polling request uses "$tenant_url/Security/OobAuthStatus". If Start-Authentication redirected to a pod (via PodFqdn), $ISPSSSession.tenant_url will differ from $tenant_url and polling the original host may fail. Consider building this URI from $ISPSSSession.tenant_url to stay consistent with the redirected base URL.

Suggested change
#Undocumented endpoint for checking the IdpLoginSessionId's status. Sniffed out from the ark-sdk-python project
$OobAuthStatusRequest['Uri'] = "$tenant_url/Security/OobAuthStatus"
$oobAuthStatusTenantUrl = if ($ISPSSSession.tenant_url) { $ISPSSSession.tenant_url } else { $tenant_url }
#Undocumented endpoint for checking the IdpLoginSessionId's status. Sniffed out from the ark-sdk-python project
$OobAuthStatusRequest['Uri'] = "$oobAuthStatusTenantUrl/Security/OobAuthStatus"

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in 28a0e91. This was actually a pre-existing issue in the polling branch (shipped with the initial OOB IdP support in 8fc35b8) that my PR inherited when I nested it under the new else. Since the surrounding code was already being touched here, I took the fix in this PR rather than leaving the two branches inconsistent. Used $ISPSSSession.tenant_url directly — no fallback needed, since New-IDSession assigns it unconditionally at line 53 before Start-Authentication runs. Regression test added in d62ba79. Happy to split that hunk into a follow-up if you'd prefer to keep this PR strictly scoped to the PIN flow.

aaearon added 2 commits April 10, 2026 13:04
simulates Start-Authentication mutating ISPSSSession.tenant_url via a
PodFqdn redirect and asserts the PIN and polling requests target the
redirected host rather than the stale local tenant_url parameter.
Start-Authentication rewrites the session tenant_url when the server
returns a PodFqdn redirect, so the OOB IdP PIN submission and the
polling fallback must build their request URIs from the session
variable rather than the original function parameter. previously both
branches used the stale local tenant_url and would hit the wrong host
for tenants that redirect to a pod.

flagged by Copilot on PR pspete#23.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants