SSO Setup
Proving it works (with controls)
★★ A successful HTTPS request, on its own, does not prove trust. It cannot distinguish "the certificate validated" from "validation was silently disabled". Every positive below is therefore paired with a negative control that must fail.
The house standard is to verify the effect, never the mechanism. For TLS:
- "the config file says SSL is enabled" is not evidence
- a port accepting a TCP connection is not evidence
- an HTTPS request returning a real status code, with validation on, is
The battery, and what each answers
1. Positive: does it validate against our CA?
openssl s_client -connect 192.168.222.100:443 \
-servername siemensdc -verify_hostname siemensdc \
-CAfile certs/ca.crt -verify_return_error
Result: Verify return code: 0 (ok), TLSv1.3, TLS_AES_256_GCM_SHA384, with the
certificate on the wire showing CN=siemensdc.xcelerator.local issued by
Xcelerator Local Root CA.
2. Negative control: a CA that never signed it
The same command against a throwaway decoy CA. Must fail.
Result: verify error:num=20: unable to get local issuer certificate. Had this
succeeded, validation was not really happening.
3. Negative control: wrong hostname
Correct CA, but -verify_hostname wrong.example.com. Must fail.
Result: Verify return code: 62 (hostname mismatch), which proves SAN matching
is live.
4. A real HTTP status, not just a handshake
GET https://siemensdc/ -> HTTP 200
GET https://192.168.222.100/ -> HTTP 200 (IP SAN works)
GET https://siemensdc:8070/deploymentcenter/ -> HTTP 200 (Jetty 12.0.16)
GET https://siemensdc:8070/.../rest/environments -> HTTP 401
★ The 401 is a pass, not a failure: it is the REST layer answering correctly that authentication is required.
★★ Better still, the Active Workspace root issues an XSRF-TOKEN cookie.
That is what the SOA bootstrap requires, so it proves real Active Workspace is
being served rather than a static page that happens to return 200.
5. The JVM, separately, because it uses a different truststore
This is the step people skip, and Teamcenter's own server-side calls are JVM.
| Run | Truststore | Expected | Actual |
|---|---|---|---|
| Positive | default cacerts |
200 | HTTP 200 |
| Negative | cacerts.bak-2026-08-15-pre-xcelerator-ca |
fail | SSLHandshakeException, PKIX path building failed |
The pre-CA backup truststore is an ideal negative control: identical to the live one except that it lacks our CA. So the pass is attributable specifically to our CA being present, not to validation being lax.
6. Confirm the old plaintext endpoints are genuinely gone
port 3000 -> unreachable
http://siemensdc:8070/... -> curl code 000, refused at transport level
7. Read the server's own log, not just the port
Started ServerConnector@...{SSL, (ssl, http/1.1)}{0.0.0.0:8070}
x509=X509@...(dcserver,h=[siemensdc.xcelerator.local, siemensdc, localhost],
a=[/192.168.222.100, /127.0.0.1])
Jetty naming the SSL connector and the loaded certificate is stronger evidence than an open socket.
Two instruments that lie
Both cost real time here, and both name the wrong cause.
⚠ Windows curl.exe uses schannel. Even with the CA fully trusted it returns
curl: (60) schannel: the revocation status is unknown. That is a revocation
complaint about a private CA that publishes no CRL, not a trust failure, and it
reads exactly like one. Use --ssl-no-revoke, or prefer openssl. schannel also
cannot do SNI against a bare IP, producing a second unrelated-looking failure.
⚠ MSYS2_ARG_CONV_EXCL="*" in Git Bash stops path conversion, so
openssl -CAfile /posix/path silently fails to open the file. A negative control
that never ran looks identical to one that passed: both produce no success
line. Print proof the control file exists before trusting any "it failed as
expected".
⇒ Keep both controls alongside the result. A checker is not a checker until it has been run against known-bad input.