Spring Security SAML with PingIdentity/ PingFedera

2019-09-16 15:06发布

问题:

Spring Security SAML Sample App is not working for me when I integrate it with PingIdentity. After getting the redirect to idp, loggin on Ping ok, getting a good saml assertion, get redirect back to Spring Security Sample SAML app, I get an endless loop with an access denied error in the spring-security stack. And an org.sourceid error in Ping. Error in Ping log is (right before creating a good SAML Assertion):

org.sourceid.saml20.profiles.StatusResponseException: Unknown AssertionConsumerServiceURL https://xxxwm07.integration.company.at:9031/sp/ACS.saml2

Access denied error in Spring is:

2017-09-18 09:48:00 INFO stdout:71 – 2017-09-18 09:48:00 DEBUG HttpSessionStorage:93 – Storing message a2iiedhi69h081391e3biag591i7a2f to session FVAX79n-fxixNnIApUrrLe2V 2017-09-18 09:48:00 DEBUG HttpSessionStorage:93 – Storing message a2iiedhi69h081391e3biag591i7a2f to session FVAX79n-fxixNnIApUrrLe2V 2017-09-18 09:48:00 INFO stdout:71 – 2017-09-18 09:48:00 INFO SAMLDefaultLogger:127 – AuthNRequest;SUCCESS;10.69.208.181;app1;pingidentity;;; 2017-09-18 09:48:00 INFO SAMLDefaultLogger:127 – AuthNRequest;SUCCESS;10.69.208.18;app1;pingidentity;;; 2017-09-18 09:48:00 INFO stdout:71 – 2017-09-18 09:48:00 DEBUG SecurityContextPersistenceFilter:97 – SecurityContextHolder now cleared, as request processing completed 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/favicon.ico’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/images/**’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/css/**’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/logout.jsp’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/saml/web/**’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterChainProxy:337 – /index.jsp at position 1 of 8 in additional filter chain; firing Filter: ‘SecurityContextPersistenceFilter’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG HttpSessionSecurityContextRepository:139 – HttpSession returned null object for SPRING_SECURITY_CONTEXT 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG HttpSessionSecurityContextRepository:85 – No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@2f3ea906. A new one will be created. 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterChainProxy:337 – /index.jsp at position 2 of 8 in additional filter chain; firing Filter: ‘FilterChainProxy’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/saml/login/**’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/saml/logout/**’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/saml/metadata/**’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/saml/sso/**’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/saml/ssohok/**’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/saml/singlelogout/**’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AntPathRequestMatcher:103 – Checking match of request : ‘/index.jsp’; against ‘/saml/discovery/**’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterChainProxy:180 – /index.jsp has no matching filters 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterChainProxy:337 – /index.jsp at position 3 of 8 in additional filter chain; firing Filter: ‘RequestCacheAwareFilter’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG DefaultSavedRequest:309 – pathInfo: both null (property equals) 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG DefaultSavedRequest:309 – queryString: both null (property equals) 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG DefaultSavedRequest:325 – requestURI: arg1=/app1/; arg2=/app1/ (property equals) 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG DefaultSavedRequest:325 – serverPort: arg1=8443; arg2=8443 (property equals) 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG DefaultSavedRequest:325 – requestURL: arg1=https://xxxwm07.integration.company.at:8443/app1/; arg2=https://xxxwm07.integration.company.at:8443/app1/ (property equals) 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG DefaultSavedRequest:325 – scheme: arg1=https; arg2=https (property equals) 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG DefaultSavedRequest:325 – serverName: arg1=xxxwm07.integration.company.at; arg2=xxxwm07.integration.company.at (property equals) 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG DefaultSavedRequest:325 – contextPath: arg1=/app1; arg2=/app1 (property equals) 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG DefaultSavedRequest:325 – servletPath: arg1=/index.jsp; arg2=/index.jsp (property equals) 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG HttpSessionRequestCache:62 – Removing DefaultSavedRequest from session if present 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterChainProxy:337 – /index.jsp at position 4 of 8 in additional filter chain; firing Filter: ‘SecurityContextHolderAwareRequestFilter’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterChainProxy:337 – /index.jsp at position 5 of 8 in additional filter chain; firing Filter: ‘AnonymousAuthenticationFilter’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AnonymousAuthenticationFilter:102 – Populated SecurityContextHolder with anonymous token: ‘org.springframework.security.authentication.AnonymousAuthenticationToken@905571d8: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@0: RemoteIpAddress: 10.69.208.181; SessionId: FVAX79n-fxixNnIApUrrLe2V; Granted Authorities: ROLE_ANONYMOUS’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterChainProxy:337 – /index.jsp at position 6 of 8 in additional filter chain; firing Filter: ‘SessionManagementFilter’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterChainProxy:337 – /index.jsp at position 7 of 8 in additional filter chain; firing Filter: ‘ExceptionTranslationFilter’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterChainProxy:337 – /index.jsp at position 8 of 8 in additional filter chain; firing Filter: ‘FilterSecurityInterceptor’ 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterSecurityInterceptor:194 – Secure object: FilterInvocation: URL: /index.jsp; Attributes: [IS_AUTHENTICATED_FULLY] 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG FilterSecurityInterceptor:310 – Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@905571d8: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@0: RemoteIpAddress: 10.69.208.18; SessionId: FVAX79n-fxixNnIApUrrLe2V; Granted Authorities: ROLE_ANONYMOUS 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AffirmativeBased:65 – Voter: org.springframework.security.access.vote.RoleVoter@18d957ee, returned: 0 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG AffirmativeBased:65 – Voter: org.springframework.security.access.vote.AuthenticatedVoter@651bd700, returned: -1 2017-09-18 09:48:01 INFO stdout:71 – 2017-09-18 09:48:01 DEBUG ExceptionTranslationFilter:165 – Access is denied (user is anonymous); redirecting to authentication entry point 2017-09-18 09:48:01 INFO stdout:71 – org.springframework.security.access.AccessDeniedException: Access is denied 2017-09-18 09:48:01 INFO stdout:71 – at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) I am about to go back to debug spring security, but if you have any tips, would be awesome. as you can see in this spring sec log, all looks ok with ping, the role voter is ok, then the authenticated user voter fails. and why do I end up with anonymousUser after a good ping authentication? seems some user principle needs to be mapped from ping to spring, yes?

If only a tip on where to start in my Spring Security debug, would be quite helpful...

Thanks in advance

Both IdP and SP config in Spring SAML Sample app are file based. Here are the details:

*******securityConext.xml

<bean id="metadata"
    class="org.springframework.security.saml.metadata.CachingMetadataManager">
    <constructor-arg>
        <list>
            <!-- IDP Metadata configuration -->
            <bean
                class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
                <constructor-arg>
                    <bean
                        class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
                        <constructor-arg>
                            <bean class="java.util.Timer" />
                        </constructor-arg>
                        <constructor-arg>
                            <bean class="org.opensaml.util.resource.ClasspathResource">
                                <constructor-arg value="/metadata/idp.xml" />
                            </bean>
                        </constructor-arg>
                        <property name="parserPool" ref="parserPool" />
                    </bean>
                </constructor-arg>
                <constructor-arg>
                    <bean
                        class="org.springframework.security.saml.metadata.ExtendedMetadata" />
                </constructor-arg>
                <property name="metadataTrustCheck" value="false" />

            </bean>

            <!-- SP Metadata configuration -->
            <bean
                class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
                <constructor-arg>
                    <bean
                        class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
                        <constructor-arg>
                            <bean class="java.util.Timer" />
                        </constructor-arg>
                        <constructor-arg>
                            <bean class="org.opensaml.util.resource.ClasspathResource">
                                <constructor-arg value="/metadata/sp.xml" />
                            </bean>
                        </constructor-arg>
                        <property name="parserPool" ref="parserPool" />
                    </bean>
                </constructor-arg>
                <constructor-arg>
                    <bean
                        class="org.springframework.security.saml.metadata.ExtendedMetadata">
                        <property name="local" value="true" />
                        <property name="securityProfile" value="pkix" />
                        <property name="sslSecurityProfile" value="pkix" />
                        <property name="sslHostnameVerification" value="default" />
                        <property name="signMetadata" value="false" />
                        <property name="signingKey" value="ping" />
                        <property name="encryptionKey" value="mykey" />
                        <property name="tlsKey" value="ping" />
                        <property name="requireArtifactResolveSigned" value="false" />
                        <property name="requireLogoutRequestSigned" value="false" />
                        <property name="requireLogoutResponseSigned" value="false" />
                        <property name="idpDiscoveryEnabled" value="false" />
                        <property name="idpDiscoveryURL" value="http://www.google.com" />
                        <property name="idpDiscoveryResponseURL" value="http://www.google.com" />
                    </bean>
                </constructor-arg>
            </bean>

        </list>
    </constructor-arg>
    <!-- OPTIONAL used when one of the metadata files contains information 
        about this service provider -->
    <!-- <property name="hostedSPName" value=""/> -->
    <!-- OPTIONAL property: can tell the system which IDP should be used for 
        authenticating user by default. -->
    <!-- <property name="defaultIDP" value="http://localhost:8080/opensso"/> -->
</bean>

*****idp.xml

<md:EntityDescriptor ID="jWQF6vBDwO-0.YYnI3YL91qXp-O"
cacheDuration="PT1440M" entityID="pingidentity" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"
    WantAuthnRequestsSigned="false">
    <md:KeyDescriptor use="signing">
        <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:X509Data>
                <ds:X509Certificate>MIIDQD...q9kMuY=
                </ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:KeyDescriptor use="encryption">
        <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:X509Data>
                <ds:X509Certificate>MIID...q9kMuY=
                </ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:ArtifactResolutionService index="0"
        Location="https://xxxwm07.integration.company.at:9031/idp/ARS.ssaml2"
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" isDefault="true" />
    <md:SingleLogoutService
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
        Location="https://xxxwm07.integration.company.at:9031/idp/SLO.saml2" />
    <md:SingleLogoutService
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://xxxwm07.integration.company.at:9031/idp/SLO.saml2" />
    <md:SingleLogoutService
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
        Location="https://xxxwm07.integration.company.at:9031/idp/SLO.saml2" />
    <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
        Location="https://xxxwm07.integration.company.at:9031/idp/SLO.ssaml2" />
    <md:SingleSignOnService
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://xxxwm07.integration.company.at:9031/idp/SSO.saml2" />
    <md:SingleSignOnService
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
        Location="https://xxxwm07.integration.company.at:9031/idp/SSO.saml2" />
    <md:SingleSignOnService
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
        Location="https://xxxwm07.integration.company.at:9031/idp/SSO.saml2" />
    <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
        Location="https://xxxwm07.integration.company.at:9031/idp/SSO.saml2" />
    <saml:Attribute Name="subject"
        NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
        xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" />
</md:IDPSSODescriptor>
<md:AttributeAuthorityDescriptor
    protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <md:AttributeService
        Location="https://xxxwm07.integration.company.at:9031/idp/attrsvc.ssaml2"
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" />
</md:AttributeAuthorityDescriptor>
<md:ContactPerson contactType="administrative" />

****sp.xml

<md:EntityDescriptor ID="U.NC.JbPpTmbfH8OQy8l9EhyRBl"
cacheDuration="PT1440M" entityID="app1" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <md:KeyDescriptor use="signing">
        <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:X509Data>
                <ds:X509Certificate>MIID....kMuY=
                </ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:KeyDescriptor use="encryption">
        <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:X509Data>
                <ds:X509Certificate>MIID....uY=
                </ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:ArtifactResolutionService index="0"
        Location="https://xxxwm07.integration.company.at:9031/sp/ARS.ssaml2"
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" isDefault="true" />
    <md:SingleLogoutService
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
        Location="https://xxxwm07.integration.company.at:9031/sp/SLO.saml2" />
    <md:SingleLogoutService
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://xxxwm07.integration.company.at:9031/sp/SLO.saml2" />
    <md:SingleLogoutService
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
        Location="https://xxxwm07.integration.company.at:9031/sp/SLO.saml2" />
    <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
        Location="https://xxxwm07.integration.company.at:9031/sp/SLO.ssaml2" />
    <md:AssertionConsumerService index="0"
        Location="https://xxxwm07.integration.company.at:9031/sp/ACS.saml2"
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" isDefault="true" />
    <md:AssertionConsumerService index="1"
        Location="https://xxxwm07.integration.company.at:9031/sp/ACS.saml2"
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" />
    <md:AssertionConsumerService index="2"
        Location="https://xxxwm07.integration.company.at:9031/sp/ACS.saml2"
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" />
    <md:AttributeConsumingService index="0">
        <md:ServiceName xml:lang="en">AttributeContract
        </md:ServiceName>
        <md:RequestedAttribute Name="subject" />
    </md:AttributeConsumingService>
</md:SPSSODescriptor>
<md:ContactPerson contactType="administrative" />

***here is the solution sp.xml generated from sample app

    <?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
    ID="app1" entityID="app1">
    <md:SPSSODescriptor AuthnRequestsSigned="true"
        WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <md:KeyDescriptor use="signing">
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>MIIDQDCCAiigAwIBAg...wq9kMuY=
                    </ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </md:KeyDescriptor>
        <md:KeyDescriptor use="encryption">
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>MIIDQDCCAiigAwIBAgIGAVzUOBXsMA0GCSqGSIb3DQEBCwUAMGExCzAJBgNVBAYTAkFUMSgwJgYD
                        VQQKEx9ldzd1aXB3bTA3LmludGVncmF0...q9kMuY=
                    </ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </md:KeyDescriptor>
        <md:SingleLogoutService
            Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
            Location="https://host1:8443/app1/saml/SingleLogout" />
        <md:SingleLogoutService
            Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
            Location="https://host1:8443/app1/saml/SingleLogout" />
        <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
        </md:NameIDFormat>
        <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient
        </md:NameIDFormat>
        <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
        </md:NameIDFormat>
        <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
        </md:NameIDFormat>
        <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
        </md:NameIDFormat>
        <md:AssertionConsumerService
            Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://host1:8443/app1/saml/SSO"
            index="0" isDefault="true" />
    </md:SPSSODescriptor>
</md:EntityDescriptor>

回答1:

Check the Spring SAML metadata you import to Ping Identity. It seems to contain a different AssertionConsumerURL than what Spring SAML sends in its SAML Authentication Request:

https://xxxwm07.integration.company.at:9031/sp/ACS.saml2