Package org.ejbca.core.ejb.ca.store

Source Code of org.ejbca.core.ejb.ca.store.CertReqHistoryData$NotPossibleToFixXML

/*************************************************************************
*                                                                       *
*  EJBCA: The OpenSource Certificate Authority                          *
*                                                                       *
*  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.ejbca.core.ejb.ca.store;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.security.cert.Certificate;
import java.util.Date;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.log4j.Logger;
import org.ejbca.core.model.ca.store.CertReqHistory;
import org.ejbca.core.model.ra.UserDataVO;
import org.ejbca.util.CertTools;
import org.ejbca.util.FixEndOfBrokenXML;
import org.ejbca.util.StringTools;

/**
* Representation of historical information about the data user to create a certificate.
*
* the information is currently used to:
* - list request history for a user
* - find issuing User DN (UserDataVO) when republishing a certificate (in case the userDN for the user changed)
*
* @version $Id: CertReqHistoryData.java 11849 2011-04-29 09:50:10Z jeklund $
*/
@Entity
@Table(name="CertReqHistoryData")
public class CertReqHistoryData implements Serializable {

  private static final long serialVersionUID = 1L;
  private static final Logger log = Logger.getLogger(CertReqHistoryData.class);

  private String issuerDN;
  private String fingerprint;
  private String serialNumber;
  private long timestamp;
  private String userDataVO;
  private String username;
  private int rowVersion = 0;
  private String rowProtection;

  /**
   * Entity Bean holding info about a request data at the time the certificate was issued.
   *
   * @param incert the certificate issued
   * @param issuerDN should be the same as CertTools.getIssuerDN(incert)
   * @param UserDataVO, the data used to issue the certificate.
   */
  public CertReqHistoryData(Certificate incert, String issuerDN, UserDataVO useradmindata) {
    // Exctract fields to store with the certificate.
    setFingerprint(CertTools.getFingerprintAsString(incert));
        setIssuerDN(issuerDN);
        if (log.isDebugEnabled()) {
          log.debug("Creating certreqhistory data, serial=" + CertTools.getSerialNumberAsString(incert) + ", issuer=" + getIssuerDN());
        }
        setSerialNumber(CertTools.getSerialNumber(incert).toString());
        setTimestamp(new Date().getTime());
    setUsername(useradmindata.getUsername());
    storeUserDataVO(useradmindata);
  }
  private void storeUserDataVO(UserDataVO useradmindata) {
    try {
      // Save the user admin data in xml encoding.
      final ByteArrayOutputStream baos = new ByteArrayOutputStream();
      final XMLEncoder encoder = new XMLEncoder(baos);
      encoder.writeObject(useradmindata);
      encoder.close();
      final String s = baos.toString("UTF-8");
      if (log.isDebugEnabled()) {
        log.debug(printUserDataVOXML("useradmindata:",s));
      }
      setUserDataVO(s);
    } catch (UnsupportedEncodingException e) {
      log.error("", e);
      throw new RuntimeException(e);                                                   
    }
  }

  public CertReqHistoryData() { }
 
  /**
   * DN of issuer of certificate
   * Should not be used outside of entity bean, use getCertReqHistory instead
   * @return issuer dn
   */
  //@Column
  public String getIssuerDN() { return issuerDN; }
  /**
   * Use setIssuer instead
   * @param issuerDN issuer dn
   */
  public void setIssuerDN(String issuerDN) { this.issuerDN =issuerDN; }

  /**
   * Fingerprint of certificate
   * Should not be used outside of entity bean, use getCertReqHistory instead
   * @return fingerprint
   */
  //@Id @Column
  public String getFingerprint() { return fingerprint; }
  /**
   * Fingerprint of certificate
   * Shouldn't be set after creation.
   * @param fingerprint fingerprint
   */
  public void setFingerprint(String fingerprint) { this.fingerprint = fingerprint; }

  /**
   * Serialnumber formated as BigInteger.toString()
   * Should not be used outside of entity bean, use getCertReqHistory instead
   * @return serial number
   */
  //@Column
  public String getSerialNumber() { return serialNumber; }

  /**
   * Serialnumber formated as BigInteger.toString()
   * Shouldn't be set after creation.
   * @param serialNumber serial number
   */
  public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; }

  /**
   * Date formated as seconds since 1970 (== Date.getTime())
   * Should not be used outside of entity bean, use getCertReqHistory instead
   * @return timestamp
   */
  //@Column
  public long getTimestamp() { return timestamp; }

  /**
   * Date formated as seconds since 1970 (== Date.getTime())
   * Shouldn't be set after creation.
   * @param timestamp when certificate request info was stored
   */
  public void setTimestamp(long timestamp) { this.timestamp = timestamp; }

  /**
   * UserDataVO in xmlencoded String format
   * Should not be used outside of entity bean, use getCertReqHistory instead
   * @return  xmlencoded encoded UserDataVO
   */
  //@Column @Lob
  public String getUserDataVO() { return userDataVO; }

  /**
   * UserDataVO in  xmlencoded String format
   * Shouldn't be set after creation.
   * @param userDataVO xmlencoded encoded UserDataVO
   */
  public void setUserDataVO(String userDataVO) { this.userDataVO = userDataVO; }

  /**
   * username in database
   * Should not be used outside of entity bean, use getCertReqHistory instead
   * @return username
   */
  //@Column
  public String getUsername() { return username; }

  /**
   * username
   * Shouldn't be set after creation.
   * @param username username
   */
  public void setUsername(String username) { this.username = StringTools.strip(username); }

  //@Version @Column
  public int getRowVersion() { return rowVersion; }
  public void setRowVersion(int rowVersion) { this.rowVersion = rowVersion; }

  //@Column @Lob
  public String getRowProtection() { return rowProtection; }
  public void setRowProtection(String rowProtection) { this.rowProtection = rowProtection; }

  //
  // Public business methods used to help us manage certificates
  //

  /**
   * Returns the value object containing the information of the entity bean.
   * This is the method that should be used to retreive cert req history
   * correctly.
   *
   * NOTE: This method will try to repair broken XML and will in that case
   * update the database. This means that this method must always run in a
   * transaction!
   *
   * @return certificate request history object
   */
  @Transient
    public CertReqHistory getCertReqHistory() {

    return new CertReqHistory(this.getFingerprint(),this.getSerialNumber(),
                              this.getIssuerDN(),this.getUsername(),new Date(this.getTimestamp()),
                              decodeXML(getUserDataVO(), false));
  }
 
  /** just used internally in the this class to indicate that the XML can not be fixed.
   */
  private class NotPossibleToFixXML extends Exception {
    // just used internally in the this class to indicate that the XML can not be fixed.
    public NotPossibleToFixXML() {
      // do nothing
    }
  }
 
  /** decode objects that have been serialized to xml.
   * This method tries to fix xml that has been broken by some characters missing in the end.
   * This has been found in some older DB during upgrade from EJBCA 3.4, and seemed to be due to
   * internationalized characters. This seemed to truncate the XML somehow, and here we try to handle that
   * in a nice way. 
   */
  private UserDataVO decodeXML(final String sXML, final boolean lastTry) {
    final byte baXML[];
    try {
      baXML = sXML.getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
    final XMLDecoder decoder = new XMLDecoder(new ByteArrayInputStream(baXML));
    final UserDataVO useradmindata;
    try {
      useradmindata  = (UserDataVO) decoder.readObject();
    } catch( Throwable t ) {
      // try to repair the end of the XML string.
      // this will only succeed if a limited number of chars is lost in the end of the string
      // note that this code will not make anything worse and that it will not be run if the XML can be encoded.
      //
      try {
        if ( lastTry ) {
          return null;
        }
        final String sFixedXML = FixEndOfBrokenXML.fixXML(sXML, "string", "</void></object></java>");
        if ( sFixedXML==null ) {
          throw new NotPossibleToFixXML();         
        }
        final UserDataVO userDataVO = decodeXML(sFixedXML, true);
        if ( userDataVO==null ) {
          throw new NotPossibleToFixXML();
        }
        storeUserDataVO(userDataVO); // store it right so it does not have to be repaired again.
        log.warn(printUserDataVOXML("XML has been repaired. Trailing tags fixed. DB updated with correct XML.", sXML));
        return userDataVO;
      } catch ( NotPossibleToFixXML e ) {
        log.error(printUserDataVOXML("Not possible to decode UserDataVO. No way to fix the XML.", sXML), t);
        return null;
      }
    } finally {
      decoder.close();
    }
    if (log.isTraceEnabled() ) {
      log.trace(printUserDataVOXML("Successfully decoded UserDataVO XML.",sXML));
    }
    /* Code that fixes broken XML that has actually been parsed. It seems that the decoder is not checking for the java end tag.
     * Currently this is left out in order to not mess with working but broken XML.
    if ( sXML.indexOf("<java")>0 && sXML.indexOf("</java>")<0 ) {
      storeUserDataVO(useradmindata); // store it right       
    }
     */
    return useradmindata;
  }
  private String printUserDataVOXML(String sComment, String sXML) {
    final StringWriter sw = new StringWriter();
    final PrintWriter pw = new PrintWriter(sw);
    pw.println(sComment);
    pw.println("XMLDATA start on next line:");
    pw.print(sXML);
    pw.println("| end of XMLDATA. The char before '|' was the last XML.");
    pw.println();
    pw.println("Issuer DN: "+getIssuerDN());
    pw.println("Serial #"+getSerialNumber());
    pw.println("User name: "+getUsername());
    pw.println("Certificate fingerprint: "+getFingerprint());
    pw.println();
    return sw.toString();
  }

  //
  // Search functions.
  //

  /** @return the found entity instance or null if the entity does not exist */
  public static CertReqHistoryData findById(EntityManager entityManager, String fingerprint) {
    return entityManager.find(CertReqHistoryData.class, fingerprint);
  }
 
  /** @return return the query results as a List. */
  public static List<CertReqHistoryData> findByIssuerDNSerialNumber(EntityManager entityManager, String issuerDN, String serialNumber) {
    Query query = entityManager.createQuery("SELECT a FROM CertReqHistoryData a WHERE a.issuerDN=:issuerDN AND a.serialNumber=:serialNumber");
    query.setParameter("issuerDN", issuerDN);
    query.setParameter("serialNumber", serialNumber);
    return query.getResultList();
  }

  /** @return return the query results as a List. */
  public static List<CertReqHistoryData> findByUsername(EntityManager entityManager, String username) {
    Query query = entityManager.createQuery("SELECT a FROM CertReqHistoryData a WHERE a.username=:username");
    query.setParameter("username", username);
    return query.getResultList();
  }
}
TOP

Related Classes of org.ejbca.core.ejb.ca.store.CertReqHistoryData$NotPossibleToFixXML

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.