Trouble setting up SAML SSO against a testing ADFS

I’m trying to configure my local IdentityIQ to perform SAML SSO, using a virtual machine.

The VM is setup in VirtualBox. A Windows server 2022 with these roles enabled:

  1. AD (set as domain controller)
  2. CA (to generate the testing certificates used in AD FS)
  3. AD FS
  4. Relying Party Trust has been setup.

In IdentityIQ, I setup SSO like this:

For SAML Name ID Format, I was having trouble matching the items in the list against those in AD FS, so for now I set it to unspecified (which should let AD FS return anything it wanted).

For the correlation rule, I used a dummy rule to always return spadmin:

// Always return spadmin
log.error("Dummy rule executing");
return context.getObjectByName(Identity.class, "spadmin");

The setup seems to work up to the point IdentityIQ tries to parse the SAML response:

  1. Open a new browser.
  2. Go to URL https://laptop.kcwong.igsl:8443/identityiq/home.jsf
  3. Browser redirects to AD FS’s login page.
  4. I login with an account from the domain.
  5. Login with AD FS is successful and redirects back to IdentityIQ.
  6. IdentityIQ fails to process the SAML response and dumps me back to login page.
  7. No error is logged in AD FS / event viewer.
  8. I cannot find the “Dummy rule executing” log in IdentityIQ.

Here’s the decoded SAML response:

