gy坏坏 2024-04-03 16:20 采纳率: 0%
浏览 1

cas4.0集成 saml2协议如何针对断言进行签名?

cas4.0集成 saml2协议如何针对断言进行签名?

MyGoogleAccountsService.java


```java
package com.gilight.cas.authorize.saml2;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.jasig.cas.authentication.principal.AbstractWebApplicationService;
import org.jasig.cas.authentication.principal.Response;
import org.jasig.cas.support.saml.util.SamlUtils;
import org.jdom.Document;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

public class MyGoogleAccountsService extends AbstractWebApplicationService {

    private static final long serialVersionUID = 6678711809842282833L;

    private static SecureRandom RANDOM_GENERATOR = new SecureRandom();

    private static final char[] CHAR_MAPPINGS = {
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
    'p'};

    private static final String CONST_PARAM_SERVICE = "SAMLRequest";

    private static final String CONST_RELAY_STATE = "RelayState";

    private static final String TEMPLATE_SAML_RESPONSE =
            "<samlp:Response ID=\"<RESPONSE_ID>\" IssueInstant=\"<ISSUE_INSTANT>\" Version=\"2.0\""
            + " xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\""
            + " xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\""
            + " Destination=\"https://login.microsoftonline.com/login.srf\""
            + " xmlns:xenc=\"http://www.w3.org/2001/04/xmlenc#\">"
            + "<samlp:Status>"
            + "<samlp:StatusCode Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\" />"
            + "</samlp:Status>"
            + "<samlp:Assertion ID=\"<ASSERTION_ID>\""
            + " IssueInstant=\"<ISSUE_INSTANT>\" Version=\"2.0\""
            + " xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\""
            // + " xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\""
            + ">"
            + "<Issuer>https://365.sias.edu.cn/cas</Issuer>"
            + "<Subject>"
            // + "<NameID Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress\">"
            + "<NameID Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent\">"
            + "<USERNAME_STRING>"
            + "</NameID>"
            + "<SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\">"
            + "<SubjectConfirmationData Recipient=\"<ACS_URL>\" NotOnOrAfter=\"<NOT_ON_OR_AFTER>\" InResponseTo=\"<REQUEST_ID>\" />"
            + "</SubjectConfirmation>"
            + "</Subject>"
            + "<Conditions NotBefore=\"<ISSUE_INSTANT>\""
            + " NotOnOrAfter=\"<NOT_ON_OR_AFTER>\">"
            + "<AudienceRestriction>"
            + "<Audience><ACS_URL></Audience>"
            + "</AudienceRestriction>"
            + "</Conditions>"

            // 人员属性
            + "<AttributeStatement>"
            + "<Attribute Name=\"IDPEmail\"><AttributeValue><USER_ATTRIBUTEVALUE_EMAIL></AttributeValue></Attribute>"
            + "</AttributeStatement>"

            + "<AuthnStatement AuthnInstant=\"<AUTHN_INSTANT>\">"
            + "<AuthnContext>"
            + "<AuthnContextClassRef>"
            + "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
            + "</AuthnContextClassRef>"
            + "</AuthnContext>"
            + "</AuthnStatement>"
            + "</samlp:Assertion></samlp:Response>";

    private final String relayState;

    private final PublicKey publicKey;

    private final PrivateKey privateKey;

    private final String requestId;

    private final String alternateUserName;
    
    private static X509Certificate x509;
    

    protected MyGoogleAccountsService(final String id, final String relayState, final String requestId,
            final PrivateKey privateKey, final PublicKey publicKey, final String alternateUserName) {
        this(id, id, null, relayState, requestId, privateKey, publicKey, alternateUserName);
    }

    protected MyGoogleAccountsService(final String id, final String originalUrl,
            final String artifactId, final String relayState, final String requestId,
            final PrivateKey privateKey, final PublicKey publicKey, final String alternateUserName) {
        super(id, originalUrl, artifactId);
        this.relayState = relayState;
        this.privateKey = privateKey;
        this.publicKey = publicKey;
        this.requestId = requestId;
        this.alternateUserName = alternateUserName;
    }

    public static MyGoogleAccountsService createServiceFrom(
            final HttpServletRequest request, final PrivateKey privateKey,
            final PublicKey publicKey, final String alternateUserName, X509Certificate x509Certificate) {
        x509 = x509Certificate;
        
        final String relayState = request.getParameter(CONST_RELAY_STATE);

        final String xmlRequest = decodeAuthnRequestXML(request.getParameter(CONST_PARAM_SERVICE));

        if (!StringUtils.hasText(xmlRequest)) {
            return null;
        }

        final Document document = SamlUtils.constructDocumentFromXmlString(xmlRequest);

        if (document == null) {
            return null;
        }

        // 获取sp url
        String assertionConsumerServiceUrl = document.getRootElement().getAttributeValue("AssertionConsumerServiceURL");
        if(null == assertionConsumerServiceUrl){
            assertionConsumerServiceUrl = request.getHeader("Referer");
        }
        if(null == assertionConsumerServiceUrl){
            assertionConsumerServiceUrl = request.getHeader("Origin");
        }
        
        String requestId = document.getRootElement().getAttributeValue("ID");

        if(null == requestId ){
            requestId = "1";
        }
        
        return new MyGoogleAccountsService(assertionConsumerServiceUrl,
                relayState, requestId, privateKey, publicKey, alternateUserName);
    }

    @Override
    public Response getResponse(final String ticketId) {
        final Map<String, String> parameters = new HashMap<String, String>();
        String uuid = createID();
        final String samlResponse = constructSamlResponse(uuid);
        String signedResponse = MySamlUtils.signSamlResponse(samlResponse, this.privateKey, this.publicKey, x509);
        
        
        parameters.put("SAMLResponse", new String(Base64.encodeBase64(signedResponse.getBytes())));
        
        
        parameters.put("RelayState", this.relayState);
        return Response.getPostResponse(getOriginalUrl(), parameters);
    }

    /**
     * Return true if the service is already logged out.
     *
     * @return true if the service is already logged out.
     */
    @Override
    public boolean isLoggedOutAlready() {
        return true;
    }

    private String constructSamlResponse(String uuid) {
        String samlResponse = TEMPLATE_SAML_RESPONSE;

        final Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.YEAR, 1);

        String userId;

        if (this.alternateUserName == null) {
            userId = getPrincipal().getId();
        } else {
            final String attributeValue = (String) getPrincipal().getAttributes().get(this.alternateUserName);
            if (attributeValue == null) {
                userId = getPrincipal().getId();
            } else {
                userId = attributeValue;
            }
        }
        


        samlResponse = samlResponse.replace("<USERNAME_STRING>", userId );
        samlResponse = samlResponse.replace("<RESPONSE_ID>", createID());
//        samlResponse = samlResponse.replace("<ISSUE_INSTANT>", SamlDateUtils.getCurrentDateAndTime());
//        samlResponse = samlResponse.replace("<AUTHN_INSTANT>", SamlDateUtils.getCurrentDateAndTime());
//        samlResponse = samlResponse.replaceAll("<NOT_ON_OR_AFTER>", SamlDateUtils.getFormattedDateAndTime(c.getTime()));
       
        samlResponse = samlResponse.replace("<ISSUE_INSTANT>", getCurrentDateAndTime());
        samlResponse = samlResponse.replace("<AUTHN_INSTANT>", getCurrentDateAndTime());
        samlResponse = samlResponse.replaceAll("<NOT_ON_OR_AFTER>", getFormattedDateAndTime(c.getTime()));
        
        
        samlResponse = samlResponse.replace("<ASSERTION_ID>", uuid);
        
        samlResponse = samlResponse.replaceAll("<ACS_URL>", getId());
        samlResponse = samlResponse.replace("<REQUEST_ID>", this.requestId);

        // 人员属性
        Map<String, Object> attributeMap = getPrincipal().getAttributes();
        // 邮箱
        if(null != attributeMap && attributeMap.size() > 0 ){
            String mailbox = null != attributeMap.get("mailbox") ? (String)attributeMap.get("mailbox") : null;
            if(null != mailbox){
                samlResponse = samlResponse.replace("<USER_ATTRIBUTEVALUE_EMAIL>", mailbox);    
            }
            
        }
        
        
        return samlResponse;
    }

    private static String createID() {
        final byte[] bytes = new byte[20]; // 160 bits
        RANDOM_GENERATOR.nextBytes(bytes);

        final char[] chars = new char[40];

        for (int i = 0; i < bytes.length; i++) {
            int left = bytes[i] >> 4 & 0x0f;
            int right = bytes[i] & 0x0f;
            chars[i * 2] = CHAR_MAPPINGS[left];
            chars[i * 2 + 1] = CHAR_MAPPINGS[right];
        }

        return String.valueOf(chars);
    }

    private static String decodeAuthnRequestXML(
            final String encodedRequestXmlString) {
        if (encodedRequestXmlString == null) {
            return null;
        }

        // final byte[] decodedBytes = base64Decode(encodedRequestXmlString);
        final byte[] decodedBytes = compressString(encodedRequestXmlString);

        if (decodedBytes == null) {
            return null;
        }

        final String inflated = inflate(decodedBytes);

        if (inflated != null) {
            return inflated;
        }

        return zlibDeflate(decodedBytes);
    }

    private static String zlibDeflate(final byte[] bytes) {
        final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        final InflaterInputStream iis = new InflaterInputStream(bais);
        final byte[] buf = new byte[1024];

        try {
            int count = iis.read(buf);
            while (count != -1) {
                baos.write(buf, 0, count);
                count = iis.read(buf);
            }
            return new String(baos.toByteArray());
        } catch (final Exception e) {
            return null;
        } finally {
            IOUtils.closeQuietly(iis);
        }
    }

    private static byte[] base64Decode(final String xml) {
        try {
            final byte[] xmlBytes = xml.getBytes("UTF-8");
            return Base64.decodeBase64(xmlBytes);
        } catch (final Exception e) {
            return null;
        }
    }

    private static String inflate(final byte[] bytes) {
        final Inflater inflater = new Inflater(true);
        final byte[] xmlMessageBytes = new byte[10000];

        final byte[] extendedBytes = new byte[bytes.length + 1];
        System.arraycopy(bytes, 0, extendedBytes, 0, bytes.length);
        extendedBytes[bytes.length] = 0;

        inflater.setInput(extendedBytes);

        try {
            final int resultLength = inflater.inflate(xmlMessageBytes);
            inflater.end();

            if (!inflater.finished()) {
                throw new RuntimeException("buffer not large enough.");
            }

            inflater.end();
            return new String(xmlMessageBytes, 0, resultLength, "UTF-8");
        } catch (final DataFormatException e) {
            return null;
        } catch (final UnsupportedEncodingException e) {
            throw new RuntimeException("Cannot find encoding: UTF-8", e);
        }
    }
    
    
    public static byte[] compressString(String input) {
        try {
            if(isBase64String(input)){
                input = new String(Base64.decodeBase64(input));
            }
            byte[] inputData = input.getBytes("UTF-8");

            Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
            deflater.setInput(inputData);
            deflater.finish();

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream(inputData.length);
            byte[] buffer = new byte[2048];
            while (!deflater.finished()) {
                int count = deflater.deflate(buffer);  
                outputStream.write(buffer, 0, count);
            }
            deflater.end();

            return outputStream.toByteArray();
        } catch (Exception e) {
            // TODO: handle exception
        }
        return null;
    }
    
    /**
     * 判断是否为base64
     * @param str
     * @return
     * @author gy
     */
    public static boolean isBase64String(String str) {
        try {
            byte[] decodedBytes = Base64.decodeBase64(str);
            String encodedString = Base64.encodeBase64String(decodedBytes);
            return str.equals(encodedString);
        } catch (IllegalArgumentException e) {
            return false;
        }
    }
    
    
    
    
    
    
    
    public static String getCurrentDateAndTime() {
        return getFormattedDateAndTime(new Date());
    }

    public static String getFormattedDateAndTime(final Date date) {
        final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        return dateFormat.format(date);
    }
    
    
    
}




MySamlUtils.java


```java
package com.gilight.cas.authorize.saml2;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.DOMBuilder;
import org.jdom.input.SAXBuilder;
import org.jdom.output.DOMOutputter;
import org.jdom.output.XMLOutputter;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;

