title: How to configure Spring Security SAML extension for Holder-of-key profile
body: <p>I tried to use SAML <strong>Holder-of-key</strong> profile of Spring Security SAML extension, but I didn't succeed, I even googled it but did not find any related documents or samples.</p>
  <p><strong>I added the following tag to the tomcat config (server.xml file) to enable HTTPS scheme and client authentication:</strong></p>
  <pre><code>&lt;Connector port=&quot;8443&quot; SSLEnabled=&quot;true&quot; scheme=&quot;https&quot; secure=&quot;true&quot; clientAuth=&quot;want&quot; sslProtocol=&quot;TLS&quot; keystoreFile=&quot;ks.keystore&quot; keystorePass=&quot;password&quot; truststoreFile=&quot;ts.keystore&quot; truststorePass=&quot;password&quot;/&gt;
  </code></pre>
  <p>This config seems to work, since when I access my application website, it request for client certificate and sends the AuthN Request to the IdP. The IdP validates the request <strong>but does not ask for client certificate</strong> and in response, it returns an assertion without HoK subject confirmation and I get the following error:</p>
  <pre><code>org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
  at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:95)
  at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
  at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
  at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
  at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
  at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
  at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
  at org.springframework.security.web.access.channel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:152)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
  at org.springframework.security.saml.metadata.MetadataGeneratorFilter.doFilter(MetadataGeneratorFilter.java:87)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
  at org.springframework.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:75)
  at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:62)
  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:221)
  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:107)
  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:76)
  at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:934)
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:90)
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:515)
  at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1012)
  at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:642)
  at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1555)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
  at java.lang.Thread.run(Thread.java:744)
  Caused by: org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
  at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:229)
  at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:84)
  ... 43 more
  Caused by: org.opensaml.common.SAMLException: Assertion invalidated by subject confirmation - can't be confirmed by holder-of-key method
  at org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl.verifySubject(WebSSOProfileConsumerHoKImpl.java:150)
  at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertion(WebSSOProfileConsumerImpl.java:296)
  at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:214)
  ... 44 more
  </code></pre>
  <p><strong>This is my Spring Security configuration:</strong></p>
  <pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
  &lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         xmlns:security=&quot;http://www.springframework.org/schema/security&quot;
         xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
         xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/security
         http://www.springframework.org/schema/security/spring-security.xsd&quot;&gt;
  
  
         &lt;context:annotation-config/&gt;
         &lt;security:debug/&gt;
  
         &lt;context:component-scan base-package=&quot;org.springframework.security.saml&quot; /&gt;
  
         &lt;security:http entry-point-ref=&quot;samlEntryPoint&quot; use-expressions=&quot;false&quot;&gt;
                &lt;security:csrf disabled=&quot;true&quot; /&gt;
                &lt;security:intercept-url pattern=&quot;/**&quot; access=&quot;IS_AUTHENTICATED_FULLY&quot; requires-channel=&quot;https&quot; /&gt;
                &lt;security:custom-filter before=&quot;FIRST&quot; ref=&quot;metadataGeneratorFilter&quot; /&gt;
                &lt;security:custom-filter after=&quot;BASIC_AUTH_FILTER&quot; ref=&quot;samlFilter&quot; /&gt;
         &lt;/security:http&gt;
  
         &lt;!-- Filter automatically generates default SP metadata --&gt;
         &lt;bean id=&quot;metadataGeneratorFilter&quot; class=&quot;org.springframework.security.saml.metadata.MetadataGeneratorFilter&quot;&gt;
                &lt;constructor-arg&gt;
                       &lt;bean class=&quot;org.springframework.security.saml.metadata.MetadataGenerator&quot;&gt;
                              &lt;property name=&quot;bindingsHoKSSO&quot;&gt;
                                     &lt;list&gt;
                                            &lt;value&gt;post&lt;/value&gt;
                                            &lt;value&gt;artifact&lt;/value&gt;
                                     &lt;/list&gt;
                              &lt;/property&gt;
                              &lt;property name=&quot;entityBaseURL&quot; value=&quot;https://localhost:8443&quot; /&gt;
                              &lt;property name=&quot;extendedMetadata&quot;&gt;
                                     &lt;bean class=&quot;org.springframework.security.saml.metadata.ExtendedMetadata&quot;&gt;
                                            &lt;property name=&quot;signMetadata&quot; value=&quot;true&quot;/&gt;
                                            &lt;property name=&quot;idpDiscoveryEnabled&quot; value=&quot;true&quot;/&gt;
                                     &lt;/bean&gt;
                              &lt;/property&gt;
                       &lt;/bean&gt;
                &lt;/constructor-arg&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;samlFilter&quot; class=&quot;org.springframework.security.web.FilterChainProxy&quot;&gt;
                &lt;security:filter-chain-map request-matcher=&quot;ant&quot;&gt;
                       &lt;security:filter-chain pattern=&quot;/saml/login/**&quot; filters=&quot;samlEntryPoint&quot; /&gt;
                       &lt;security:filter-chain pattern=&quot;/saml/SSO/**&quot; filters=&quot;samlWebSSOProcessingFilter&quot; /&gt;
                       &lt;security:filter-chain pattern=&quot;/saml/HoKSSO&quot; filters=&quot;samlWebSSOHoKProcessingFilter&quot; /&gt;
                       &lt;security:filter-chain pattern=&quot;/saml/metadata/**&quot; filters=&quot;metadataDisplayFilter&quot;/&gt;
                       &lt;security:filter-chain pattern=&quot;/saml/discovery/**&quot; filters=&quot;samlIDPDiscovery&quot;/&gt;
                       &lt;security:filter-chain pattern=&quot;/saml/logout/**&quot; filters=&quot;samlLogoutFilter&quot; /&gt;
                       &lt;security:filter-chain pattern=&quot;/saml/single_logout/**&quot; filters=&quot;samlLogoutProcessingFilter&quot; /&gt;
                &lt;/security:filter-chain-map&gt;
         &lt;/bean&gt;
  
         &lt;!-- LOGOUT --&gt;
         &lt;!-- (Local Logout) Override default logout processing filter with the one processing SAML messages --&gt;
         &lt;bean id=&quot;samlLogoutFilter&quot; class=&quot;org.springframework.security.saml.SAMLLogoutFilter&quot;&gt;
                &lt;constructor-arg index=&quot;0&quot; ref=&quot;successLogoutHandler&quot;/&gt;
                &lt;constructor-arg index=&quot;1&quot; ref=&quot;logoutHandler&quot;/&gt;
                &lt;constructor-arg index=&quot;2&quot; ref=&quot;logoutHandler&quot;/&gt;
         &lt;/bean&gt;
  
         &lt;!-- (Single Logout) Filter processing incoming logout messages --&gt;
         &lt;!-- First argument determines URL user will be redirected to after successful global logout --&gt;
         &lt;bean id=&quot;samlLogoutProcessingFilter&quot; class=&quot;org.springframework.security.saml.SAMLLogoutProcessingFilter&quot;&gt;
                &lt;constructor-arg index=&quot;0&quot; ref=&quot;successLogoutHandler&quot;/&gt;
                &lt;constructor-arg index=&quot;1&quot; ref=&quot;logoutHandler&quot;/&gt;
         &lt;/bean&gt;
  
         &lt;!-- Handler for successful logout --&gt;
         &lt;bean id=&quot;successLogoutHandler&quot; class=&quot;org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler&quot;&gt;
                &lt;property name=&quot;defaultTargetUrl&quot; value=&quot;/logout.jsp&quot;/&gt;
         &lt;/bean&gt;
  
         &lt;!-- Logout handler terminating local session --&gt;
         &lt;bean id=&quot;logoutHandler&quot; class=&quot;org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler&quot;&gt;
                &lt;property name=&quot;invalidateHttpSession&quot; value=&quot;false&quot;/&gt;
         &lt;/bean&gt;
  
         &lt;!-- SAML 2.0 Logout Profile --&gt;
         &lt;bean id=&quot;logoutprofile&quot; class=&quot;org.springframework.security.saml.websso.SingleLogoutProfileImpl&quot;/&gt;
  
         &lt;!-- IDP Discovery Service --&gt;
         &lt;bean id=&quot;samlIDPDiscovery&quot; class=&quot;org.springframework.security.saml.SAMLDiscovery&quot;&gt;
                &lt;property name=&quot;idpSelectionPath&quot; value=&quot;/idpSelection.jsp&quot;/&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;metadataDisplayFilter&quot; class=&quot;org.springframework.security.saml.metadata.MetadataDisplayFilter&quot; /&gt;
  
         &lt;!-- Processing filter for WebSSO Holder-of-Key profile --&gt;
         &lt;bean id=&quot;samlWebSSOHoKProcessingFilter&quot; class=&quot;org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter&quot;&gt;
                &lt;property name=&quot;authenticationManager&quot; ref=&quot;authenticationManager&quot;/&gt;
                &lt;property name=&quot;authenticationSuccessHandler&quot; ref=&quot;successRedirectHandler&quot;/&gt;
                &lt;property name=&quot;authenticationFailureHandler&quot; ref=&quot;failureRedirectHandler&quot;/&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;samlWebSSOProcessingFilter&quot; class=&quot;org.springframework.security.saml.SAMLProcessingFilter&quot;&gt;
                &lt;property name=&quot;authenticationManager&quot; ref=&quot;authenticationManager&quot; /&gt;
                &lt;property name=&quot;authenticationSuccessHandler&quot; ref=&quot;successRedirectHandler&quot; /&gt;
                &lt;property name=&quot;authenticationFailureHandler&quot; ref=&quot;failureRedirectHandler&quot; /&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;successRedirectHandler&quot; class=&quot;org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler&quot;&gt;
                &lt;property name=&quot;defaultTargetUrl&quot; value=&quot;/&quot; /&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;failureRedirectHandler&quot; class=&quot;org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler&quot;&gt;
                &lt;property name=&quot;useForward&quot; value=&quot;true&quot; /&gt;
                &lt;property name=&quot;defaultFailureUrl&quot; value=&quot;/error.jsp&quot; /&gt;
         &lt;/bean&gt;
  
         &lt;bean class=&quot;org.springframework.security.saml.trust.httpclient.TLSProtocolConfigurer&quot;&gt;
                &lt;property name=&quot;sslHostnameVerification&quot; value=&quot;default&quot;/&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;samlEntryPoint&quot; class=&quot;org.springframework.security.saml.SAMLEntryPoint&quot;&gt;
                &lt;property name=&quot;defaultProfileOptions&quot;&gt;
                       &lt;bean class=&quot;org.springframework.security.saml.websso.WebSSOProfileOptions&quot;&gt;
                              &lt;property name=&quot;assertionConsumerIndex&quot; value=&quot;2&quot; /&gt;
                              &lt;property name=&quot;binding&quot; value=&quot;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST&quot; /&gt;
                              &lt;property name=&quot;includeScoping&quot; value=&quot;false&quot; /&gt;
                       &lt;/bean&gt;
                &lt;/property&gt;
         &lt;/bean&gt;
         &lt;security:authentication-manager alias=&quot;authenticationManager&quot;&gt;
                &lt;security:authentication-provider ref=&quot;samlAuthenticationProvider&quot; /&gt;
         &lt;/security:authentication-manager&gt;
  
         &lt;bean id=&quot;metadata&quot; class=&quot;org.springframework.security.saml.metadata.CachingMetadataManager&quot;&gt;
                &lt;constructor-arg&gt;
                       &lt;list&gt;
                              &lt;bean class=&quot;org.springframework.security.saml.metadata.ExtendedMetadataDelegate&quot;&gt;
                                     &lt;constructor-arg&gt;
                                            &lt;bean class=&quot;org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider&quot;&gt;
                                                   &lt;constructor-arg&gt;
                                                          &lt;value type=&quot;java.io.File&quot;&gt;classpath:IS_metadata.xml&lt;/value&gt;
                                                   &lt;/constructor-arg&gt;
                                                   &lt;property name=&quot;parserPool&quot; ref=&quot;parserPool&quot;/&gt;
                                            &lt;/bean&gt;
                                     &lt;/constructor-arg&gt;
                                     &lt;constructor-arg&gt;
                                            &lt;bean class=&quot;org.springframework.security.saml.metadata.ExtendedMetadata&quot;&gt;
                                            &lt;/bean&gt;
                                     &lt;/constructor-arg&gt;
                              &lt;/bean&gt;
                       &lt;/list&gt;
                &lt;/constructor-arg&gt;
                &lt;!--&lt;property name=&quot;defaultIDP&quot; value=&quot;https://localhost:9443/samlsso&quot; /&gt;--&gt;
         &lt;/bean&gt;
  
         &lt;bean class=&quot;org.springframework.security.saml.SAMLBootstrap&quot; /&gt;
  
         &lt;bean id=&quot;samlAuthenticationProvider&quot; class=&quot;org.springframework.security.saml.SAMLAuthenticationProvider&quot; /&gt;
  
         &lt;!-- SAML 2.0 WebSSO Assertion Consumer --&gt;
         &lt;bean id=&quot;webSSOprofileConsumer&quot; class=&quot;org.springframework.security.saml.websso.WebSSOProfileConsumerImpl&quot; /&gt;
  
         &lt;!-- SAML 2.0 Web SSO profile --&gt;
         &lt;bean id=&quot;webSSOprofile&quot; class=&quot;org.springframework.security.saml.websso.WebSSOProfileImpl&quot; /&gt;
  
         &lt;!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer --&gt;
         &lt;bean id=&quot;hokWebSSOprofileConsumer&quot; class=&quot;org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl&quot; /&gt;
  
         &lt;!-- SAML 2.0 Holder-of-Key Web SSO profile --&gt;
         &lt;bean id=&quot;hokWebSSOProfile&quot; class=&quot;org.springframework.security.saml.websso.WebSSOProfileHoKImpl&quot; /&gt;
  
         &lt;!-- SAML 2.0 ECP profile --&gt;
         &lt;bean id=&quot;ecpprofile&quot; class=&quot;org.springframework.security.saml.websso.WebSSOProfileECPImpl&quot;/&gt;
  
         &lt;!-- Provider of default SAML Context --&gt;
         &lt;bean id=&quot;contextProvider&quot; class=&quot;org.springframework.security.saml.context.SAMLContextProviderImpl&quot;&gt;
                &lt;!--&lt;property name=&quot;metadataResolver&quot;&gt;
                       &lt;bean class=&quot;org.springframework.security.saml.trust.MetadataCredentialResolver&quot;&gt;
                              &lt;constructor-arg  index=&quot;0&quot; ref=&quot;metadata&quot; /&gt;
                              &lt;constructor-arg name=&quot;keyManager&quot; index=&quot;1&quot; ref=&quot;keyManager&quot; /&gt;
                              &lt;property name=&quot;useXmlMetadata&quot; value=&quot;false&quot; /&gt;
                       &lt;/bean&gt;
                &lt;/property&gt;--&gt;
                &lt;property name=&quot;storageFactory&quot;&gt;
                       &lt;bean class=&quot;org.springframework.security.saml.storage.EmptyStorageFactory&quot; /&gt;
                &lt;/property&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;samlLogger&quot; class=&quot;org.springframework.security.saml.log.SAMLDefaultLogger&quot; /&gt;
  
         &lt;bean id=&quot;keyManager&quot; class=&quot;org.springframework.security.saml.key.JKSKeyManager&quot;&gt;
                &lt;constructor-arg value=&quot;classpath:samlKeystore.jks&quot; /&gt;
                &lt;constructor-arg type=&quot;java.lang.String&quot; value=&quot;nalle123&quot; /&gt;
                &lt;constructor-arg&gt;
                       &lt;map&gt;
                              &lt;entry key=&quot;spalias&quot; value=&quot;nalle123&quot; /&gt;
                       &lt;/map&gt;
                &lt;/constructor-arg&gt;
                &lt;constructor-arg type=&quot;java.lang.String&quot; value=&quot;spalias&quot; /&gt;
         &lt;/bean&gt;
  
         &lt;!-- Class loading incoming SAML messages from httpRequest stream --&gt;
         &lt;bean id=&quot;processor&quot; class=&quot;org.springframework.security.saml.processor.SAMLProcessorImpl&quot;&gt;
                &lt;constructor-arg&gt;
                       &lt;list&gt;
                              &lt;ref bean=&quot;redirectBinding&quot; /&gt;
                              &lt;ref bean=&quot;postBinding&quot; /&gt;
                              &lt;ref bean=&quot;artifactBinding&quot; /&gt;
                              &lt;ref bean=&quot;soapBinding&quot; /&gt;
                              &lt;ref bean=&quot;paosBinding&quot; /&gt;
                       &lt;/list&gt;
                &lt;/constructor-arg&gt;
         &lt;/bean&gt;
  
         &lt;!-- Bindings, encoders and decoders used for creating and parsing messages --&gt;
         &lt;bean id=&quot;postBinding&quot; class=&quot;org.springframework.security.saml.processor.HTTPPostBinding&quot;&gt;
                &lt;constructor-arg ref=&quot;parserPool&quot; /&gt;
                &lt;constructor-arg ref=&quot;velocityEngine&quot; /&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;redirectBinding&quot; class=&quot;org.springframework.security.saml.processor.HTTPRedirectDeflateBinding&quot;&gt;
                &lt;constructor-arg ref=&quot;parserPool&quot; /&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;artifactBinding&quot; class=&quot;org.springframework.security.saml.processor.HTTPArtifactBinding&quot;&gt;
                &lt;constructor-arg ref=&quot;parserPool&quot; /&gt;
                &lt;constructor-arg ref=&quot;velocityEngine&quot; /&gt;
                &lt;constructor-arg&gt;
                       &lt;bean class=&quot;org.springframework.security.saml.websso.ArtifactResolutionProfileImpl&quot;&gt;
                              &lt;constructor-arg&gt;
                                     &lt;bean class=&quot;org.apache.commons.httpclient.HttpClient&quot;&gt;
                                            &lt;constructor-arg&gt;
                                                   &lt;bean class=&quot;org.apache.commons.httpclient.MultiThreadedHttpConnectionManager&quot; /&gt;
                                            &lt;/constructor-arg&gt;
                                     &lt;/bean&gt;
                              &lt;/constructor-arg&gt;
                              &lt;property name=&quot;processor&quot;&gt;
                                     &lt;bean class=&quot;org.springframework.security.saml.processor.SAMLProcessorImpl&quot;&gt;
                                            &lt;constructor-arg ref=&quot;soapBinding&quot; /&gt;
                                     &lt;/bean&gt;
                              &lt;/property&gt;
                       &lt;/bean&gt;
                &lt;/constructor-arg&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;soapBinding&quot; class=&quot;org.springframework.security.saml.processor.HTTPSOAP11Binding&quot;&gt;
                &lt;constructor-arg ref=&quot;parserPool&quot; /&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;paosBinding&quot; class=&quot;org.springframework.security.saml.processor.HTTPPAOS11Binding&quot;&gt;
                &lt;constructor-arg ref=&quot;parserPool&quot; /&gt;
         &lt;/bean&gt;
  
         &lt;!-- XML parser pool needed for OpenSAML parsing --&gt;
         &lt;bean id=&quot;parserPool&quot; class=&quot;org.opensaml.xml.parse.StaticBasicParserPool&quot; init-method=&quot;initialize&quot;&gt;
                &lt;property name=&quot;builderFeatures&quot;&gt;
                       &lt;map&gt;
                              &lt;entry key=&quot;http://apache.org/xml/features/dom/defer-node-expansion&quot; value=&quot;false&quot; /&gt;
                       &lt;/map&gt;
                &lt;/property&gt;
         &lt;/bean&gt;
  
         &lt;bean id=&quot;parserPoolHolder&quot; class=&quot;org.springframework.security.saml.parser.ParserPoolHolder&quot; /&gt;
  
         &lt;!-- Initialization of the velocity engine --&gt;
         &lt;bean id=&quot;velocityEngine&quot; class=&quot;org.springframework.security.saml.util.VelocityFactory&quot; factory-method=&quot;getEngine&quot; /&gt;
  &lt;/beans&gt;
  </code></pre>
  <p><strong>I am using WSO2 Identity Server v4.5.0 as IdP in this case, this is WSO2 IdP Metadata:</strong></p>
  <pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;md:EntityDescriptor xmlns:md=&quot;urn:oasis:names:tc:SAML:2.0:metadata&quot; xmlns:saml=&quot;urn:oasis:names:tc:SAML:2.0:assertion&quot; xmlns:ds=&quot;http://www.w3.org/2000/09/xmldsig#&quot; entityID=&quot;https://localhost:9443/samlsso&quot; validUntil=&quot;2023-09-23T06:57:15.396Z&quot;&gt;
      &lt;md:IDPSSODescriptor protocolSupportEnumeration=&quot;urn:oasis:names:tc:SAML:2.0:protocol&quot;&gt;
          &lt;md:KeyDescriptor use=&quot;signing&quot;&gt;
              &lt;ds:KeyInfo&gt;
                  &lt;ds:X509Data&gt;
                      &lt;ds:X509Certificate&gt;
                          MIIDXTCCAkWgAwIBAgIETYI6hjANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJJ
                          UjELMAkGA1UECBMCTkExDzANBgNVBAcTBlRlaHJhbjENMAsGA1UEChMEV1NPMjEQ
                          MA4GA1UECxMHV1NPMiBJUzERMA8GA1UEAxMIaG9zdG5hbWUwHhcNMTUwOTI3MDYy
                          NDE2WhcNMTUxMjI2MDYyNDE2WjBfMQswCQYDVQQGEwJJUjELMAkGA1UECBMCTkEx
                          DzANBgNVBAcTBlRlaHJhbjENMAsGA1UEChMEV1NPMjEQMA4GA1UECxMHV1NPMiBJ
                          UzERMA8GA1UEAxMIaG9zdG5hbWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
                          AoIBAQCOD3I08VYC+auzqP6sZbnejD40jtuDuX/IooDxzphysqeTaPVOq0Fquv9i
                          uIb6XfxGk1hbFiThriCynXAkxeNbmK2ByurRVoJBgdFcCB9JfbGNapVodAbVl9cR
                          5kXmMJAdqXFDOrMCluira/7HzR0SpoG6A41M/cOkJHq7qtdQlCBaC+L0C5KK+P6/
                          g4X1zKIt5+vmn1lnDDxdOlCUsv5xVgEYLai+2ArPCZzMxKwlGQ/yWoDky2HXRrnx
                          ja/vV0J1VeV86tVwyxMb4Bm4XKohrH5sVtzE296JoiPl3rLfGeWpYEO4DXfJYLbi
                          4+kUvQ4MXTcsSDwQI9aBwVhia8uVAgMBAAGjITAfMB0GA1UdDgQWBBT5CS2/DmR3
                          lWx35Pmf1jZwbYJpcTANBgkqhkiG9w0BAQsFAAOCAQEANU/dEo7hWpQEDaYvaZmN
                          IJbck5fqKw4bgbPE2D6ifaYdb4SxxbNL3eBHg1Hbr5hCwLuX4zeqS9D8mrGzWnap
                          ZgG88VtDl/Y75t9Q3/y8PaRzHKaijo6ydyewLRtumhxFf/nXVKod9kNSPrOorM+o
                          T/1ht+yfaxCeeK32aV/SLs42raPI3LAT2ZyPimiVhsou72jXD7st8aRhm21qliZq
                          Qezbz8MccO1peASUikh8ksXNzb6Uh/3o/ks03NJibBZXwgzXR/62KXq8+FRNKEy+
                          Ec0yudq7bSaBGalQ3SqLXycKP9/Ct58eI2qRVGa0RwqcieDZIspFCgbAlZ2+qIDU
                          rQ==
                      &lt;/ds:X509Certificate&gt;
                  &lt;/ds:X509Data&gt;
              &lt;/ds:KeyInfo&gt;
          &lt;/md:KeyDescriptor&gt;
          &lt;md:SingleLogoutService
                  Binding=&quot;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect&quot;
                  Location=&quot;https://localhost:9443/samlsso&quot;
                  ResponseLocation=&quot;https://localhost:9443/samlsso&quot;/&gt;
  
          &lt;md:SingleSignOnService
                  Binding=&quot;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST&quot;
                  Location=&quot;https://localhost:9443/samlsso&quot;/&gt;
  
          &lt;md:SingleSignOnService
                  Binding=&quot;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect&quot;
                  Location=&quot;https://localhost:9443/samlsso&quot;/&gt;
                  
          &lt;md:SingleSignOnService
                  Binding=&quot;urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser&quot;
                  hoksso:ProtocolBinding=&quot;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST&quot;
                  xmlns:hoksso=&quot;urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser&quot;
                  Location=&quot;https://localhost:9443/samlsso&quot;/&gt;
      &lt;/md:IDPSSODescriptor&gt;
  &lt;/md:EntityDescriptor&gt;
  </code></pre>
  <p>Can anyone help me configure Spring Security SAML to enable Holder-of-key profile correctly?</p>
  <h2><strong>Edit:</strong></h2>
  <p>OK, my bad. Since IdP does not ask for client certificate, it seems that this version of &quot;WSO2 IS&quot; I'm using (v4.5.0), does not support issuing SAML HoK subject confirmation assertions (I updated the question accordingly). I will try with the latest release of WSO2 Identity Server (v5.0.0) and share the results.</p>
  <p><strong>I'm still not sure whether my spring configuration is correct or not.</strong></p>
  <p>Thanks</p>