问题描述
我的Web应用程序已部署在Amazon ECS上,并使用ALB并从堡垒主机访问此应用程序。我将Okta用于SSO。登录页面成功重定向到Okta,并且在请求返回到应用程序服务器时进行身份验证之后,出现以下错误-
Caused by: org.opensaml.common.SAMLException: InResponsetoField of the Response doesn't correspond to sent message a491gda80cgh3a2b5bb3j8ebd515d2
at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:139)
我正在使用CustomSAMLContextProvider,并按照其他答案中的建议将MessageStorageFactory设置为EmptyStorageFactory。 我不确定为什么仍在进行此检查。
这是我的自定义SAMLContextProviderImpl类-
public class SAMLMultipleEndpointContextProvider extends SAMLContextProviderImpl {
/**
* Creates a SAMLContext with local entity values filled. LocalEntityId is set to server name of the request. Also
* request and response must be stored in the context as message transports.
*
* @param request request
* @param response response
* @return context
* @throws MetadataProviderException in case of Metadata problems
*/
@Override
public SAMLMessageContext getLocalEntity(HttpServletRequest request,HttpServletResponse response) throws MetadataProviderException {
SAMLMessageContext context = new SAMLMessageContext();
populateGenericContext(request,response,context);
populateLocalEntityId(context,request.getServerName());
populateLocalContext(context);
return context;
}
/**
* Creates a SAMLContext with local entity and peer values filled. LocalEntityId is set to server name of the
* request. Also request and response must be stored in the context as message transports. Should be used when both
* local entity and peer entity can be determined from the request.
*
* @param request request
* @param response response
* @return context
* @throws MetadataProviderException in case of Metadata problems
*/
@Override
public SAMLMessageContext getLocalAndPeerEntity(HttpServletRequest request,request.getServerName());
populateLocalContext(context);
populatePeerEntityId(context);
populatePeerContext(context);
return context;
}
/**
* Populate LocalEntityId with retrieved entityId from Metadata manager using given localAlias parameter value.
*/
@Override
public void populateLocalEntityId(SAMLMessageContext context,String localAlias) throws MetadataProviderException {
String entityId = Metadata.getEntityIdForAlias(localAlias);
QName localEntityRole = SPSSODescriptor.DEFAULT_ELEMENT_NAME;
if (entityId == null) {
throw new MetadataProviderException("No local entity found for alias " + localAlias + ",verify your configuration.");
} else {
logger.debug("Using SP {} specified in request with alias {}",entityId,localAlias);
}
context.setLocalEntityId(entityId);
context.setLocalEntityRole(localEntityRole);
}
/**
* disable the check for InResponsetoField from SSO message response.
*/
@Override
public void setStorageFactory(SAMLMessageStorageFactory storageFactory) {
super.setStorageFactory(new EmptyStorageFactory());
}
}
解决方法
为了遵守SAML规范中定义的规则,必须对照SP发起的SSO流中的SAML AuthNRequest验证SAML响应。 默认情况下,Spring SAML将SAML AuthNRequest存储在内存中,因此包含SAML响应作为有效负载的HTTP POST请求必须命中创建AuthNRequest的同一JVM。如果LB无法保证粘性,那么您需要实现一个可以与多个实例共享消息的消息存储(org.springframework.security.saml.storage.SAMLMessageStorage
,org.springframework.security.saml.storage.SAMLMessageStorageFactory
)。请确保您在使用完邮件后将其从存储中删除,以规避重播攻击,因为SAML共振只能一次性使用。