How to view a SAML responses from a HAR file
Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.
Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
Purpose
The following guide describes some processes that can be used to troubleshoot SAML 2.0 related configurations with Atlassian applications from a HAR file generated during the SAML dance. Note that this is specifically intended to show how to parse a HAR file and retrieve the information if you do not have direct access to the instance. If you have access to the instance, the following guide is better to intercept the calls directly:
How to view SAML responses in your browser for troubleshooting
Process
Generate a HAR file while the failed SAML dance is happening. More details are available at Generating HAR files and analyzing web requests.
Make sure that the HAR file is taken correctly. Some IdP's open a new tab after being redirected to them from the SP (Jira, Confluence, etc) and this will not be captured in the HAR file
Once you have the HAR file, go to your Chrome browser and open up your Developer Tools. You can generally do this by going to the Chrome settings and clicking on More Tools --> Developer Tools.
Select the Network tab
Drag and Drop the HAR file to the
Filter for samlconsumer using the filter dialog box
Copy the contents of the SAML Response from Form Data section:
Do not include the RelayState data that may be there as well. We are just interested in the encoded and inflated SAML response)
Open your terminal and run the following decode command, substituting SAMLResponse with the actual response copied over from the HAR file. The decode command will transform the base64 encoded text and xmllint will make it readable XML format:
echo SAMLResponse | base64 --decode | xmllint --format -
You can set up a Text Expander snippet the following to allow you easily paste the response:
Echo %filltext:name=SAMLResponse:width=20% | base64 --decode | xmllint --format -
There should be some XML formatted text containing the actual content shared between the IdP and the SP:
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDpDCCAoygAwIBAgIGAWVKFlLOMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi04MDkxODQxHDAaBgkqhkiG9w0BCQEW
DWluZm9Ab2t0YS5jb20wHhcNMTgwODE3MjI1MDQxWhcNMjgwODE3MjI1MTQxWjCBkjELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNV
BAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtODA5MTg0MRwwGgYJ
KoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
lxRsDpgJYZaor5tbyujpcVOWHVO+4AGof+RAVbzLG/WGFLC3pId8joLNR6JCLe0uQL0gqj+P/ulT
SHp0G/ztWcltvs1gZ5geuibq209UT3iAKDtRLy7x8ZeoF3wPU8vANOoeGUYa55Ezd5Xp7n3Cqmex
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">atlassiandcforall@gmail.com</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="ONELOGIN_a8330c84-470b-41e3-9777-5b4c71b03c7c" NotOnOrAfter="2019-04-26T00:33:57.329Z" Recipient="http://10.125.x.x/jira/plugins/servlet/samlconsumer"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2019-04-26T00:23:57.329Z" NotOnOrAfter="2019-04-26T00:33:57.329Z">
<saml2:AudienceRestriction>
<saml2:Audience>http://10.125.x.x/jira</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2019-04-25T21:20:38.353Z" SessionIndex="ONELOGIN_a8330c84-470b-41e3-9777-5b4c71b03c7c">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:Attribute Name="test" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">atlassian@gmail.com</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
</saml2p:Response>
Things to Note and Check
Make sure that the following data sent from the IdP perfectly matches the data within the SP (Jira, Confluence, etc), including trailing/leading spaces.
Make sure that the Audience value matches the Audience URL (Entity ID) URL used in the SP SAML settings
<saml2:Audience>http://IPAddress/jira</saml2:Audience>
Make sure that the destination value matches the Assertion Consumer Service URL within the SP
Destination="http://IPAddress/jira/plugins/servlet/samlconsumer”
Make sure that the issuer sent from the IdP matches the Issuer set in the application
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exkkl2cugfzfv8Qz</saml2:Issuer>
- Make sure that the X509 certificate information sent from the IdP matches the one configured on the SP side
Additionally, make sure that the following conditions are satisfied, including the name of the user being authenticated.
The NameID the IdP is sending has to exactly match the username field in the SP. This cannot be the email property.
NameID: <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">atlassiandcforall@gmail.com</saml2:NameID>
Make sure that the following time stamps sent by IdP are accurate. These are attributes used by SAML to enforce authentication for a certain time range:
NotBefore="2019-04-25T23:17:17.166Z" NotOnOrAfter="2019-04-25T23:27:17.166Z"