<samlp:Response ID="_78a3f381-138d-4e76-b43d-d48516b6228a"
                Version="2.0"
                IssueInstant="2022-08-02T09:51:37.286Z"
                Destination="https://laptop.kcwong.igsl:8443/identityiq/home.jsf"
                Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified"
                InResponseTo="_eab0c567-20d8-4927-aaae-e72e1b13793c"
                xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
	<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">https://WIN-EF20VIM8EIQ.win2022.kcwong.igsl/adfs/services/trust</Issuer>
	<samlp:Status>
		<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
	</samlp:Status>
	<Assertion ID="_5b487453-9ef1-4e0d-a13e-dfa037bf6d83"
	           IssueInstant="2022-08-02T09:51:37.286Z"
	           Version="2.0"
	           xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
		<Issuer>https://WIN-EF20VIM8EIQ.win2022.kcwong.igsl/adfs/services/trust</Issuer>
		<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
			<ds:SignedInfo>
				<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
				<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
				<ds:Reference URI="#_5b487453-9ef1-4e0d-a13e-dfa037bf6d83">
					<ds:Transforms>
						<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
						<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
					</ds:Transforms>
					<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
					<ds:DigestValue>qZSGXtkN3Gxftlxc6vKD4GbuchIth6kET5PNE//Rmyo=</ds:DigestValue>
				</ds:Reference>
			</ds:SignedInfo>
			<ds:SignatureValue>n9mCdTsGQhJJBcGq/Dpf6tr9mjQGUBpEj4+zKnjQkzCSVFC3T/3j1snGW81IPEXEddejCSqy25yo3Jrsq78CcFnbsCGnUddyiLemvU7BKafJXQoRBrusv4RU4CFla7jyUduMOzn9k88y11qw0MkXTN0qEx9VEyf8wfIldN714BgO5N5QV4SxWKD3gd+XXxNmm0itRGY7b7N4yv1wbeBqTn9hQ9Pq588MII2LWyNqJ8TLyabZImjQjLeJxwNQNMRJBlajJIuH5x3yifkepz7h4ZOrM9XWR/IwLFoLUTc0Hb6+HvBSJhPEEFu9tvAJu4RFUTmupBBDGqOURlZltiBwgeKNnvjSTE5CZbbvzAAH7lJkNCGTA2d+7EFcwB7RjAETtQDqxbiFxdKdpXV/yw9ymlMuygeeMkuo5FRx0nTrMzmGpsNvXJeANup70hNEtlQUUGvfxtZb7HsjTa+4yyNMl1VRxHewH0MVCcYSKL5MLkNk6IumrgBXa6xIr7r3y1uCycB5dwe2aUphGg5qBojkbrLj7eL4NyqUilAitHCMAAhv9Ur3dNfKzbDoV6N81zwFmRCLu6tDR1C8QRhG6hOGP/0e4yqDP44aNVb5J2/rIdkn9a9KHXH4CKrhDlLYKPYHnPCUYjx3bKVMMqKvzi4ckVUWZDPBF86qw9bXeHnPllE=</ds:SignatureValue>
			<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
				<ds:X509Data>
					<ds:X509Certificate>MIIFAjCCAuqgAwIBAgIQbkS0ygF6tZlJYaeCvJMjhjANBgkqhkiG9w0BAQsFADA9MTswOQYDVQQDEzJBREZTIFNpZ25pbmcgLSBXSU4tRUYyMFZJTThFSVEud2luMjAyMi5rY3dvbmcuaWdzbDAeFw0yMjA4MDEwOTI4MzFaFw0yMzA4MDEwOTI4MzFaMD0xOzA5BgNVBAMTMkFERlMgU2lnbmluZyAtIFdJTi1FRjIwVklNOEVJUS53aW4yMDIyLmtjd29uZy5pZ3NsMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3BmPeokbalvh03hxFAq5//myVMTRi39ayqxuMan+CFyumprahswqhgaWVkH0mcUQRu3ihrgIUKMHMQC0s/9YCoE5q5JliajJFEmKjIOOpBGm8FjU0tudeeqqk9UxDyt4lpirQhlUJIzF5LhV8NoP58T5xw+mbbNoKoTupgsFV1dZBNi/W4P9nC259hRaIkX+reqTe5lqLFDhEc2arFQgvhwQaATSELcrB0yg9+09JrygVRCxHCG2O3tmnyQOJc6rsO4ynOWO5eGGRFRi8AmLTMiyxaNN05qptP/szHUJ06qXvUSal5zrp35ve01c3ch7Q75VuR6wAu/HRuBBGSClLUHAMwOrTC+rHFNwGQE+5EEkezUku5esifZkaY6A/hEbuMlh4dGYl4xov/0r8MKeBJMyklGxH+45L+PxYEITm/08G2bgu4Gi0SZB0w9fOqZPvdBkvI/JsfFQBLKRFMk0fUTSsdvrh14qNdc9s+Z4qV9QXZDqegO/UVitr6ZWooakhW/7jViOmf4oySJssOXs0LDl78NF3ctVw4edmxTPAKE51Mayjoaqu3qFw6mQYSvjFi84FVnDW4ng+VkLU6ze9rxIH44JVHUs1jEMbssX5vKWGKlaIPAku+8UAulAaXjuDfSTlwKtcdXqBXkmtvIjfGKWusWmMzC7/v98DkGlOkCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAXQT+yDKFSAG8N3xuQjKDU4bEC4lMTMlDQMT3gtGiYjItRXIN0GrvZ49qohI3wCSLMPtqD7nYUncT+CRuuuNgrXmDmlpNLACa/D4vfmcqoNq0E+305A9+tOOLQK7rZIfUecYe8eXOLteBq7miNEu0qfhjk0yb+0vteynjotqhSyszisy0VYJhVGjf8DCrEKy/87Be3EXJ+Lje+3AeIEcOrQdJVTOj+gQjBtkJpjw6IYfiPOwABYIVUMr5LqaIkIzFRV41RkcxF/OOZ9+Mu/ZWWPFO+H0Hq/5wyXe8uF3HhBeV5HFtLJPfFKlUv7g8MGfzL7jiq+ztaOH8aUpb4OExNzMsMTBw+IEOLQU2NS+FBAo0X/1vwZQIzDEisP+1PqVrIGhUidNH85zrr/VOkRBsjcbaKW9uAzY1MH8jlt3Y7zNEFr9pzwzlVHRius0r8Tl9mFBdbw9AyXdLuzqY34HiGUsmA8TPAUONmfZwFck62jr+CQ9ZfLapPYCmaV7J2k4w/uuw9VdG87wQsd5xi0FtaoilhGt56KN6rpALy+q7iQFIDMK05o7rFVcvPK4PurpYYZbuafU7DkOOuE6HosT86lsDHsDcYODfDZBjBpQcxxOYBvjOMfPMIYEt9r1O7c40//kU79TaQ5uagnecoUIzjbcLWjMRtp7H4SAWC6D/DIk=</ds:X509Certificate>
				</ds:X509Data>
			</KeyInfo>
		</ds:Signature>
		<Subject>
			<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
				<SubjectConfirmationData InResponseTo="_eab0c567-20d8-4927-aaae-e72e1b13793c"
				                         NotOnOrAfter="2022-08-02T09:56:37.286Z"
				                         Recipient="https://laptop.kcwong.igsl:8443/identityiq/home.jsf"/>
			</SubjectConfirmation>
		</Subject>
		<Conditions NotBefore="2022-08-02T09:51:37.284Z"
		            NotOnOrAfter="2022-08-02T10:51:37.284Z">
			<AudienceRestriction>
				<Audience>laptop.kcwong.igsl</Audience>
			</AudienceRestriction>
		</Conditions>
		<AttributeStatement>
			<Attribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname">
				<AttributeValue>Administrator</AttributeValue>
			</Attribute>
		</AttributeStatement>
		<AuthnStatement AuthnInstant="2022-08-02T09:51:37.225Z">
			<AuthnContext>
				<AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef>
			</AuthnContext>
		</AuthnStatement>
	</Assertion>
</samlp:Response>

Then I logged in as spadmin and found these logs:

The stack trace is:

java.lang.NullPointerException
	at sailpoint.web.sso.SAMLSSOAuthenticator.phase2PostHandler(SAMLSSOAuthenticator.java:278)
	at sailpoint.web.sso.SAMLSSOAuthenticator.doAuthenticate(SAMLSSOAuthenticator.java:216)
	at sailpoint.web.sso.SAMLSSOAuthenticator.authenticate(SAMLSSOAuthenticator.java:198)
	at sailpoint.web.sso.SSOAuthenticationRunner.run(SSOAuthenticationRunner.java:37)
	at sailpoint.service.PageAuthenticationService$2.command(PageAuthenticationService.java:786)
	at sailpoint.service.PageAuthenticationService.handleCommands(PageAuthenticationService.java:659)
	at sailpoint.web.PageAuthenticationFilter$MyHandler.handle(PageAuthenticationFilter.java:315)
	at sailpoint.web.PageAuthenticationFilter.doFilter(PageAuthenticationFilter.java:126)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at sailpoint.web.SailPointContextRequestFilter.doFilter(SailPointContextRequestFilter.java:61)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at sailpoint.web.util.MethodFilter.doFilter(MethodFilter.java:51)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at sailpoint.web.SailPointPollingRequestFilter.doFilter(SailPointPollingRequestFilter.java:151)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at sailpoint.web.util.TimingFilter.doFilter(TimingFilter.java:88)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at sailpoint.web.ResponseHeaderFilter.doFilter(ResponseHeaderFilter.java:63)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1787)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:750)

What is wrong with my setup? Given that I cannot find the dummy rule’s log message, this failed before correlation, probably trying to parse the SAML response.

        Response samlResponse = getResponse(input);
        Assertion assertion = verifyAssertion(samlResponse);
        String assertionId = assertion.getID();
        DateTime samlIssueInstant = assertion.getIssueInstant();
        Issuer samlIssuer = assertion.getIssuer();
        String samlIssuerVal = samlIssuer.getValue();
        Subject samlSubject = assertion.getSubject();
        NameID samlNameId = samlSubject.getNameID();
        String samlNameVal = samlNameId.getValue();    // This is the source of the NPE

So my mistake is my AD FS did not produce Name ID in the SAML response.

Setting a rule to return “Name ID” does the trick. My dummy rule got fired and I was logged into IdentityIQ as spadmin.

Next is to find out which item in AD FS corresponds to IdentityIQ’s email… previously when I do that, AD FS reports that it is unable to fulfill the request.

EDIT: The thing with email is:

  1. With that setting, IdentityIQ is expecting Name ID is in the format of email.
  2. On AD FS side, I need to return AD’s email attribute as email address. Then add another rule to transform email address to Name ID.