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
Spring SAML-支持自定义SAML断言_Spring_Spring Security_Spring Saml - Fatal编程技术网

Spring SAML-支持自定义SAML断言

Spring SAML-支持自定义SAML断言,spring,spring-security,spring-saml,Spring,Spring Security,Spring Saml,我们有一个只有一个客户的产品,当我们作为服务提供商且idp在客户端时,我们为该客户实施SAML流程 现在,我们有另一个客户也希望使用SAML进行身份验证,我们希望同一个SP为该客户实施SAML流,第二个客户将有两个SAML流,一个用于移动设备,另一个用于使用相同IDP的其他设备。两个客户的IDP不同 问题 这两个客户之间存在一些差异,例如断言属性不同,成功身份验证的操作不同,目前我们提供了自己的实现 此外,可能会有更多的更改,如不同的绑定等 我的问题是,支持这种场景并能够扩展我的SP以支持更多在

我们有一个只有一个客户的产品,当我们作为服务提供商且idp在客户端时,我们为该客户实施SAML流程

现在,我们有另一个客户也希望使用SAML进行身份验证,我们希望同一个SP为该客户实施SAML流,第二个客户将有两个SAML流,一个用于移动设备,另一个用于使用相同IDP的其他设备。两个客户的IDP不同

问题

这两个客户之间存在一些差异,例如断言属性不同,成功身份验证的操作不同,目前我们提供了自己的实现

此外,可能会有更多的更改,如不同的绑定等

我的问题是,支持这种场景并能够扩展我的SP以支持更多在断言属性和更多配置方面存在差异的SAML流的最佳选项/最佳实践是什么

当我们使用SpringSAML时,我们应该为每个SAML风格使用不同的Spring安全上下文文件吗

并行使用多个上下文时是否存在线程安全问题

我的问题是,什么是支持这种做法的最佳选择/最佳做法 并能够扩展我的SP以支持更多SAML流 断言属性和更多配置之间存在差异

要分支某些配置(如断言属性),需要创建单独的服务提供者。可以共享其他配置和服务。应共享其他配置。例如,我使用单个定制SAMLUserDetailsService实现,它从凭证中提取唯一的EntityID,并使用它为每个IDP映射不同的SAML属性

当我们使用Spring SAML时,我们应该使用不同的Spring安全性吗 每个SAML风格的上下文文件? 在中使用多个上下文时是否存在线程安全问题 平行

我不建议单独运行多个安全上下文。根据我的经验,SpringSAML涉及很多配置,这样做很可能会不必要地复制大量代码

在SpringSAML中,有一个为不同的服务提供者使用不同别名的概念。我已经为许多IDP设置了许多服务提供商,并且能够使用一个Spring安全上下文并在需要处理差异的地方实现定制服务。我没有您的需求的完整列表,可能有一些在单个spring安全上下文中根本无法完成,但我会在采取这一路线之前等待以确保情况属实

每个IDP之间具体需要有哪些不同

我在允许发布的代码方面受到限制,但我已经包括了我可以发布的代码

  • 入口点URL-如果您的配置中设置了多个别名的IDP,则默认情况下入口点URL为

    ”/saml/login/alias/“+productAlias+”?idp=“+entityId

    如果您使用的是负载平衡器,则可以将其配置为将您想要的任何URL重写为客户的URL

  • 绑定和断言-这些在每个Service Providers metadata.xml文件中配置,对于每个客户可以不同。真正的挑战是如何从经过身份验证的SAML请求中提取属性,并以可用的形式获取它

    我不知道是否有更好的方法来实现这一点,但我的要求是为我配置的任何IDP提供可映射和可配置的绑定。为了实现这一点,我实现了一个定制的
    SAMLUserDetailsService
    。从传递到服务的
    SAMLCredential
    中,可以使用
    credential.getRemoteEntityID()
    为客户提取映射。从那里,您需要从凭证中解析出属性

解析Microsoft和其他IDP的SAML属性的示例

 public class AttributeMapperImpl implements AttributeMapper {

    @Override
    public Map<String, List<String>> parseSamlStatements(List<AttributeStatement> attributeList) {
        Map<String, List<String>> map = new HashMap<>();
        attributeList.stream().map((statement) -> parseSamlAttributes(statement.getAttributes())).forEach((list) -> {
            map.putAll(list);
        });
        return map;
    }

    @Override
    public Map<String, List<String>> parseSamlAttributes(List<Attribute> attributes) {
        Map<String, List<String>> map = new HashMap<>();
        attributes.stream().forEach((attribute) -> {
            List<String> sList = parseXMLObject(attribute.getAttributeValues());
            map.put(attribute.getName(), sList);
        });
        return map;
    }

    @Override
    public List<String> parseXMLObject(List<XMLObject> objs) {
        List<String> list = new ArrayList<>();

        objs.stream().forEach((obj) -> {
            if(obj instanceof org.opensaml.xml.schema.impl.XSStringImpl){
                XSStringImpl xs = (XSStringImpl) obj;
                list.add(xs.getValue());
            }else if(obj instanceof org.opensaml.xml.schema.impl.XSAnyImpl){
                XSAnyImpl xs = (XSAnyImpl) obj;
                list.add(xs.getTextContent());
            }
        });  

        return list;
    }

    @Override
    public String parseSamlStatementsToString(Map<String, List<String>> map) {
        String values = "";
        Iterator it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry) it.next();
            values += pair.getKey() + "=" + pair.getValue() + " ";
            it.remove(); // avoids a ConcurrentModificationException
        }
        return values;
    }

}
公共类AttributeMapperImpl实现AttributeMapper{
@凌驾
公共地图parseSamlStatements(列表属性列表){
Map Map=newhashmap();
attributeList.stream().map((语句)->ParseSamlatAttributes(语句.getAttributes()).forEach((列表)->{
地图.普塔尔(列表);
});
返回图;
}
@凌驾
公共地图属性(列表属性){
Map Map=newhashmap();
attributes.stream().forEach((属性)->{
List sList=parseXMLObject(attribute.getAttributeValues());
map.put(attribute.getName(),sList);
});
返回图;
}
@凌驾
公共列表parseXMLObject(列表对象){
列表=新的ArrayList();
objs.stream().forEach((obj)->{
if(obj instanceof org.opensaml.xml.schema.impl.XSStringImpl){
XSStringImpl xs=(XSStringImpl)obj;
添加(xs.getValue());
}else if(obj instanceof org.opensaml.xml.schema.impl.XSAnyImpl){
XSAnyImpl xs=(XSAnyImpl)obj;
add(xs.getTextContent());
}
});  
退货清单;
}
@凌驾
公共字符串parseSamlStatementsToString(映射){
字符串值=”;
迭代器it=map.entrySet().Iterator();
while(it.hasNext()){
Map.Entry对=(Map.Entry)it.next();
值+=pair.getKey()+“=”+pair.getValue()+”;
it.remove();//避免ConcurrentModificationException
}
返回值;
}
}
  • 对成功/失败采取行动-有很多可能的方法。我选择在控制器中使用一个端点,该端点可以访问所访问的会话