2016-07-05 115 views
4

我们有一个产品拥有一个客户,我们在为客户实施SAML流程时使用Spring Security SAML作为服务提供商,而idp位于客户方。Spring SAML - 支持自定义SAML声明

现在我们有另一位客户也希望验证与SAML一致,并且我们希望同一个SP为此客户实施SAML流程,另外第二个客户将拥有2个SAML一个用于移动设备的流程,另一个用于其他设备使用相同的IDP。这两个客户的国内流离失所者是不同的。

问题

有两个客户例如断言属性是不同的,成功验证行动不同的是,目前我们为我们自己的实现之间存在一些差异。

也可能有更多的变化就像不同的绑定等...

我的问题是什么是最好的选择/最佳实践来支持这样的场景,并能够延长我的SP支持更多的SAML与流Assertion属性和更多配置的区别?

当我们使用Spring SAML时,我们是否应该为每种SAML风格使用不同的Spring Security上下文文件?

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

回答

2

我的问题是什么是最好的选择/最佳实践来支持这样 场景,并能够延长我的SP支持更多的SAML和断言属性和更多的配置差异流动 ?

要分支某些配置,例如Assertion属性,您需要创建单独的服务提供者。其他配置和服务可以共享。其他配置应该共享。例如,我使用单个自定义SAMLUserDetailsS​​ervice实现,将唯一EntityID从凭证中提取出来,并使用它为每个IDP以不同的方式映射SAML属性。

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

我不建议单独运行多个安全上下文。根据我的经验,在Spring SAML中涉及到很多配置,而且很可能你必须通过这种方式不必要地重复大量代码。

在Spring SAML中,存在为不同服务提供者使用不同别名的概念。我为许多IDP设置了许多服务提供者,并且能够使用一个Spring Security上下文并在需要处理差异的地方实现自定义服务。我没有你的要求的完整列表,可能有一些不能在单一的春季安全环境中完成,但我会等待确保在采用该路线之前就是这种情况。

每个IDP之间会有什么特别的区别?

我被限制在允许发布的代码中,但我已经包含了我可以提供的内容。

  • 入口点URL - 如果你有多个国内流离失所者在配置中设置一个别名,默认入口点URL将被

    "/saml/login/alias/" +productAlias+ "?idp=" + entityId;

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

  • 绑定和断言 - 这些配置在每个服务提供商metadata.xml文件中,并且可能因每个客户而不同。真正的挑战是如何从已认证的SAML请求中提取属性,并以可用的形式获取它。

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

解析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; 
    } 

} 
  • 行动 - 有这样做的许多可能的方式。我选择在可访问会话的控制器中使用单个终端,以便所有请求都取得成功。验证成功后,我可以退出会话,查看用户来自哪个IDP并相应地重定向他们。失败有点难度,因为完全有可能并且可能有些失败会非常严重,以至于您不知道请求来自哪个IDP(即,如果saml消息使用错误的证书签名)。
+0

idps之间的差异是入口点URL,绑定,成功和失败的行为和断言......你能分享一个证明它的samle代码吗? –

+0

我在回答中添加了一些信息 – blur0224