簡體   English   中英

根據SAML請求創建SAML響應

[英]Create SAML response based on SAML request

我已經開發了Java Web應用程序,並且想要實現SAML。 這些是我認為實施SAML正確的步驟。

  1. 服務提供商(SP,在本例中為我的應用程序)將SAML身份驗證請求發送到IdP。
  2. 然后,IdP對其進行驗證並創建SAML響應聲明,並使用證書對其進行簽名,然后發送回SP。
  3. 然后,SP用密鑰庫中的證書的公鑰對其進行驗證,然后進一步進行驗證。

我有一個示例代碼,並且能夠創建SAML請求及其類似內容

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    ID="_c7b796f4-bc16-4fcc-8c1d-36befffc39c2" Version="2.0"
    IssueInstant="2014-10-30T11:21:08Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    AssertionConsumerServiceURL="http://localhost:8080/mywebapp/consume.jsp">
    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost:8080/mywebapp
    </saml:Issuer>
    <samlp:NameIDPolicy
        Format="urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified"
        AllowCreate="true"></samlp:NameIDPolicy>
    <samlp:RequestedAuthnContext Comparison="exact">
        <saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
        </saml:AuthnContextClassRef>
    </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>

我可以對其進行編碼並發送到IdP。

我想創建示例Java代碼來獲取此SAML請求,然后創建SAML響應。 如何解碼請求並驗證它並創建響應? 並且我需要用證書在saml響應上簽名嗎? 然后發送回SP?

謝謝。

盡管這是一篇過時的文章,但是我添加了示例代碼和我認為有用的參考。

SAMLResponse = hreq.getParameter("SAMLResponse");
InputSource inputSource = new InputSource(new StringReader(SAMLResponse));
SAMLReader samlReader = new SAMLReader();                   
response2 = org.opensaml.saml2.core.Response)samlReader.readFromFile(inputSource);

現在驗證數字簽名:

org.opensaml.saml2.core.Response response2 = (org.opensaml.saml2.core.Response)samlReader.readFromFile(inputSource);  
//To fetch the digital signature from the response.
Signature signature  = response2.getSignature(); 
X509Certificate certificate = (X509Certificate) keyStore.getCertificate(domainName);
//pull out the public key part of the certificate into a KeySpec
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(certificate.getPublicKey().getEncoded());
//get KeyFactory object that creates key objects, specifying RSA - java.security.KeyFactory
KeyFactory keyFactory = KeyFactory.getInstance("RSA");                  
//generate public key to validate signatures
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
//we have the public key                    
BasicX509Credential publicCredential = new BasicX509Credential();
//add public key value
publicCredential.setPublicKey(publicKey);
//create SignatureValidator
SignatureValidator signatureValidator = new SignatureValidator(publicCredential);
//try to validate
try{
signatureValidator.validate(signature); 
catch(Exception e){
//
} 

現在獲取斷言圖:

samlDetailsMap = setSAMLDetails(response2);

在上述邏輯中,使用以下私有方法提取所有斷言屬性。 最后,您將獲得發送給您的所有字段的地圖。

 private Map<String, String> setSAMLDetails(org.opensaml.saml2.core.Response  response2){
        Map<String, String> samlDetailsMap = new HashMap<String, String>();
        try {
            List<Assertion> assertions = response2.getAssertions();
            LOGGER.error("No of assertions : "+assertions.size());
            for(Assertion assertion:assertions){
                List<AttributeStatement> attributeStatements = assertion.getAttributeStatements();
                for(AttributeStatement attributeStatement: attributeStatements){
                    List<Attribute> attributes = attributeStatement.getAttributes();
                    for(Attribute attribute: attributes){
                        String name = attribute.getName();                          
                        List<XMLObject> attributes1 = attribute.getAttributeValues();
                        for(XMLObject xmlObject : attributes1){
                            if(xmlObject instanceof XSString){
                                samlDetailsMap.put(name, ((XSString) xmlObject).getValue());
                                LOGGER.error("Name is : "+name+" value is : "+((XSString) xmlObject).getValue());
                            }else if(xmlObject instanceof XSAnyImpl){
                                String value = ((XSAnyImpl) xmlObject).getTextContent();

                                samlDetailsMap.put(name, value);

                            }         
                    }
                }
            }       
       }
      } catch (Exception e) {             
          LOGGER.error("Exception occurred while setting the saml details");        
        }       
        LOGGER.error("Exiting from  setSAMLDetails method"); 
        return samlDetailsMap;
    }

添加新的類SAMLReader,如下所示:

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.opensaml.DefaultBootstrap;
import org.opensaml.xml.Configuration;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.io.UnmarshallingException;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;


public class SAMLReader {

 private static DocumentBuilder builder;

 static{
        try{
            DefaultBootstrap.bootstrap ();
            DocumentBuilderFactory factory = 
                    DocumentBuilderFactory.newInstance ();
                factory.setNamespaceAware (true);        
            builder = factory.newDocumentBuilder ();
        }catch (Exception ex){
            ex.printStackTrace ();
        }
    }



/**
 * 
 * @param filename
 * @return
 * @throws IOException
 * @throws UnmarshallingException
 * @throws SAXException
 */
public XMLObject readFromFile (String filename)
            throws IOException, UnmarshallingException, SAXException{
            return fromElement (builder.parse (filename).getDocumentElement ());    
}
/**
 *      
 * @param is
 * @return
 * @throws IOException
 * @throws UnmarshallingException
 * @throws SAXException
 */
public XMLObject readFromFile (InputStream is)
                throws IOException, UnmarshallingException, SAXException{
                return fromElement (builder.parse (is).getDocumentElement ());    
}
/**
 *      
 * @param is
 * @return
 * @throws IOException
 * @throws UnmarshallingException
 * @throws SAXException
 */
public XMLObject readFromFile (InputSource  is)
                throws IOException, UnmarshallingException, SAXException{                   
                return fromElement (builder.parse (is).getDocumentElement ());    
}

/**
 * 
 * @param element
 * @return
 * @throws IOException
 * @throws UnmarshallingException
 * @throws SAXException
 */
public static XMLObject fromElement (Element element)
            throws IOException, UnmarshallingException, SAXException{   
    return Configuration.getUnmarshallerFactory ()
                .getUnmarshaller (element).unmarshall (element);    
 }

}

您列出的步驟或多或少是正確的。 我唯一要指出的是,如果單詞發送 (例如,在“ SP ...將SAML身份驗證請求發送到IdP”中),則必須小心含義。 SAML允許SP和IdP之間零直接通信的身份驗證方案。

另一個小的補充是SP也可以簽署他的請求,因此您可能在兩面都進行了簽名驗證。 SP方面的驗證是強制性的。

如果要實現SAML,則可能需要檢查現有解決方案之一,例如Shibboleth 如果您使用Spring和JBoss等平台,則可能需要檢查Spring Security SAMLJBoss PicketLink 如果要降級 ,請檢查OpenSAML

在我的公司中,我們以JBoss為標准,並對PicketLink感到非常滿意。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM