Untitled

 avatar
unknown
plain_text
a month ago
7.2 kB
5
Indexable
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.io.StringWriter;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

public class SAMLDecoder {
    
    public static class SAMLResponse {
        private String issuer;
        private String nameId;
        private String recipient;
        private Map<String, String> attributes;
        
        public SAMLResponse() {
            this.attributes = new HashMap<>();
        }
        
        // Getters and setters
        public String getIssuer() { return issuer; }
        public void setIssuer(String issuer) { this.issuer = issuer; }
        public String getNameId() { return nameId; }
        public void setNameId(String nameId) { this.nameId = nameId; }
        public String getRecipient() { return recipient; }
        public void setRecipient(String recipient) { this.recipient = recipient; }
        public Map<String, String> getAttributes() { return attributes; }
    }

    public static SAMLResponse decodeSAMLResponseFromFile(File file) throws Exception {
        SAMLResponse response = new SAMLResponse();
        
        // Create a buffered reader with a large buffer size
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8), 
                8192 * 4)) { // 32KB buffer
            
            // Read and decode the base64 content in chunks
            StringBuilder base64Content = new StringBuilder();
            char[] buffer = new char[8192]; // 8KB chunks
            int bytesRead;
            
            while ((bytesRead = reader.read(buffer)) != -1) {
                base64Content.append(buffer, 0, bytesRead);
            }
            
            // Create decoder that can handle large content
            Base64.Decoder decoder = Base64.getMimeDecoder();
            byte[] decodedBytes = decoder.decode(base64Content.toString().replaceAll("\\s+", ""));
            
            // Create XML input factory for streaming
            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
            // Disable external entity processing
            xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
            xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
            
            // Create XML stream reader
            XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(
                new ByteArrayInputStream(decodedBytes));
            
            // Process XML stream
            String currentElement = "";
            while (xmlStreamReader.hasNext()) {
                int event = xmlStreamReader.next();
                
                switch (event) {
                    case XMLStreamReader.START_ELEMENT:
                        currentElement = xmlStreamReader.getLocalName();
                        
                        if ("Issuer".equals(currentElement)) {
                            response.setIssuer(xmlStreamReader.getElementText());
                        } 
                        else if ("NameID".equals(currentElement)) {
                            response.setNameId(xmlStreamReader.getElementText());
                        }
                        else if ("SubjectConfirmationData".equals(currentElement)) {
                            response.setRecipient(xmlStreamReader.getAttributeValue(null, "Recipient"));
                        }
                        else if ("Attribute".equals(currentElement)) {
                            String attributeName = xmlStreamReader.getAttributeValue(null, "Name");
                            // Get the attribute value in the next iteration
                            while (xmlStreamReader.hasNext()) {
                                event = xmlStreamReader.next();
                                if (event == XMLStreamReader.START_ELEMENT && 
                                    "AttributeValue".equals(xmlStreamReader.getLocalName())) {
                                    String attributeValue = xmlStreamReader.getElementText();
                                    response.getAttributes().put(attributeName, attributeValue);
                                    break;
                                }
                            }
                        }
                        break;
                }
            }
            
            xmlStreamReader.close();
        }
        
        return response;
    }

    public static void streamProcessLargeSAMLResponse(File inputFile, File outputFile) throws Exception {
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(inputFile), StandardCharsets.UTF_8),
                8192 * 4)) {
            
            // Process in chunks and write to output file
            Base64.Decoder decoder = Base64.getMimeDecoder();
            java.io.FileOutputStream fos = new java.io.FileOutputStream(outputFile);
            
            char[] buffer = new char[8192];
            int bytesRead;
            byte[] decodedChunk;
            
            while ((bytesRead = reader.read(buffer)) != -1) {
                if (bytesRead > 0) {
                    String chunk = new String(buffer, 0, bytesRead);
                    // Remove whitespace and decode
                    decodedChunk = decoder.decode(chunk.replaceAll("\\s+", ""));
                    fos.write(decodedChunk);
                }
            }
            
            fos.close();
        }
    }

    // Example usage
    public static void main(String[] args) {
        try {
            // For huge SAML response stored in a file
            File inputFile = new File("huge_saml_response.txt");
            
            // Option 1: Parse and get structured data
            SAMLResponse response = decodeSAMLResponseFromFile(inputFile);
            System.out.println("Issuer: " + response.getIssuer());
            System.out.println("NameID: " + response.getNameId());
            System.out.println("Recipient: " + response.getRecipient());
            System.out.println("\nAttributes:");
            response.getAttributes().forEach((key, value) -> 
                System.out.println(key + ": " + value));
            
            // Option 2: Just decode to a new file
            File outputFile = new File("decoded_saml.xml");
            streamProcessLargeSAMLResponse(inputFile, outputFile);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Leave a Comment