import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;



/**
 * saml工具
 * @ClassName: MySamlUtils
 * @author: gy
 * @date: 2024年4月1日
 */
public class MySamlUtils {
    private static final String JSR_105_PROVIDER = "org.jcp.xml.dsig.internal.dom.XMLDSigRI";
    private static final String SAML_PROTOCOL_NS_URI_V20 = "urn:oasis:names:tc:SAML:2.0:protocol";

    /**
     * The constructor is intentionally marked as private.
     */
    private MySamlUtils() {
        // nothing to do
    }

    public static String signSamlResponse(final String samlResponse, final PrivateKey privateKey, final PublicKey publicKey, X509Certificate x509Certificate) {
        Document doc = constructDocumentFromXmlString(samlResponse);
        if (doc != null) {
            // 获取断言
            Element element = (Element) doc.getRootElement().getContent().get(1);

            // 断言签名
            final Element signedElement = signSamlElement(element, privateKey, publicKey, x509Certificate);
//            doc.setRootElement((Element) signedElement.detach());
//            return new XMLOutputter().outputString(doc);

            // final Element signedElement = signSamlElement(doc.getRootElement(), privateKey, publicKey, x509Certificate);

            //element.addContent((Element)signedElement.getContent().get(2));

            // 1.断言签名结果转字符串
            String signed = getElementXML(toDom2(signedElement)).replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "");
            System.out.println(signed);
            // TODO 2.通过samlResponse
            StringBuilder sb = new StringBuilder();
            sb.append(samlResponse.substring(0,samlResponse.indexOf("<samlp:Assertion")));
            sb.append(signed);
            sb.append(samlResponse.substring(samlResponse.indexOf("</samlp:Assertion>") + 18));

            String xml = sb.toString();


            return xml;
        }
        throw new RuntimeException("Error signing SAML Response: Null document");
    }

    public static Document constructDocumentFromXmlString(final String xmlString) {
        try {
            final SAXBuilder builder = new SAXBuilder();
            builder.setFeature("http://xml.org/sax/features/external-general-entities", false);
            builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
            return builder.build(new ByteArrayInputStream(xmlString.getBytes()));
        } catch (final Exception e) {
            return null;
        }
    }

    private static Element signSamlElement(final Element element, final PrivateKey privKey, final PublicKey pubKey, X509Certificate x509Certificate) {
        try {
            final String providerName = System.getProperty("jsr105Provider", JSR_105_PROVIDER);
            final XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance());

            List envelopedTransform = new ArrayList();
            envelopedTransform.add(sigFactory.newTransform(Transform.ENVELOPED,(TransformParameterSpec) null));
            envelopedTransform.add(sigFactory.newTransform("http://www.w3.org/2001/10/xml-exc-c14n#",(TransformParameterSpec) null));
            
//            Element element1 = (Element) element.getContent().get(1);
//            System.out.println(getElementXML(toDom(element1)));

            // final Reference ref = sigFactory.newReference("#" + element1.getAttribute("ID").getValue(), sigFactory.newDigestMethod(DigestMethod.SHA256, null), envelopedTransform, null, null);
            final Reference ref = sigFactory.newReference("", sigFactory.newDigestMethod(DigestMethod.SHA256, null), envelopedTransform, null, null);
            // final Reference ref = sigFactory.newReference("" , sigFactory.newDigestMethod(DigestMethod.SHA1, null), envelopedTransform, null, null);
            
            // Create the SignatureMethod based on the type of key
            SignatureMethod signatureMethod;
            if (pubKey instanceof DSAPublicKey) {
                signatureMethod = sigFactory.newSignatureMethod(SignatureMethod.DSA_SHA1, null);
            } else if (pubKey instanceof RSAPublicKey) {
                signatureMethod = sigFactory.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null);
                // signatureMethod = sigFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
            } else {
                throw new RuntimeException("Error signing SAML element: Unsupported type of key");
            }

            final CanonicalizationMethod canonicalizationMethod = 
                    sigFactory.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null);

            // 创建签名信息
            final SignedInfo signedInfo = sigFactory.newSignedInfo(canonicalizationMethod, signatureMethod, Collections.singletonList(ref));

            //创建包含DSA或RSA PublicKey的KeyValue
            final KeyInfoFactory keyInfoFactory = sigFactory.getKeyInfoFactory();
            
            // 使用 KeyInfoFactory 创建 KeyInfo 对象,并添加 X509Data
            KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(keyInfoFactory.newX509Data(Collections.singletonList(x509Certificate))));
            
            // 在指定位置进行数字签名
            // org.w3c.dom.Element w3cElement = toDom(element);
            org.w3c.dom.Element w3cElement = toDom2(element);
            System.err.println("----1:" + getElementXML(w3cElement));
            // 创建签名内容对象privKey私钥, w3cElement 待签名xml
            DOMSignContext signContext = new DOMSignContext(privKey, w3cElement);
            // xml签名对象signedInfo签名信息, keyInfo公钥相关信息
            XMLSignature signature = sigFactory.newXMLSignature(signedInfo, keyInfo);
            // 使用提供的私钥对指定的XML元素进行数字签名,将签名结果附加到XML文档中
            signature.sign(signContext);

            System.err.println("----2:" + getElementXML(w3cElement));
            
            return toJdom(w3cElement);
        } catch (final Exception e) {
            throw new RuntimeException("Error signing SAML element: " + e.getMessage(), e);
        }
    }

    private static Node getXmlSignatureInsertLocation(final org.w3c.dom.Element elem) {
        Node insertLocation = null;
        org.w3c.dom.NodeList nodeList = elem.getElementsByTagNameNS(SAML_PROTOCOL_NS_URI_V20, "Extensions");
        if (nodeList.getLength() != 0) {
            insertLocation = nodeList.item(nodeList.getLength() - 1);
        } else {
            nodeList = elem.getElementsByTagNameNS(SAML_PROTOCOL_NS_URI_V20, "Status");
            insertLocation = nodeList.item(nodeList.getLength() - 1);
        }
        return insertLocation;
    }


    private static org.w3c.dom.Element toDom2(final Element element) {
        try {
            // 克隆要转换的元素
            Element clonedElement = (Element) element.clone();

            // 将克隆后的元素添加到新的 org.jdom.Document 中
            Document jdomDocument = new Document(clonedElement);

            // 使用 DOMOutputter 进行转换
            DOMOutputter domOutputter = new DOMOutputter();
            org.w3c.dom.Document w3cDocument = domOutputter.output(jdomDocument);

            // 从 org.w3c.dom.Document 获取 org.w3c.dom.Element
            return w3cDocument.getDocumentElement();
        }catch (Exception e){
            return null;
        }
    }

    private static org.w3c.dom.Element toDom(final Element element) {
        return toDom(element.getDocument()).getDocumentElement();
    }

    private static org.w3c.dom.Document toDom(final Document doc) {
        try {
            final XMLOutputter xmlOutputter = new XMLOutputter();
            final StringWriter elemStrWriter = new StringWriter();
            xmlOutputter.output(doc, elemStrWriter);
            final byte[] xmlBytes = elemStrWriter.toString().getBytes();
            final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            return dbf.newDocumentBuilder().parse(new ByteArrayInputStream(xmlBytes));
        } catch (final Exception e) {
            return null;
        }
    }

    private static Element toJdom(final org.w3c.dom.Element e) {
        return  new DOMBuilder().build(e);
    }

    
    
    
    
    /**
     * 仅测试
     * @param w3cElement
     * @return
     * @author gy
     */
    public static String getElementXML(org.w3c.dom.Element w3cElement) {
        try {
            // 创建转换器工厂
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            // 创建转换器
            Transformer transformer = transformerFactory.newTransformer();
            // 将DOMSource包装W3C Element
            DOMSource domSource = new DOMSource(w3cElement);
            // 创建StringWriter来保存XML内容
            StringWriter writer = new StringWriter();
            // 将DOMSource转换为StreamResult,输出到StringWriter
            StreamResult result = new StreamResult(writer);
            // 执行转换
            transformer.transform(domSource, result);
            // 返回XML字符串
            return writer.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }



    /**
     * xml转element
     * @param xmlString
     * @return
     * @author gy
     */
    public static Element createElement(String xmlString){
        try {
            // 创建DocumentBuilder
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();

            // 将XML字符串转换为InputSource
            InputSource is = new InputSource(new StringReader(xmlString));

            // 解析XML并获取Document对象
            Document doc = (Document) builder.parse(is);

            // 获取Document的DocumentElement,即根元素<samlp:Response>
            Element rootElement = doc.getRootElement();
            return rootElement;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * xml转element
     * @param xmlString
     * @return
     * @author gy
     */
    public static Element createElement2(String xmlString){
        try {
            SAXBuilder builder = new SAXBuilder();
            Document jdomDocument = builder.build(new StringReader(xmlString));

            Element rootElement = jdomDocument.getRootElement();
            return rootElement;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    
}


  • 写回答

2条回答 默认 最新

  • 码农阿豪 Java领域优质创作者 2024-04-03 16:25
    关注
    让阿豪来帮你解答,本回答参考chatgpt3.5编写提供,如果还有疑问可以评论或留言
    该问题需要进一步了解Cas4.0的SAML2协议集成以及对断言进行签名的方法。 对于该问题,可以按照以下步骤回答:
    1. Cas4.0集成SAML2协议需要进行哪些配置? 答:Cas4.0集成SAML2协议需要在cas.properties文件中配置一些基本信息,例如: cas.samlKeystore.file=/path/to/keystore cas.samlKeystore.password=password cas.samlKeystore.privateKeyPassword=password cas.samlIdentityProvider.entityId=https://example.com cas.samlIdentityProvider.metadata.location=/path/to/idp-metadata.xml 其中,samlKeystore为Keystore文件的位置,包含了私钥和公钥,samlIdentityProvider为身份提供者的基本信息。
    2. 如何对断言进行签名? 答:对于SAML2协议断言的签名,可以按照以下步骤进行: (1) 配置Keystore文件,生成公钥和私钥。 (2) 在CAS配置文件中配置MetadataSigningCriterion,用于验证元数据和签名。 (3) 在生成的SAML响应中,使用私钥对断言部分进行签名。签名部分需要包括ID、IssueInstant、Issuer、NameID、Attributes等内容。 示例代码如下: PublicKey publicKey = (PublicKey) casSamlClient.getMetadataResolver().resolveSingle(new CriteriaSet(new EntityIdCriterion(IDP_ENTITY_ID)), "idp.crt"); PrivateKey privateKey = (PrivateKey) metadataResolver.getEntityDescriptor(SP_ENTITY_ID).getSPSSODescriptor("urn:oasis:names:tc:SAML:2.0:protocol").getKeyDescriptors(KeyDescriptor.DEFAULT_ELEMENT_NAME).get(0).getKeyInfo().getPrivateKey(); Assertion assertion = new AssertionBuilder().buildObject(); // 构建断言部分 assertion.setID("" + UUID.randomUUID().toString()); assertion.setIssueInstant(new DateTime()); assertion.setIssuer(new IssuerBuilder().buildObject()); assertion.getIssuer().setValue(IDP_ENTITY_ID); assertion.getIssuer().setFormat(NameIDType.ENTITY); assertion.setSubject(new SubjectBuilder().buildObject()); assertion.getSubject().setNameID(new NameIDBuilder().buildObject()); assertion.getSubject().getNameID().setValue(USERNAME_STRING); assertion.getSubject().getNameID().setFormat(NameIDType.PERSISTENT); assertion.setConditions(new ConditionsBuilder().buildObject()); assertion.getConditions().setNotBefore(new DateTime().minusMinutes(5)); assertion.getConditions().setNotOnOrAfter(new DateTime().plusMinutes(5)); assertion.setAuthnStatement(new AuthnStatementBuilder().buildObject()); assertion.getAuthnStatement().setAuthnInstant(new DateTime().minusMinutes(10)); assertion.getAuthnStatement().setSessionIndex("" + UUID.randomUUID().toString()); // 签名断言 Signer.signObject(assertion); // 将签名后的断言部分转换成字符串,添加到SAML响应中 StringWriter writer = new StringWriter(); Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(assertion); marshaller.marshal(assertion, writer); String assertionString = writer.toString(); String samlResponse = TEMPLATE_SAML_RESPONSE.replace("<ASSERTION_ID>", assertion.getID()).replace("<USERNAME_STRING>", USERNAME_STRING).replace("<ISSUE_INSTANT>", new DateTime().toString()).replace("<RESPONSE_ID>", "_" + UUID.randomUUID().toString()) + assertionString + "</samlp:Response>"; // 将SAML响应进行压缩 ByteArrayOutputStream baos = new ByteArrayOutputStream(); Deflater compressor = new Deflater(Deflater.DEFLATED, true); DeflaterOutputStream dos = new DeflaterOutputStream(baos, compressor); dos.write(samlResponse.getBytes("UTF-8")); dos.finish(); dos.close(); samlResponse = new String(Base64.encodeBase64(baos.toByteArray())); 可以看到,代码中使用了Signer.signObject方法进行断言签名,并将签名后的断言部分添加到了SAML响应中。另外,还使用了Deflater进行压缩,并使用Base64编码将响应部分转换成字符串。
    评论

报告相同问题?

问题事件

  • 创建了问题 4月3日

悬赏问题

  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题