org.signserver.module.pdfsigner.PDFSignerParameters.java Source code

Java tutorial

Introduction

Here is the source code for org.signserver.module.pdfsigner.PDFSignerParameters.java

Source

/*************************************************************************
 *                                                                       *
 *  SignServer: The OpenSource Automated Signing Server                  *
 *                                                                       *
 *  This software is free software; you can redistribute it and/or       *
 *  modify it under the terms of the GNU Lesser General Public           *
 *  License as published by the Free Software Foundation; either         *
 *  version 2.1 of the License, or any later version.                    *
 *                                                                       *
 *  See terms of license at gnu.org.                                     *
 *                                                                       *
 *************************************************************************/
package org.signserver.module.pdfsigner;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;

import org.apache.log4j.Logger;
import org.ejbca.util.Base64;
import org.signserver.common.IllegalRequestException;
import org.signserver.common.SignServerException;
import org.signserver.common.WorkerConfig;

import com.lowagie.text.BadElementException;
import com.lowagie.text.Image;
import com.lowagie.text.pdf.PdfSignatureAppearance;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * Class that holds configuration values passed to pdfsigner.
 *
 * @author rayback_2
 * @version $Id: PDFSignerParameters.java 4709 2014-05-19 12:16:50Z malu9369 $
 */
public class PDFSignerParameters {

    /** Logger for this class. */
    private static final Logger LOG = Logger.getLogger(PDFSignerParameters.class);

    private int workerId;
    private WorkerConfig config;

    // private member declarations holding configuration property values
    private String reason = PDFSigner.REASONDEFAULT;
    private String location = PDFSigner.LOCATIONDEFAULT;

    private boolean add_visible_signature = PDFSigner.ADD_VISIBLE_SIGNATURE_DEFAULT;
    private String visible_sig_page = PDFSigner.VISIBLE_SIGNATURE_PAGE_DEFAULT;
    private String visible_sig_rectangle = PDFSigner.VISIBLE_SIGNATURE_RECTANGLE_DEFAULT;
    private int visible_sig_rectangle_llx;
    private int visible_sig_rectangle_lly;
    private int visible_sig_rectangle_urx;
    private int visible_sig_rectangle_ury;

    private String visible_sig_custom_image_base64;
    private String visible_sig_custom_image_path;
    private boolean visible_sig_custom_image_scale_to_rectangle = PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_SCALE_TO_RECTANGLE_DEFAULT;

    private int certification_level = PDFSigner.CERTIFICATION_LEVEL_DEFAULT;

    private String tsa_url;
    private String tsa_username;
    private String tsa_password;

    private boolean embed_crl = PDFSigner.EMBED_CRL_DEFAULT;
    private boolean embed_ocsp_response = PDFSigner.EMBED_OCSP_RESPONSE_DEFAULT;

    /** Used to mitigate a collision signature vulnerability described in http://pdfsig-collision.florz.de/ */
    private boolean refuseDoubleIndirectObjects;

    /** Permissions to not allow in a document. */
    private Set<String> rejectPermissions = new HashSet<String>();
    /** Permissions to set. **/
    private Permissions setPermissions;
    /** Permissions to remove. **/
    private Set<String> removePermissions;
    /** Password to set as owner password. */
    private String setOwnerPassword;

    // helper variables
    private boolean use_custom_image = false;
    private boolean use_timestamp = false;
    private boolean use_timestamp_authorization = false;
    private Image custom_image = null;

    private String tsa_worker;

    public PDFSignerParameters(int workerId, WorkerConfig config)
            throws IllegalRequestException, SignServerException {
        this.workerId = workerId;
        this.config = config;
        extractAndProcessConfigurationProperties();
    }

    private void extractAndProcessConfigurationProperties() throws IllegalRequestException, SignServerException {

        // The reason shown in the PDF signature
        if (config.getProperties().getProperty(PDFSigner.REASON) != null) {
            reason = config.getProperties().getProperty(PDFSigner.REASON);
        }
        LOG.debug("Using reason: " + reason);

        // The location shown in the PDF signature
        if (config.getProperties().getProperty(PDFSigner.LOCATION) != null) {
            location = config.getProperties().getProperty(PDFSigner.LOCATION);
        }
        LOG.debug("Using location: " + location);

        // are we adding visible or invisible signature
        // note : ParseBoolean returns false for everything but "True"
        if (config.getProperties().getProperty(PDFSigner.ADD_VISIBLE_SIGNATURE) != null) {
            add_visible_signature = Boolean
                    .parseBoolean(config.getProperties().getProperty(PDFSigner.ADD_VISIBLE_SIGNATURE).trim());
        }
        LOG.debug("Using visible signature: " + add_visible_signature);

        // timestamp url
        if (config.getProperties().getProperty(PDFSigner.TSA_URL) != null) {
            tsa_url = config.getProperties().getProperty(PDFSigner.TSA_URL);
            use_timestamp = true;
            LOG.debug("Using tsa url : " + tsa_url);
        } else if (config.getProperties().getProperty(PDFSigner.TSA_WORKER) != null) {
            tsa_worker = config.getProperties().getProperty(PDFSigner.TSA_WORKER);
            use_timestamp = true;
        }

        if (use_timestamp && config.getProperties().getProperty(PDFSigner.TSA_USERNAME) != null
                && config.getProperties().getProperty(PDFSigner.TSA_PASSWORD) != null) {
            tsa_username = config.getProperties().getProperty(PDFSigner.TSA_USERNAME);
            tsa_password = config.getProperties().getProperty(PDFSigner.TSA_PASSWORD);
            use_timestamp_authorization = true;
        }

        // should we embed crl inside the cms package
        if (config.getProperties().getProperty(PDFSigner.EMBED_CRL) != null) {
            embed_crl = Boolean.parseBoolean(config.getProperties().getProperty(PDFSigner.EMBED_CRL).trim());
        }
        LOG.debug("Using embed crl inside cms package : " + isEmbed_crl());

        // should we embed ocsp response inside the cms package
        if (config.getProperties().getProperty(PDFSigner.EMBED_OCSP_RESPONSE) != null) {
            embed_ocsp_response = Boolean
                    .parseBoolean(config.getProperties().getProperty(PDFSigner.EMBED_OCSP_RESPONSE).trim());
        }
        LOG.debug("Using embed ocsp inside cms package : " + isEmbed_ocsp_response());

        // should we refuse PDF documents that contains multiple
        // indirect objects with the same name
        if (config.getProperties().getProperty(PDFSigner.REFUSE_DOUBLE_INDIRECT_OBJECTS) != null) {
            refuseDoubleIndirectObjects = Boolean
                    .parseBoolean(config.getProperties().getProperty(PDFSigner.REFUSE_DOUBLE_INDIRECT_OBJECTS));
        }

        // Reject permissions
        String rejectPermissionsValue = config.getProperties().getProperty(PDFSigner.REJECT_PERMISSIONS);
        if (rejectPermissionsValue != null) {
            String[] array = rejectPermissionsValue.split(",");
            rejectPermissions.addAll(Arrays.asList(array));
        }
        // Set permissions
        String setPermissionsValue = config.getProperties().getProperty(PDFSigner.SET_PERMISSIONS);
        if (setPermissionsValue != null) {
            String[] array = setPermissionsValue.split(",");
            try {
                setPermissions = Permissions.fromSet(Arrays.asList(array), true);
            } catch (UnknownPermissionException ex) {
                throw new SignServerException("Signer " + workerId + " missconfigured: " + ex.getMessage());
            }
        }
        // Remove permissions
        String removePermissionsValue = config.getProperties().getProperty(PDFSigner.REMOVE_PERMISSIONS);
        if (removePermissionsValue != null) {
            String[] array = removePermissionsValue.split(",");
            removePermissions = new HashSet<String>();
            removePermissions.addAll(Arrays.asList(array));
        }
        // Set ownerpassword
        setOwnerPassword = config.getProperties().getProperty(PDFSigner.SET_OWNERPASSWORD);

        // if signature is chosen to be visible proceed with setting visibility
        // properties
        if (add_visible_signature) {
            // page to draw visible signature at
            if (config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_PAGE) != null) {
                visible_sig_page = config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_PAGE);
            }

            LOG.debug("Using visible signature page: " + visible_sig_page);

            // The location of the visible signature rectangle(llx, lly, urx,
            // ury)
            // llx = lower left x coordinate, lly = lower left y coordinate, urx
            // = upper right x coordinate, ury = upper right y coordinate
            if (config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_RECTANGLE) != null) {
                visible_sig_rectangle = config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_RECTANGLE);
            }
            LOG.debug("Using rectangle: " + visible_sig_rectangle);

            String[] rect = visible_sig_rectangle.split(",");
            if (rect.length < 4) {
                throw new IllegalRequestException(
                        "RECTANGLE property must contain 4 comma separated values with no spaces.");
            }
            visible_sig_rectangle_llx = Integer.valueOf(rect[0]);
            visible_sig_rectangle_lly = Integer.valueOf(rect[1]);
            visible_sig_rectangle_urx = Integer.valueOf(rect[2]);
            visible_sig_rectangle_ury = Integer.valueOf(rect[3]);

            // custom image to use with signature
            // base64 encoded byte[]
            if (config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_BASE64) != null) {
                visible_sig_custom_image_base64 = config.getProperties()
                        .getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_BASE64);
                LOG.debug("base64 encoded custom image is set");
            }

            // custom image path. Do not set if base64 encoded image is
            // specified
            if (visible_sig_custom_image_base64 == null || visible_sig_custom_image_base64.isEmpty()) {
                if (config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_PATH) != null) {
                    visible_sig_custom_image_path = config.getProperties()
                            .getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_PATH);
                    LOG.debug("using custom image path : " + visible_sig_custom_image_path);
                }
            }

            boolean use_image_from_base64_string = visible_sig_custom_image_base64 != null
                    && !visible_sig_custom_image_base64.isEmpty();
            boolean use_image_from_path = visible_sig_custom_image_path != null
                    && !visible_sig_custom_image_path.isEmpty();

            use_custom_image = use_image_from_base64_string || use_image_from_path;

            // custom image resizing (if we are using custom image)
            if (use_custom_image) {

                // retrieve custom image
                byte[] imageByteArray;
                if (use_image_from_base64_string) {
                    imageByteArray = Base64.decode(visible_sig_custom_image_base64.getBytes());
                } else {
                    try {
                        imageByteArray = readFile(visible_sig_custom_image_path);
                    } catch (IOException e) {
                        throw new SignServerException("Error reading custom image data from path specified", e);
                    }
                }

                try {
                    custom_image = Image.getInstance(imageByteArray);
                } catch (BadElementException e) {
                    throw new SignServerException("Problem constructing image from custom image data", e);
                } catch (MalformedURLException e) {
                    throw new SignServerException("Problem constructing image from custom image data", e);
                } catch (IOException e) {
                    throw new SignServerException("Problem constructing image from custom image data", e);
                }

                if (config.getProperties()
                        .getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_SCALE_TO_RECTANGLE) != null) {
                    visible_sig_custom_image_scale_to_rectangle = Boolean.parseBoolean(config.getProperties()
                            .getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_SCALE_TO_RECTANGLE).trim());
                    LOG.debug("resize custom image to rectangle : " + visible_sig_custom_image_scale_to_rectangle);
                }

                // if we are using custom image and the
                // VISIBLE_SIGNATURE_CUSTOM_IMAGE_SCALE_TO_RECTANGLE is set to
                // true resize image to fit to rectangle specified
                // If set to false calculate urx and ury coordinates from image
                if (visible_sig_custom_image_scale_to_rectangle) {
                    resizeImageToFitToRectangle();
                } else {
                    calculateUpperRightRectangleCoordinatesFromImage();
                }
            }
        }

        // Certification level
        final String level = config.getProperty(PDFSigner.CERTIFICATION_LEVEL);
        if (level != null) {
            if (level.equalsIgnoreCase("NO_CHANGES_ALLOWED")) {
                certification_level = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED;
            } else if (level.equalsIgnoreCase("FORM_FILLING_AND_ANNOTATIONS")) {
                certification_level = PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS;
            } else if (level.equalsIgnoreCase("FORM_FILLING")) {
                certification_level = PdfSignatureAppearance.CERTIFIED_FORM_FILLING;
            } else if (level.equalsIgnoreCase("NOT_CERTIFIED")) {
                certification_level = PdfSignatureAppearance.NOT_CERTIFIED;
            } else {
                throw new SignServerException("Unknown value for CERTIFICATION_LEVEL");
            }
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("using certification level: " + certification_level);
        }
    }

    /**
     * Read byte[] data from file.
     *
     * @param pFilePath
     * @return content of file
     * @throws IOException
     */
    public byte[] readFile(String pFilePath) throws IOException {
        FileInputStream fis = null;
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        try {
            fis = new FileInputStream(pFilePath);
            byte[] buff = new byte[1024];
            int count;
            while ((count = fis.read(buff, 0, buff.length)) > 0) {
                bout.write(buff, 0, count);
            }
        } finally {
            if (fis != null) {
                fis.close();
            }
        }

        return bout.toByteArray();
    }

    /**
     * resize image to fit to a specified rectangle
     */
    private void resizeImageToFitToRectangle() {
        float newWidth = visible_sig_rectangle_urx - visible_sig_rectangle_llx;
        float newHeight = visible_sig_rectangle_ury - visible_sig_rectangle_lly;
        custom_image.scaleToFit(newWidth, newHeight);
    }

    /**
     * set upper right coordinates of the rectangle from given image
     */
    private void calculateUpperRightRectangleCoordinatesFromImage() {
        visible_sig_rectangle_urx = (int) (visible_sig_rectangle_llx + custom_image.getWidth());
        visible_sig_rectangle_ury = (int) (visible_sig_rectangle_lly + custom_image.getHeight());
    }

    public String getReason() {
        return reason;
    }

    public String getLocation() {
        return location;
    }

    public boolean isAdd_visible_signature() {
        return add_visible_signature;
    }

    public String getVisible_sig_page() {
        return visible_sig_page;
    }

    public String getVisible_sig_rectangle() {
        return visible_sig_rectangle;
    }

    public int getVisible_sig_rectangle_llx() {
        return visible_sig_rectangle_llx;
    }

    public int getVisible_sig_rectangle_lly() {
        return visible_sig_rectangle_lly;
    }

    public int getVisible_sig_rectangle_urx() {
        return visible_sig_rectangle_urx;
    }

    public int getVisible_sig_rectangle_ury() {
        return visible_sig_rectangle_ury;
    }

    public String getVisible_sig_custom_image_base64() {
        return visible_sig_custom_image_base64;
    }

    public String getVisible_sig_custom_image_path() {
        return visible_sig_custom_image_path;
    }

    public boolean isVisible_sig_custom_image_scale_to_rectangle() {
        return visible_sig_custom_image_scale_to_rectangle;
    }

    public String getTsa_url() {
        return tsa_url;
    }

    public String getTsa_worker() {
        return tsa_worker;
    }

    public String getTsa_username() {
        return tsa_username;
    }

    public String getTsa_password() {
        return tsa_password;
    }

    public boolean isUse_custom_image() {
        return use_custom_image;
    }

    public boolean isUse_timestamp() {
        return use_timestamp;
    }

    public boolean isUse_timestamp_authorization() {
        return use_timestamp_authorization;
    }

    public Image getCustom_image() {
        return custom_image;
    }

    public boolean isEmbed_crl() {
        return embed_crl;
    }

    public boolean isEmbed_ocsp_response() {
        return embed_ocsp_response;
    }

    /**
     * @return if we should refuse PDF documents that contains multiple
     * indirect objects with the same name
     */
    public boolean isRefuseDoubleIndirectObjects() {
        return refuseDoubleIndirectObjects;
    }

    public int getCertification_level() {
        return certification_level;
    }

    /**
     * @return Set with permissions to reject.
     */
    public Set<String> getRejectPermissions() {
        return rejectPermissions;
    }

    /**
     * @return Permissions to remove or null.
     */
    public Set<String> getRemovePermissions() {
        return removePermissions;
    }

    /**
     * @return The permissions to use or null.
     */
    public Permissions getSetPermissions() {
        return setPermissions;
    }

    /**
     * @return The owner password to set or null.
     */
    public String getSetOwnerPassword() {
        return setOwnerPassword;
    }

}