Spring security SOAP消息的身份验证
我已经找了一个好的例子,但找不到一个。我想从SOAP头中获取用户名和密码,并在使用现有服务方法进行身份验证后设置spring安全上下文。我已经实现了Wss4jSecurityInterceptor,它验证了header元素。在回调或其他机制中,我需要做的是创建一个授权上下文,以便稍后在端点中访问它 然而,我不认为回调是正确的地方做这件事,因为我一直得到密码提供没有密码错误。我不熟悉spring安全和集成 配置:Spring security SOAP消息的身份验证,spring-security,spring-ws,Spring Security,Spring Ws,我已经找了一个好的例子,但找不到一个。我想从SOAP头中获取用户名和密码,并在使用现有服务方法进行身份验证后设置spring安全上下文。我已经实现了Wss4jSecurityInterceptor,它验证了header元素。在回调或其他机制中,我需要做的是创建一个授权上下文,以便稍后在端点中访问它 然而,我不认为回调是正确的地方做这件事,因为我一直得到密码提供没有密码错误。我不熟悉spring安全和集成 配置: <bean id="SOAPSecurityInterceptor"
<bean id="SOAPSecurityInterceptor" class="com.ps.snt.ws.interceptor.SOAPSecurityInterceptor">
<property name="validationActions" value="UsernameToken"/>
<property name="validationCallbackHandler" ref="callbackHandler"/>
</bean>
<bean id="callbackHandler" class="com.ps.snt.ws.interceptor.SOAPSecurityValidationCallbackHandler">
</bean>
我的要求很简单:
-验证SOAP头(工作)
-检索用户名和密码
-调用遗留服务来创建登录上下文
-设置spring安全上下文(详细信息为logincontext),以便稍后在端点中使用
我可以使用什么机制来验证soap头并从该头设置安全上下文
SpringSecurityPasswordValidationCallbackHandler是为您准备的。从Spring WS文档:
SpringSecurityPasswordValidationCallbackHandler使用SpringSecurityUserDetailService来验证纯文本和摘要密码。它使用此服务检索令牌中指定的用户的密码(摘要)。然后将此详细信息对象中包含的密码(摘要)与消息中的摘要进行比较。如果它们相等,则表示用户已成功进行身份验证,并且UsernamePasswordAuthenticationToken存储在SecurityContextHolder中。您可以使用userDetailsService设置服务。此外,还可以设置userCache属性,以缓存加载的用户详细信息
...
感谢您的回复,我仍然不知道这将如何工作。UserDetailsService类有一个loadByUsername方法,该方法返回一个用户对象。我可以假设在调用这个类之前已经完成了身份验证部分吗?所以我仍然需要实现一个回调处理程序来获取用户的密码。据我所知,我需要执行以下操作:1)实现一个回调handleUSernameToken方法,该方法从数据库检索密码并在回调中设置密码,2)Spring通过将SOAP消息密码与我在回调中设置的密码匹配来验证用户名,3)实现loadByUsername方法以创建用户对象。在这个方案中,我将把我的自定义LoginContext对象放在哪里,用户类似乎没有我可以使用的任何属性。不确定为什么需要它。如果您遵循WS-Security
的要求,那么请求中应该包含所有内容……我想我现在理解了。我是从另一方面来处理这个问题的。基本上,我创建user details服务来加载用户对象,然后根据SOAP头密码对其进行身份验证。不过,我还有一个问题,数据库中的密码是加密的,那么在比较之前,如何告诉spring在SOAP消息中加密密码呢?我无法解密密码,但确实有一个实用方法来加密字符串。请参阅UsernameTokenValidator
和UsernameToken
有助于了解密码的情况
public class SOAPSecurityValidationCallbackHandler extends SimplePasswordValidationCallbackHandler {
@Override
protected void handleUsernameToken(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
System.out.println("In security callback " + callback.getPassword());
boolean valid = true;
String token = callback.getIdentifier();
String password = callback.getPassword();
Integer zoneID = null;
String username = null;
StringBuffer errorMessages = new StringBuffer();
if(StringUtils.isEmpty(token)) {
errorMessages.append("Username token cannot be empty");
valid = false;
} else {
Pattern pattern = Pattern.compile("^[\\w]+\\d\\d\\d\\d\\d");
Matcher matcher = pattern.matcher(token);
if(!matcher.matches()) {
valid = false;
errorMessages.append("Username token must be in the format 'user@zone'.");
}
else {
String[] parts = token.split("@");
username = parts[0];
zoneID = Integer.parseInt(parts[1]);
}
}
if(StringUtils.isEmpty(password)) {
errorMessages.append("Password cannot be empty.");
valid = false;
}
if(valid && username != null && zoneID != null) {
LoginService loginService = new LoginService();
LoginContextDO loginContextDO = loginService.getAuthenticatedLoginContext(username, password, zoneID);
AbstractAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, password);
authentication.setDetails(loginContextDO);
authentication.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
System.out.println("Authetnication failed!");
}
}
}
<beans>
<bean class="org.springframework.ws.soap.security.wss4j.callback.SpringDigestPasswordValidationCallbackHandler">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
...
</beans>