Skip to content

Instantly share code, notes, and snippets.

@kjunichi
Last active October 22, 2024 05:07
Show Gist options
  • Save kjunichi/7b03eb675dd78f87089847dc314efc1a to your computer and use it in GitHub Desktop.
Save kjunichi/7b03eb675dd78f87089847dc314efc1a to your computer and use it in GitHub Desktop.

SAMLを扱うコード

署名の検証をするあたりのコード

import java.nio.file.Paths;
import java.security.Key;
import java.security.PublicKey;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.Iterator;

import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.KeySelectorException;
import javax.xml.crypto.KeySelectorResult;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;

import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class Main {
    public void execute() throws Exception {
        System.out.println("start");
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        //Document document = builder.parse(Paths.get("rawSamlRes02.xml").toFile()); // 署名検証OKなファイル
        Document document = builder.parse(Paths.get("checkSig01.xml").toFile());
        //Document document = builder.parse(Paths.get("checkToolRes.xml").toFile()); SHA-1 NG
        // 署名要素(Signature)の特定
        Element sigNode = (Element) document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);

        String svalue = (String) sigNode.getElementsByTagNameNS(XMLSignature.XMLNS, "SignatureValue").item(0).getTextContent();
        System.out.println("svalue = " + svalue);

        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
        DOMValidateContext valContext = new DOMValidateContext(new RawX509KeySelector(), sigNode);
        NodeList anl = document.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:assertion", "Assertion");
        valContext.setIdAttributeNS((Element) anl.item(0), null, "ID");

        System.out.println("valCon");

        // unmarshal the XMLSignature
        XMLSignature signature = fac.unmarshalXMLSignature(valContext);
        System.out.println("signature : " + signature.getSignedInfo().toString());
        System.out.println("signature : " + signature.getSignatureValue().toString());
        // Validate the XMLSignature (generated above)
        boolean coreValidity=false;
        try {
        coreValidity = signature.validate(valContext);
        }catch(Exception e) {
            e.printStackTrace();
        }
        System.out.println("coreValidity = " + coreValidity);

        if (!coreValidity) {
            boolean sv = signature.getSignatureValue().validate(valContext);
            System.out.println("signature validation status: " + sv);
            Iterator i = signature.getSignedInfo().getReferences().iterator();
            for (int j = 0; i.hasNext(); j++) {
                System.out.println("j = " + j);
                boolean refValid = ((javax.xml.crypto.dsig.Reference) i.next()).validate(valContext);
                System.out.println("ref[]" + j + "] validity status: " + refValid);
            }
        }
        System.out.println("end");
    }

    public static void main(String[] args) {
        Main m = new Main();
        try {
            m.execute();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public static class RawX509KeySelector extends KeySelector {

        public KeySelectorResult select(KeyInfo keyInfo,
                KeySelector.Purpose purpose,
                AlgorithmMethod method,
                XMLCryptoContext context)
                throws KeySelectorException {
            if (keyInfo == null) {
                throw new KeySelectorException("Null KeyInfo object!");
            }
            // search for X509Data in keyinfo
            Iterator<?> iter = keyInfo.getContent().iterator();
            while (iter.hasNext()) {
                XMLStructure kiType = (XMLStructure) iter.next();
                if (kiType instanceof X509Data) {
                    X509Data xd = (X509Data) kiType;
                    Object[] entries = xd.getContent().toArray();
                    X509CRL crl = null;
                    // Looking for CRL before finding certificates
                    for (int i = 0; (i < entries.length && crl == null); i++) {
                        if (entries[i] instanceof X509CRL) {
                            crl = (X509CRL) entries[i];
                        }
                    }
                    Iterator<?> xi = xd.getContent().iterator();
                    while (xi.hasNext()) {
                        Object o = xi.next();
                        // skip non-X509Certificate entries
                        if (o instanceof X509Certificate) {
                            if ((purpose != KeySelector.Purpose.VERIFY) &&
                                    (crl != null) &&
                                    crl.isRevoked((X509Certificate) o)) {
                                continue;
                            } else {
                                return new SimpleKeySelectorResult(((X509Certificate) o).getPublicKey());
                            }
                        }
                    }
                }
            }
            throw new KeySelectorException("No X509Certificate found!");
        }
    }

    private static class SimpleKeySelectorResult implements KeySelectorResult {
        private PublicKey pk;

        SimpleKeySelectorResult(PublicKey pk) {
            this.pk = pk;
        }

        public Key getKey() {
            return pk;
        }
    }
}
import java.io.*;
import java.util.Iterator;
import java.security.PublicKey;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.security.Key;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Base64;
import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.KeySelectorException;
import javax.xml.crypto.KeySelectorResult;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyValue;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class SamlPostServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String relayState = request.getParameter("RelayState");
Document samlResponseDoc = getSamlResponse(request.getParameter("SAMLResponse"));
String upn = getUpn(samlResponseDoc);
if (relayState != null) {
HttpSession session = request.getSession();
session.setAttribute("IsAuth", "True");
session.setAttribute("UPN", upn);
//response.setHeader("UPN", upn);
response.sendRedirect(relayState);
}
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<html><head></head><body>");
// out.println("decodeSamlResponse = <textarea>" + decodeSamlResponse +
// "</textarea><br>");
//out.println("samlResponse = " + samlResponse + "<br>");
out.println("relayState = " + relayState + "<br>");
out.println("</body></html>");
out.close();
}
private String getUpn(Document document) {
// UPNの取得
NodeList attributeNl = document.getElementsByTagName("Attribute");
String upn = null;
for (int i = 0; i < attributeNl.getLength(); i++) {
Node node = attributeNl.item(i);
NamedNodeMap map = node.getAttributes();
if (map.getNamedItem("Name").getTextContent()
.equals("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress")) {
upn = node.getChildNodes().item(0).getTextContent();
System.out.println("upn = " + upn);
}
}
return upn;
}
private Document getSamlResponse(String rawSamlResponse) {
// 暗号化されているか否か?
byte[] decodeSamlResposeBuf = Base64.getDecoder().decode(rawSamlResponse);
String decodeSamlResponse = null;
try {
decodeSamlResponse = new String(decodeSamlResposeBuf, "UTf-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
StringReader reader = new StringReader(decodeSamlResponse);
Document document = null;
try {
document = builder.parse(new InputSource(reader));
} catch (SAXException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// SAMLの検証
Element sigNode = (Element) document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
DOMValidateContext valContext = new DOMValidateContext(new RawX509KeySelector(), sigNode);
// NodeList anl =
// document.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:protocol",
// "Response");
NodeList anl = document.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:assertion", "Assertion");
valContext.setIdAttributeNS((Element) anl.item(0), null, "ID");
XMLSignature signature = null;
try {
signature = fac.unmarshalXMLSignature(valContext);
} catch (MarshalException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Validate the XMLSignature (generated above)
boolean coreValidity = false;
try {
coreValidity = signature.validate(valContext);
} catch (XMLSignatureException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (!coreValidity) {
// 検証に失敗した場合
boolean sv = false;
try {
sv = signature.getSignatureValue().validate(valContext);
} catch (XMLSignatureException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("signature validation status: " + sv);
Iterator i = signature.getSignedInfo().getReferences().iterator();
for (int j = 0; i.hasNext(); j++) {
System.out.println("j = " + j);
boolean refValid = false;
try {
refValid = ((javax.xml.crypto.dsig.Reference) i.next()).validate(valContext);
} catch (XMLSignatureException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("ref[]" + j + "] validity status: " + refValid);
}
}
// 検証に成功したら処理続行
return document;
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
String upn = request.getHeader("UPN");
HttpSession session = request.getSession();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("UPN = " + upn);
out.println("<hr>");
out.println("UPN(session) = " + session.getAttribute("UPN"));
out.println("<hr>");
out.println(session.getId());
out.println("</body>");
out.println("</html>");
response.addHeader("Access-Control-Allow-Credentials", "true");
}
public static class RawX509KeySelector extends KeySelector {
public KeySelectorResult select(KeyInfo keyInfo, KeySelector.Purpose purpose, AlgorithmMethod method,
XMLCryptoContext context) throws KeySelectorException {
if (keyInfo == null) {
throw new KeySelectorException("Null KeyInfo object!");
}
// search for X509Data in keyinfo
Iterator<?> iter = keyInfo.getContent().iterator();
while (iter.hasNext()) {
XMLStructure kiType = (XMLStructure) iter.next();
if (kiType instanceof X509Data) {
X509Data xd = (X509Data) kiType;
Object[] entries = xd.getContent().toArray();
X509CRL crl = null;
// Looking for CRL before finding certificates
for (int i = 0; (i < entries.length && crl == null); i++) {
if (entries[i] instanceof X509CRL) {
crl = (X509CRL) entries[i];
}
}
Iterator<?> xi = xd.getContent().iterator();
while (xi.hasNext()) {
Object o = xi.next();
// skip non-X509Certificate entries
if (o instanceof X509Certificate) {
if ((purpose != KeySelector.Purpose.VERIFY) && (crl != null)
&& crl.isRevoked((X509Certificate) o)) {
continue;
} else {
return new SimpleKeySelectorResult(((X509Certificate) o).getPublicKey());
}
}
}
}
}
throw new KeySelectorException("No X509Certificate found!");
}
}
private static class SimpleKeySelectorResult implements KeySelectorResult {
private PublicKey pk;
SimpleKeySelectorResult(PublicKey pk) {
this.pk = pk;
}
public Key getKey() {
return pk;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment