Skills
Polarion Authentication
Skill
polarion-authentication. Configure Polarion 2606 authentication - the authentication.xml contract, SSO via Teamcenter Security Services (tcss) or OIDC (oauth2), and the traps that make a wrong config look right. Covers the built-in editor being the only supported edit surface, the schema-vs-runtime contradiction that makes password and tcss mutually exclusive, the JVM truststore Polarion needs before it can call TcSS at all, and the TcSS Application Registry check that fires on the return leg only so a clean outbound redirect proves nothing. Use for any Polarion SSO, LDAP, OIDC or "my authentication config will not save" work.
Provenance is marked throughout. EXERCISED came back from a real call or a real save on this
estate (Polarion 2606 at D:\Polarion on MARTINI-GAMING, TcSS on TC2606/siemensdc, Keycloak 24
realm xcelerator, 2026-08-19). DERIVED was read out of the shipped 2606 documentation and has
not been run. Do not promote a DERIVED line without running it.
Related: tc-sso-keycloak (the Teamcenter half, and the three-truststore problem this extends).
0. The one-paragraph version
All Polarion authentication lives in one file, authentication.xml, and you edit it through
Global Administration > User Management > Authentication, not on disk. Polarion serves its own
authoritative XSD and the editor genuinely enforces it. Adopting Teamcenter SSO means the <tcss>
authenticator, which cannot coexist with local password login, needs a CA in Polarion's own JVM
truststore, and needs Polarion registered in TcSS's Application Registry on the Teamcenter side.
1. Where the config lives, and why not to touch the file
EXERCISED. The supported surface is the built-in editor:
Global Administration (or Administration in the Default Repository) then User Management > Authentication > Create XML configuration
Buttons: Default Template (known-good starter), Import from File, Cancel.
Siemens' own guidance, quoted: "We recommend that you only update the authentication.xml file via the built-in editor. (Do not edit the authentication.xml file directly with an external editor.)" and a Warning that a direct file edit means you "will have to reindex the coordinator."
The editor validates on save and applies immediately across all nodes with no service restart. A direct file edit needs a restart. So the editor is both safer and faster.
com.siemens.polarion.security.auth.fileinpolarion.propertiesrelocates the file. DERIVED.- Cluster/multi-instance default lives on the Coordinator under
$POLARION_DATA/workspace/cluster-data;com.siemens.polarion.security.auth.cluster.folderoverrides. DERIVED. authentication.xmlReload.enabled=trueplus a GET on<server>/polarion/authentication-reloadrefreshes an on-disk edit without a restart. DERIVED. Note it cannot create or remove the initial file, and setting the property needs a working login, so it is not a lockout recovery.
WARNING. Do not go hunting for authentication.xml on disk to find out whether one exists. A
recursive filename search on this install returned eight hits, all 122 bytes, all
...\plugins\...\templates\<tpl>\.polarion\tracker\categories\authentication.xml, which are
work-item category definitions named "Authentication" and have nothing to do with SSO. The real
SSO file did not exist at all. Exclude \plugins\ and \templates\ before drawing any conclusion.
2. The schema is authoritative, published, and enforced
EXERCISED, and this is the highest-value item here. Polarion serves its own XSD:
http://<polarion-host>/polarion/authentication.xsd
(about 22 KB, namespace http://polarion.com/PolarionAuthentication)
Validating locally against that file predicted the editor's verdict exactly, on both a pass and
a fail. So you can author and check offline with lxml and be confident before pasting.
WARNING. /polarion/<anything> returns HTTP 200 on this server, including nonsense paths. A
bogus .xsd path returned 200 as readily as the real one. Status code is not evidence here; check
the content. This is the classic "limit that behaves like success" shape.
Root element and child order (xs:sequence, so order matters):
<authentication>
password? (0..1)
ldap* (0..n)
saml* (0..n)
oauth2* (0..n)
tcss? (0..1)
basic? (0..1)
jwt* (0..n)
</authentication>
Which types carry id and default is NOT uniform, and the prose misleads. The docs say
"id: Required, String. Must be unique across whole XML" in the general authenticator section. That
applies only to the types that declare it:
| Type | id |
default |
other attributes |
|---|---|---|---|
oauth2 |
required | optional | forceLdapEsignatures, usage |
ldap |
required | none | allowWebServices, syncUserGroups, usage |
saml |
required | optional | |
password |
none | optional | usage |
tcss |
none | none | forceLdapEsignatures, usage |
basic |
none | none | allowOslc, usage |
The base authenticator type is literally empty (<xs:complexType name="authenticator"/>), so
nothing is inherited. Writing <tcss id="..." default="true"> from the general prose fails.
3. password and tcss cannot coexist. There is no valid configuration.
EXERCISED, proven in both directions against the live editor. This is a planning constraint, not a detail, because it means adopting Teamcenter SSO removes local login from Polarion.
<password default="true"/> + <tcss> -> XSD passes, RUNTIME rejects:
"Multiple authenticators must have exactly one default authenticator.
Please set the "default" attribute to configuration."
<tcss default="true"> + <password/> -> RUNTIME rejects on SCHEMA:
"cvc-complex-type.3.2.2: Attribute 'default' is not allowed to appear in element 'tcss'."
The runtime demands exactly one default among multiple authenticators; the schema forbids
default on tcss; and <password default="true"/> does not satisfy the runtime's check. Both
constraints cannot be met at once.
So <tcss> alone is the documented and working shape. The migration topic shows exactly that as
the complete replacement for the pre-22R1 polarion.properties settings.
And decide the lockout story before you save. On a system whose only account is the default
admin, saving a tcss-only config with SSO not yet fully working leaves the current browser session
as the sole way in.
Rollback is one click
EXERCISED. The Authentication page's Default Template button regenerates
<password default="true" /> with the other providers commented out. Save applies immediately, no
restart, local login restored. This is far cheaper than an elevated rename-the-file-and-restart
script, and it needs no admin rights on the host. Reach for it first.
4. <tcss>: the element, and finding its real URLs
<tcss>
<loginUrl>https://TCSS-HOST:PORT/login/sa</loginUrl>
<serviceUrl>https://TCSS-HOST:PORT/identity</serviceUrl>
<!-- optional -->
<paramAppUserId>APP_USER_ID</paramAppUserId>
<paramSessionKey>SESSION_KEY</paramSessionKey>
<autocreate><enabled>true</enabled></autocreate>
</tcss>
autocreate is type createAccount: required <enabled>, optional
<globalRoles><role>...</role></globalRoles>. Still untested here - the federated user already
existed, so it never had an account to create. Do not describe it as working.
★★★ The documented defaults for the parameter names are WRONG, and the symptom misleads
EXERCISED, and this was the single hardest thing in the whole exercise. The docs give
paramAppUserId a default of APP_USER_ID and paramSessionKey a default of SESSION_KEY.
This TcSS posts neither. Captured from the real return POST body:
TCSSO_APP_USER_ID = ed
TCSSO_SESSION_KEY = eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9... (a JWT)
IS_TCSSO_APP_TOKEN = true
TCSSO_LOCALE = en_us
tcsso.behind_sso_gateway = false
TCSSONOAPPLETS = true
iss = https://<idp>/realms/<realm>
x-siemens-session-id / x-correlation-id
So set them explicitly:
<paramAppUserId>TCSSO_APP_USER_ID</paramAppUserId>
<paramSessionKey>TCSSO_SESSION_KEY</paramSessionKey>
⚠ The symptom points at the wrong thing. Leaving the defaults produces
[AUTH-0002] ... Reason: The supplied token is invalid, which reads as a broken or expired token
and sends you into TcSS, Keycloak, certificates and clocks. It is none of those. The tell is that
Polarion rejects in ~40 ms and TcSS logs NO validateAppToken at all - Polarion never contacts
the identity service, because it never found a session key to validate. When TcSS's log is silent
for an attempt, the failure is client-side parameter extraction, not the token.
★ Get the names by capturing the POST, not by reading the docs. DevTools > Network > the POST
to /polarion/ > Payload. Every hypothesis formed before that capture (log4j config, origin
mismatch, SameSite on a cross-site POST, clock skew, certificate trust) was wrong, and each cost a
config change and a restart to disprove.
Probe for the real service names rather than trusting a written-down value. On this estate the
SsoSetup blueprint recorded the Login Service as https://siemensdc:8093/Teamcenter1/..., which
404s. The live paths are:
/login/sa -> 302 <- loginUrl
/identity -> 301 <- serviceUrl
/Teamcenter1 -> 404 <- the stale blueprint value
That is tc-sso-keycloak section 11's trap: the Deployment Center web-app name and the Login
Service name look interchangeable and are not. One curl per candidate settles it.
5. Polarion's JVM needs the TcSS CA, and it is not the CA you expect
EXERCISED. <tcss> makes Polarion call TcSS over HTTPS from its own JVM, which is a fourth
truststore beyond the three in tc-sso-keycloak section 3. A fresh Temurin JDK trusts neither the
corporate CA nor Teamcenter's.
On this estate TcSS is signed by Deployment Center's internal PKI, not the shared CA.
siemensdc:8093 chain: CN=SIEMENSDC
<- CN=Siemens Deployment Center Vault Intermediate CA
<- CN=Siemens Deployment Center Vault root CA
Keycloak's CA file: CN=Xcelerator Local Root CA <- a DIFFERENT CA
Importing the Keycloak CA looks obviously right and does nothing. Take the root off the wire:
keytool -printcert -rfc -sslserver TCSS-HOST:PORT > chain.pem # keep the LAST cert
keytool -importcert -noprompt -trustcacerts -cacerts -storepass changeit -alias NAME -file root.crt
Verify with an A/B control, because a pass alone cannot distinguish "trusted" from "validation
disabled". Back up cacerts first, then probe the same URL twice: once against the live store,
once against the pre-import backup via -Djavax.net.ssl.trustStore=. The second must fail
PKIX path building failed. Pair with a public HTTPS URL to prove the probe itself works. Re-run
after any JDK patch: a new JDK ships a fresh cacerts and the alias is gone.
curl --cacert on Windows may fail with CERT_TRUST_REVOCATION_STATUS_UNKNOWN. That is a schannel
CRL-check artifact, not a trust failure; --ssl-no-revoke clears it. Do not report it as a
certificate problem.
6. The TcSS Application Registry check fires on the RETURN leg only
EXERCISED, and this one is genuinely easy to misreport. Once <tcss> is saved, an
unauthenticated hit on /polarion/ returns an auto-submitting form:
POST https://TCSS-HOST:8093/login/sa/weblogin/login_redirect
TCSSORURI = /polarion/
TCSSONOAPPLETS = true
TCSSOAPPID = Polarion <- the app id TcSS must know
POSTing that by hand returns a clean 302 to a well-formed OP authorization request, and the OP
will then authenticate a real user and return a real code. None of that proves the application
is registered. TcSS only consults its Application Registry when it comes to redirect the browser
back, and an unregistered app fails there:
There is a system error. Please contact your system administrator. Web redirection from an unknown application: Polarion.
The fix is on the Teamcenter side, a third Application Registry row beside TCSSOLoginService
and the AWC application:
| Field | Value |
|---|---|
| Application ID | must equal TCSSOAPPID, i.e. Polarion |
| APPLICATIONROOTURL | the host root only, e.g. https://POLARION-HOST:PORT |
| REDIRECTURL | the same host root, not an OAuth callback |
⚠ Scheme and port are part of the registered root, so moving Polarion to HTTPS breaks SSO until
this row moves with it. EXERCISED 2026-08-19: putting Polarion behind TLS on a non-standard port
required this value to change from http://martini-gaming to https://martini-gaming:4443. Still
host root only, still no trailing slash. Since the registry is consulted on the return leg, the
symptom of forgetting is a login that starts fine and fails at the end. Sequence the two changes
together, and see polarion-https-and-rest.
TcSS APPENDS TCSSORURI to the registered root, so the root must NOT contain the application
path. EXERCISED failure: registering http://HOST/polarion/ while Polarion posts
TCSSORURI=/polarion/ produced a post-login redirect to .../polarion/polarion/, a doubled path
that 404s. Register http://POLARION-HOST and let TCSSORURI supply /polarion/.
And the root must name the machine that actually serves Polarion, not the TcSS host. The same
failure landed on siemensdc/polarion/polarion/ where siemensdc is the Teamcenter VM and serves
no Polarion at all (http://siemensdc/polarion/ -> 404). Confirm with a plain curl which host
answers 200 for the application root before registering anything.
And per tc-sso-keycloak section 18, the pool manager service must be restarted before any TcSS
change is actually live. A retest that skips it can fail for reasons that have nothing to do with
the change.
7. Verification bar
In order, because each step passes while the next is broken:
- The config saves in the built-in editor. Schema plus semantic rules, both.
/polarion/returns the auto-POST form carrying the expectedTCSSOAPPID.- That POST returns 302 to a well-formed OP authorization request (right
client_id,redirect_uri,scope). - The OP renders a login page and authenticates a real user.
- The callback lands back in Polarion authenticated. Only this proves SSO. Steps 2 to 4 all passed on this estate while the whole thing was still broken.
- The user has a Polarion account. Federated ids must match Polarion user ids, or
<autocreate>must be on. A realm carrying dozens of users plusautocreatealso has licence-allocation consequences worth thinking about before enabling it.
7b. A valid token is not a successful login: Polarion's catch-all message
EXERCISED. Once the parameter names are right, TcSS logs SSO token validated and the login
can still fail, with a different and even less helpful message:
[AUTH-0002] Unsuccessful login attempt for user 'ed' by 'TCSS' mechanism.
Reason: Your Username or Password is incorrect, or there was another problem logging in.
There is no password in an SSO flow, so that text is a catch-all for anything that goes wrong after the token is accepted. Here the cause was the Polarion account itself.
★★ [disabled] on a Polarion user is a DERIVED state, not a settable flag. The user detail page
showed Ed Engineer [disabled] in red, and there is no enable checkbox anywhere on the form.
Polarion marks an account disabled when it lacks what it needs to be usable; granting the user
global role cleared it on save. So "enable the user" is not an action you can take - you fix the
underlying gap and the state follows. Do not go hunting for the toggle.
The diagnostic ladder, which localises the failure in one log read each:
| Observation | Failing layer |
|---|---|
TcSS logs no Redirection request from: <app> |
Polarion is not emitting the handoff; check <tcss> is live |
TcSS logs Web redirection from an unknown application |
app not in the TcSS Application Registry |
TcSS logs the redirect but no validateAppToken |
parameter-name mismatch (section 4) |
TcSS logs SSO token validated, Polarion still AUTH-0002 |
the Polarion account: disabled state, roles, licence |
No AUTH-0002 and the user lands in the portal |
working |
Check the user's own detail page early. The answer to the last case was visible as a red tag on that page the entire time, while hours went into TcSS logs, JWT payloads and certificate probes. The moment Polarion names a user in an error, open that user.
Licences are a real ceiling. The account also needed an assigned licence, and the dropdown read
Named ALM (0 remaining). Shipped demo personas hold seats. Expect to free one before onboarding a
real user, and note that a disabled account may still be holding its seat.
⚠ That reading was taken on the 30-day trial, whose seat count is small. On a real SALT entitlement the ceiling is whatever was issued, and the seats are visible from outside Polarion, which is a much faster check than the UI dropdown:
"C:/Program Files/Siemens/License Server/lmutil.exe" lmstat -a -c 29000@localhost | grep -i "Users of pln_"
OUT: "pln_alm_n" <user>@<HOST> lines in saltd.log name exactly who holds a seat. If licensing
itself is the problem rather than the allocation, see polarion-salt-licensing: an unlicensed
Polarion starts and serves normally, so a login failure is a plausible first symptom.
Where accounts come from. Do not assume an account that matches your federated id was created by
<autocreate>. Compare it against the directory: here the Polarion account carried a curated name,
initials, a description and the installer's admin email, while LDAP held only uid/cn/sn = ed and
ed@<host>. The mismatch proved it predated SSO entirely - it shipped with the demo projects,
alongside personas like Steve Developer and Melanie Test.
7c. Operating this without locking yourself out
Because password and tcss cannot coexist (section 3), every SSO experiment risks losing all
access, and a session timeout alone is enough to strand you. Two things make the loop cheap:
- The config file's real location is
<POLARION_DATA>\authentication\authentication.xml(D:\Polarion\data\authentication\here), **not** underpolarion\configuration\. Find it by recursive search excluding\plugins\and\templates\, which hold eight same-named work-item category files that are not the auth config. - Removing that file and restarting the Polarion service reverts to built-in login. Writing it back
and restarting re-enables SSO. A small elevated script with
local/tcss/statusmodes turns each flip into one command.set-polarion-auth.ps1inDocuments\Siemens\polarion-sso\.
★ Do all account work (roles, licence, provider settings) while on local login, then flip once. Testing one attribute per flip costs a lockout cycle each time.
★ Chrome blocks the return POST with "The information you're about to submit is not secure" on every login, because the form originates on HTTPS (TcSS) and posts to HTTP (Polarion). It is not a failure and the POST completes after "Send anyway", but it makes an HTTP-only Polarion unshippable to real users. Put TLS on Polarion before onboarding anyone.
8. The OIDC alternative, if you do not want the Teamcenter dependency
<oauth2 id="..." default="true"> points Polarion straight at the OP, with <authorizeUrl>,
<tokenUrl>, <clientId>, <clientSecret>, optional <userUrl>, plus <mapping>, <scopes>,
<groupsSynchronization>, <rolesSynchronization>. DERIVED here, not run on this estate.
Trade-off, worth stating explicitly when someone asks for "Teamcenter SSO":
<tcss>gives a shared Teamcenter session, which the Polarion/Teamcenter Direct and Linked Data integrations expect. Cost: Polarion login depends on the Teamcenter tier being up, and on a VM that gets reverted, TcSS config does not survive the revert.<oauth2>makes Polarion a peer client of the same IdP. Both apps then trust one issuer and one user-id namespace, and Polarion keeps working when Teamcenter is down.oauth2also carriesidanddefault, so it can coexist with<password>, which sidesteps section 3 entirely.
Generated from skills/polarion-authentication/SKILL.md in the tc-automation-skills library, which is the canonical copy and also serves as the agent skill set for Teamcenter work.