Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring SAML:更新元数据提供程序不会更新使用的签名证书_Java_Spring_Spring Saml - Fatal编程技术网

Java Spring SAML:更新元数据提供程序不会更新使用的签名证书

Java Spring SAML:更新元数据提供程序不会更新使用的签名证书,java,spring,spring-saml,Java,Spring,Spring Saml,我最近实现了一个Spring SAML解决方案,它允许客户向服务注册他们的IdP元数据,并使用他们的SAML身份验证来访问我的SP IdP元数据作为自定义AbstractReloadingMetadataProvider实现的一部分存储为数据库条目,建议如下: 更新元数据时,我将元数据XML保存到数据库中,并从CachingMetadataManager中删除元数据提供程序的前一个实例。然后,我将证书从元数据导入本地密钥库,并将新的元数据提供程序实例添加到CachingMetadataMan

我最近实现了一个Spring SAML解决方案,它允许客户向服务注册他们的IdP元数据,并使用他们的SAML身份验证来访问我的SP

IdP元数据作为自定义AbstractReloadingMetadataProvider实现的一部分存储为数据库条目,建议如下:



更新元数据时,我将元数据XML保存到数据库中,并从CachingMetadataManager中删除元数据提供程序的前一个实例。然后,我将证书从元数据导入本地密钥库,并将新的元数据提供程序实例添加到CachingMetadataManager:

@Autowired
private MetadataManager       metadataManager;

...

/**
 * Update our existing IdP metadata provider with new XML and other information
 */
public void updateIdpMetadata(IdPRegistrationData _data) throws RequiredDataException, NotFoundException, SystemException {
  IdpProviderData           provider;
  XMLObject                 xml;
  String                    metadataXml;
  EntityDescriptor          entity;
  String                    entityId;

  try {

    // validation
    validateIdpRegistrationData(_data);

    //ensure our top level DOM element is the IDPSSO entity descriptor, removing all other metadata
    xml         = parseMetadataXml(_data.getMetadataXml());
    entity      = getIDPSSOParentEntityDescriptor(xml);
    entityId    = entity.getEntityID();
    metadataXml = serialize(entity);

    // get our provider Data
    provider    = getIdpByAccountSysid(_data.getAccountSysid());

    if ( null == provider) {
      throw new NotFoundException(NotFoundExceptionType.ACCOUNT);
    }

    // update our provider
    provider.setEntityId(entityId);
    provider.setMetadataBody(metadataXml);

    // save data in database
    metadataStoreDao.saveAndFlush(provider);
    keystoreMgr.importMetadataCertificates(xml, provider.getUrlContext());

    // remove existing provider from metadata store
    removeDelegateFromManager(entityId);

    // reintroduce delegate to manager
    loadIdpMetadata(provider);

  }
  catch(NotFoundException e) {
    log.error("No previous version of IDP registration metadata found to update.",e);
    throw (e);
  }
  catch (MetadataProviderException e){
    log.error("Failed to update Keystore and Signing algorithm of IdP Metadata.",e);
    throw new SystemException("Failed to update certificates.");
  }
  catch(RequiredDataException e) {
    log.error("Missing required data for update.",e);
    throw(e);
  }

}

/**
 * Remove the metadata provider from our manager
 */
private void removeDelegateFromManager( String _entityId ) throws MetadataProviderException {
  ExtendedMetadataDelegate  delegate;
  DbIdpMetadataProvider     provider;

  delegate  = findMetadataDelegate(_entityId);

  if( null == delegate){
    log.error("Failed to find Delegate in metadata manager for Entity ID: " + _entityId );
    return;
  }

  metadataManager.removeMetadataProvider(delegate);
  provider = (DbIdpMetadataProvider)delegate.getDelegate();
  provider.destroy();
  metadataManager.setRefreshRequired(true);
  metadataManager.refreshMetadata();

}    

/**
 * load our provider data to a metadata provider object
 */
private void loadIdpMetadata(IdpProviderData _providerData) throws MetadataProviderException {
  DbIdpMetadataProvider idpProvider;

  // initialize our IdP provider
  idpProvider     = new DbIdpMetadataProvider(_providerData);
  idpProvider.setParserPool(parser);
  addIdpToMetadataManager(idpProvider);

}

/**
 * Add the metadata provider to our cache
 */
private void addIdpToMetadataManager(DbIdpMetadataProvider _provider) throws MetadataProviderException {
  ExtendedMetadataDelegate  delegate;
  ExtendedMetadata          extMeta = new ExtendedMetadata();

  // initialize our provider
  _provider.initialize();

  extMeta     = createExtendedMetadata(_provider);

  delegate    = new ExtendedMetadataDelegate(_provider, extMeta);
  delegate.setMetadataTrustCheck(false);
  delegate.initialize();

  metadataManager.addMetadataProvider(delegate);
  metadataManager.setRefreshRequired(true);
  metadataManager.refreshMetadata();
}
问题在于,当刷新数据库条目时,IdP元数据中元素中定义的新签名证书不会应用

打印元数据XML时,我可以看到新证书:



MIIC4jCCAcqgAwIBAgIQafZAY7。。。
MIIC3DCCAcSgAwIBAgIQeny6jM。。。
MIIC3DCCAcSgAwIBAgIQRtno3W。。。
SP启动登录时,我收到来自我的IdP的成功SAML响应:



http://{mydomain}/adfs/services/trust
http://{mydomain}/adfs/services/trust
x/PKYQXDECME2IBNIZ0PQET3HQYGDWLBEO1VB3GXD8=
UvhpsDE7XT1uvqGbA+IZ2sC9t8x0i42/P7tdNXO。。。
MIIC3DCCAcSgAwIBAgIQRtno3W。。。
用户ID
https://{my domain}/eas saml
用户ID
user@domain.com
urn:oasis:name:tc:SAML:2.0:ac:classes:PasswordProtectedTransport

其中,日志输出显示以下堆栈跟踪的故障:


2018-10-17 18:31:47信息样本故障记录器:129-验证响应;失败;172.17.0.1;https://{my domain}/eas saml;http://{mydomain}/adfs/services/trust;;;org.opensaml.common.SAMLException:响应没有任何可以通过主题验证的有效断言 位于org.springframework.security.saml.webso.websoprofileConsumerImpl.processAuthenticationResponse(websoprofileConsumerImpl.java:229) 位于org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:88) 位于org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) 位于org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:92) 位于org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) 位于org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 位于org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) 位于org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186) 位于org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 位于org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) 位于org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 位于org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 位于org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) 位于org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 位于org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 位于org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) 位于org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 位于org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) 位于org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) 原因:org.opensaml.xml.validation.ValidationException:签名不可信或无效 位于org.springframework.security.saml.webso.AbstractProfileBase.verifySignature(AbstractProfileBase.java:272) 位于org.springframework.security.saml.webso.websoprofileConsumerImpl.verifyAssertionSignature(websoprofileConsumerImpl.java:419) 位于org.springframework.security.saml.webso.websoprofileConsumerImpl.verifyAssertion(websoprofileConsumerImpl.java:292) 位于org.springframework.security.saml.webso.websoprofileConsumerImpl.processAuthenticationResponse(websoprofileConsumerImpl.java:214) ... 39多
如果我重新启动服务,签名将被识别并成功处理响应

有人能看出我做错了什么吗?元数据管理器的刷新不足以允许使用新证书吗?还是我遗漏了一个步骤?

我在

由于我当前使用的是XML配置文件,我修改了安全上下文XML以设置凭证解析器,如下所示:

<!-- Provider of default SAML Context -->
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl">
  <property name="metadataResolver">
            <bean class="com.mydomain.CustomMetadataCredentialResolver">
                <constructor-arg index="0" ref="metadata" />
                <constructor-arg index="1" ref="keyManager" />
                <property name="useXmlMetadata" value="true" />
            </bean>
  </property> 
</bean>
我可能会在命令上清除缓存,而不是从不缓存凭据,但现在它可以工作了

  <!--  new signing key  -->
  <IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <KeyDescriptor use="encryption">
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <X509Data>
          <X509Certificate>MIIC4jCCAcqgAwIBAgIQafZAY7...</X509Certificate>
        </X509Data>
      </KeyInfo>
    </KeyDescriptor>
    <KeyDescriptor use="signing">
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <X509Data>
          <X509Certificate>MIIC3DCCAcSgAwIBAgIQeny6jM...</X509Certificate>
        </X509Data>
      </KeyInfo>
    </KeyDescriptor>
    <KeyDescriptor use="signing">
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <X509Data>
          <X509Certificate>MIIC3DCCAcSgAwIBAgIQRtno3W...</X509Certificate>
        </X509Data>
      </KeyInfo>
<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" Destination="https://{my-domain}:443/eas-saml/saml/SSO" ID="_0d023fb8-bf24-4b78-b690-c9b53df4db72" InResponseTo="a22h6bb0gf2e8f314e00316b198ddg1" IssueInstant="2018-10-17T18:31:47.332Z" Version="2.0">
   <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://{my-domain}/adfs/services/trust</Issuer>
   <samlp:Status>
      <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
   </samlp:Status>
   <Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="_317d062d-247e-4405-9dd8-0ef3d032bf3f" IssueInstant="2018-10-17T18:31:47.332Z" Version="2.0">
      <Issuer>http://{my-domain}/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="#_8049000b-6e76-416c-84aa-180d61ca359a">
               <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>x/PKyqXDECmE2IBNiZ0pqet3HqQYgDwlbeo1Vb3gXD8=</ds:DigestValue>
            </ds:Reference>
         </ds:SignedInfo>
         <ds:SignatureValue>UvhpsDE7XT1uvqGbA+IZ2sC9t8x0i42/P7tdNXO...</ds:SignatureValue>
         <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <ds:X509Data>
               <ds:X509Certificate>MIIC3DCCAcSgAwIBAgIQRtno3W...</ds:X509Certificate>
            </ds:X509Data>
         </KeyInfo>
      </ds:Signature>
      <Subject>
         <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">userId</NameID>
         <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
            <SubjectConfirmationData InResponseTo="a22h6bb0gf2e8f314e00316b198ddg1" NotOnOrAfter="2018-10-17T18:36:47.332Z" Recipient="https://{my-domain}:443/eas-saml/saml/SSO"/>
         </SubjectConfirmation>
      </Subject>
      <Conditions NotBefore="2018-10-17T18:31:47.327Z" NotOnOrAfter="2018-10-17T18:33:47.327Z">
         <AudienceRestriction>
            <Audience>https://{my-domain}/eas-saml</Audience>
         </AudienceRestriction>
      </Conditions>
      <AttributeStatement>
         <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn">
            <AttributeValue>userId</AttributeValue>
         </Attribute>
         <Attribute Name="http://E-Mail-Addresses">
            <AttributeValue>user@domain.com</AttributeValue>
         </Attribute>
      </AttributeStatement>
      <AuthnStatement AuthnInstant="2018-10-17T18:31:47.233Z" SessionIndex="_317d062d-247e-4405-9dd8-0ef3d032bf3f">
         <AuthnContext>
            <AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef>
         </AuthnContext>
      </AuthnStatement>
   </Assertion>
</samlp:Response>
2018-10-17 18:31:47 INFO SAMLDefaultLogger:129 - AuthNResponse;FAILURE;172.17.0.1;https://{my-domain}/eas-saml;http://{my-domain}/adfs/services/trust;;;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:88) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:92) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 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:334) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) Caused by: org.opensaml.xml.validation.ValidationException: Signature is not trusted or invalid at org.springframework.security.saml.websso.AbstractProfileBase.verifySignature(AbstractProfileBase.java:272) at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertionSignature(WebSSOProfileConsumerImpl.java:419) at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertion(WebSSOProfileConsumerImpl.java:292) at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:214) ... 39 more
<!-- Provider of default SAML Context -->
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl">
  <property name="metadataResolver">
            <bean class="com.mydomain.CustomMetadataCredentialResolver">
                <constructor-arg index="0" ref="metadata" />
                <constructor-arg index="1" ref="keyManager" />
                <property name="useXmlMetadata" value="true" />
            </bean>
  </property> 
</bean>
@Component
public class CustomMetadataCredentialResolver extends MetadataCredentialResolver {

  public CustomMetadataCredentialResolver(MetadataManager metadataProvider, KeyManager keyManager) {
    super(metadataProvider, keyManager);
  }

  @Override
  protected void cacheCredentials( MetadataCacheKey cacheKey, Collection<Credential> credentials ) {
    //no-op
  }
}