JSD-7610 SAML单点
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

204 lines
8.3 KiB

package com.fr.plugin.xxxx.saml.xxxx.saml;
import org.apache.jcp.xml.dsig.internal.dom.DOMTransform;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.input.DOMBuilder;
import org.jdom.output.XMLOutputter;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
import javax.xml.crypto.MarshalException;
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.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class SAMLUtil {
public static String toStanderTime(Date date) {
SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
TimeZone zone = TimeZone.getTimeZone("GMT");
dayFormat.setTimeZone(zone);
timeFormat.setTimeZone(zone);
return dayFormat.format(date) + 'T' + timeFormat.format(date) + 'Z';
}
public static Calendar toDate(String t) {
String date = t.substring(0, t.indexOf("T"));
String time = t.substring(t.indexOf("T") + 1, t.length() - 1);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
// Time in GMT
TimeZone zone = TimeZone.getTimeZone("GMT");
dateFormat.setTimeZone(zone);
timeFormat.setTimeZone(zone);
try {
Date dd = dateFormat.parse(date);
Date tt = timeFormat.parse(time);
long m = dd.getTime() + tt.getTime();
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(m);
return cal;
} catch (ParseException e) {
throw new IllegalArgumentException("Invalid SAML time");
}
}
public static void addNamespace(Element root, Namespace namespace) {
if (root == null) {
return;
}
root.setNamespace(namespace);
if (root.getChildren() == null) {
return;
}
for (int index = 0; index < root.getChildren().size(); index++) {
Element child = (Element) root.getChildren().get(index);
addNamespace(child, namespace);
}
}
public static void insertSignature(org.w3c.dom.Element element,
PrivateKeyEntry privateKey, Node insertBefore) throws SAMLException {
String digestAlgorithm = SAMLAlgorithmUtil.getDigestAlgorithmValue(SAMLAlgorithmUtil.DigestAlgorithmEnum.SHA1.getKey());
String signatureAlgorithm = SAMLAlgorithmUtil.getSignatureAlgorithmValue(SAMLAlgorithmUtil.SignatureAlgorithmEnum.RSA_SHA1.getKey());
signSignature(element, privateKey, insertBefore, digestAlgorithm,
signatureAlgorithm);
}
public static void insertSignature(org.w3c.dom.Element element,
PrivateKeyEntry privateKey, Node insertBefore, String digestAlgorithm,String signatureAlgorithm)
throws SAMLException {
signSignature(element, privateKey, insertBefore,
digestAlgorithm,signatureAlgorithm);
}
private static void signSignature(org.w3c.dom.Element element,
PrivateKeyEntry privateKey, Node insertBefore,String digestAlgorithm ,String signatureAlgorithm) throws SAMLException {
String JSR_105_PROVIDER = "org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI";
String providerName = System.getProperty("jsr105Provider",
JSR_105_PROVIDER);
try {
Provider provider = (Provider) Class.forName(providerName).newInstance();
// 创建XML签名工厂
XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM", provider);
TransformService ts = TransformService.getInstance(Transform.ENVELOPED, "DOM", provider);
DOMTransform domTrasform = new DOMTransform(ts);
CanonicalizationMethod canMethod = factory.newCanonicalizationMethod(
CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null);
element.setIdAttribute("ID", true);
String refId = element.getAttribute("ID");
//消息摘要包括:MD(Message Digest,消息摘要算法)、SHA(Secure Hash Algorithm,安全散列算法)、MAC(Message AuthenticationCode,消息认证码算法)
//这里采用 安全散列算法SHA
Reference ref = factory.newReference("#" + refId,
factory.newDigestMethod(SAMLAlgorithmUtil.getDigestAlgorithmValue(digestAlgorithm), null),
Collections.singletonList(domTrasform), null, null);
// SignatureMethod signatureMethod = factory.newSignatureMethod(
// SignatureMethod.RSA_SHA1, null);
// 数字签名算法 MD5和SHA1分别是MD、SHA算法系列中最有代表性的算法
SignatureMethod signatureMethod = factory.newSignatureMethod(
SAMLAlgorithmUtil.getSignatureAlgorithmValue(signatureAlgorithm), null);
SignedInfo signedInfo = factory.newSignedInfo(canMethod,
signatureMethod, Collections.singletonList(ref));
X509Certificate cert = (X509Certificate) privateKey.getCertificate();
KeyInfoFactory kif = factory.getKeyInfoFactory();
List<Serializable> x509Content = new ArrayList<Serializable>();
x509Content.add(cert);
X509Data xd = kif.newX509Data(x509Content);
KeyInfo keyInfo = kif.newKeyInfo(Collections.singletonList(xd));
PrivateKey key = privateKey.getPrivateKey();
DOMSignContext dsc = new DOMSignContext(key, element);
dsc.setNextSibling(insertBefore);
XMLSignature signature = factory.newXMLSignature(signedInfo,keyInfo);
signature.sign(dsc);
} catch (IllegalAccessException e) {
throw new SAMLException("Error insertSignature:" + e.getMessage(),e);
} catch (MarshalException e) {
throw new SAMLException("Error insertSignature:" + e.getMessage(),e);
} catch (XMLSignatureException e) {
throw new SAMLException("Error insertSignature:" + e.getMessage(),e);
} catch (InstantiationException e) {
throw new SAMLException("Error insertSignature:" + e.getMessage(),e);
} catch (ClassNotFoundException e) {
throw new SAMLException("Error insertSignature:" + e.getMessage(),e);
} catch (NoSuchAlgorithmException e) {
throw new SAMLException("Error insertSignature:" + e.getMessage(),e);
} catch (InvalidAlgorithmParameterException e) {
throw new SAMLException("Error insertSignature:" + e.getMessage(),e);
}
}
public static org.w3c.dom.Document toDom(org.jdom.Document doc)
throws SAMLException {
try {
XMLOutputter xmlOutputter = new XMLOutputter();
StringWriter elemStrWriter = new StringWriter();
xmlOutputter.output(doc, elemStrWriter);
byte[] xmlBytes = elemStrWriter.toString().getBytes();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
setDocumentBuilderFeature(dbf);
return dbf.newDocumentBuilder().parse(
new ByteArrayInputStream(xmlBytes));
} catch (IOException e) {
throw new SAMLException("Error JDOM to W3 DOM: " + e.getMessage(), e);
} catch (ParserConfigurationException e) {
throw new SAMLException("Error JDOM to W3 DOM: " + e.getMessage(), e);
} catch (SAXException e) {
throw new SAMLException("Error JDOM to W3 DOM: " + e.getMessage(), e);
}
}
public static org.w3c.dom.Element toDom(org.jdom.Element element)
throws SAMLException {
org.jdom.Document doc = element.getDocument();
if (doc == null) {
throw new SAMLException("Invalid JDOM element");
}
return toDom(element.getDocument()).getDocumentElement();
}
public static org.jdom.Element toJdom(org.w3c.dom.Element e) {
DOMBuilder builder = new DOMBuilder();
org.jdom.Element jdomElem = builder.build(e);
return jdomElem;
}
public static void setDocumentBuilderFeature(DocumentBuilderFactory dbf)
throws ParserConfigurationException {
//必选
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,true );
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
//必选
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
}
}