消费SAMLResponse令牌。

11

SAML基于服务提供商(SP)的身份验证具有以下简短工作流程:

  • 用户想要访问SP上的应用程序。
  • SP向IDP发送SAMLRequest令牌。
  • IDP接受并生成SAMLResponse令牌。
  • IDP将此SAMLResponse令牌发送到SP给出的AC-URL。

我的问题是SP如何使用此SAMLResponse令牌。 逻辑是什么? 如果我能得到一些JAVA代码帮助,那将是有益的。

3个回答

16
下面这个方法对我有用:

以下是需要翻译的内容:

  1. Get the SAMLResponse token and decode it and inflate:

    // Base64 decode
    Base64 base64Decoder = new Base64();
    byte[] xmlBytes = encodedXmlString.getBytes("UTF-8");
    byte[] base64DecodedByteArray = base64Decoder.decode(xmlBytes);
    
    // Inflate (uncompress) the AuthnRequest data
    // First attempt to unzip the byte array according to DEFLATE (rfc 1951)
    
    Inflater inflater = new Inflater(true);
    inflater.setInput(base64DecodedByteArray);
    // since we are decompressing, it's impossible to know how much space we
    // might need; hopefully this number is suitably big
    byte[] xmlMessageBytes = new byte[5000];
    int resultLength = inflater.inflate(xmlMessageBytes);
    
    if (!inflater.finished()) {
        throw new RuntimeException("didn't allocate enough space to hold "
                + "decompressed data");
    }
    
    inflater.end();
    
    String decodedResponse = new String(xmlMessageBytes, 0, resultLength,
            "UTF-8");
    
    return decodedResponse;
    
  2. Parse the resulting XML. Here you can get the info that you need and for example, create a POJO with it (this is a sample code for parsing LogoutRequest's but would be analogous for responses):

    // Parse the XML. SAX approach, we just need the ID attribute
    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
    
    // If we want to validate the doc we need to load the DTD
    // saxParserFactory.setValidating(true);
    
    // Get a SAXParser instance
    SAXParser saxParser = saxParserFactory.newSAXParser();
    
    // Parse it
    XMLhandler xmLhandler = new XMLhandler();
    saxParser.parse(new ByteArrayInputStream(xmlLogoutRequest.getBytes()),
            xmLhandler);
    
    // Return the SamlVO
    return xmLhandler.getSamlVO();
    

对于我的使用情况,我只关心几个元素,因此我正在使用 SAX

public class XMLhandler extends DefaultHandler {

    private SamlVO samlVO;

    public XMLhandler() {
        samlVO = new SamlVO();
    }

    @Override
    public void startElement(String uri, String localName, String qName,
        Attributes attributes) throws SAXException {

        // Managing a LogoutRequest means that we are going to build a LogoutResponse
        if (qName.equals("samlp:LogoutRequest")) {
            // The ID value of a request will be the LogoutResponse's InReponseTo attribute 
            samlVO.setInResponseTo(attributes.getValue("ID"));
            // From the destination we can get the Issuer element
            String destination = attributes.getValue("Destination");
            if (destination != null) {
                URL destinationUrl = null;
                try {
                    destinationUrl = new URL(destination);
                } catch (MalformedURLException e) {
                     // TODO: We could set the server hostname (take it from a property), but this URL SHOULD be well formed!
                     e.printStackTrace();
                }
                samlVO.setIssuer(destinationUrl.getHost());
            }
        }   
    }

    public SamlVO getSamlVO() {
        return samlVO;
    }

}

希望这可以帮到你,

Luis

附注:你也可以使用类似OpenSAML的库。

DefaultBootstrap.bootstrap();

HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder(new BasicParserPool());
BasicSAMLMessageContext<LogoutRequest, ?, ?> messageContext = new BasicSAMLMessageContext<LogoutRequest, SAMLObject, SAMLObject>();
messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(request));
decode.decode(messageContext);
XMLObjectBuilderFactory builderFactory = org.opensaml.Configuration.getBuilderFactory();
LogoutRequestBuilder logoutRequestBuilder = (LogoutRequestBuilder) builderFactory.getBuilder(LogoutRequest.DEFAULT_ELEMENT_NAME);
LogoutRequest logoutRequest = logoutRequestBuilder.buildObject();
logoutRequest = (LogoutRequest) messageContext.getInboundMessage();

但是准备好在你的CLASSPATH中包含一些库!!!


这真的帮了我很多。请同时添加SamlVO以供参考。 - ashish gupta
当然可以!https://github.com/cerndb/wls-cern-sso/blob/master/saml2slo/src/ch/cern/security/saml2/vo/SamlVO.java - Gaucho
谢谢,那真的帮了我很多。在从 XML 中提取 ID 和目标之后,您是如何使用它们的? - Manuela
很高兴听到它对你有所帮助,@Manuela。我将它们添加到SAMLResponse中,请参见https://github.com/cerndb/wls-cern-sso/blob/master/saml2slo/src/ch/cern/security/saml2/utils/UrlUtils.java。 - Gaucho

2
这是我在Java中的做法。我使用XMLBeans来解析SAMLResponse,然后解密它(如果它被加密了),最后验证签名: WebBrowserSSOAuthConsumerService

1

要求提供代码有些过分,但基本处理是SP验证SAMLResponse,包括格式是否正确、必需值是否存在、协议是否正确以及任何其他SP特定的验证(时间限制、数据对应等),将令牌中标识的用户映射到SP上的用户(可能涉及创建用户),并将用户传输到请求的资源。


1
谢谢您的帮助。我会仔细检查所有这些内容。请问您能否给我一些关于涉及所有这些操作的类的提示,或者除了opensaml之外的任何网站都可以提供帮助。 - Muhammad Imran Tariq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接