001: /*************************************************************************
002: * *
003: * EJBCA: The OpenSource Certificate Authority *
004: * *
005: * This software is free software; you can redistribute it and/or *
006: * modify it under the terms of the GNU Lesser General Public *
007: * License as published by the Free Software Foundation; either *
008: * version 2.1 of the License, or any later version. *
009: * *
010: * See terms of license at gnu.org. *
011: * *
012: *************************************************************************/package org.ejbca.core.model.approval;
013:
014: import java.io.ByteArrayInputStream;
015: import java.io.Externalizable;
016: import java.io.IOException;
017: import java.io.ObjectInput;
018: import java.io.ObjectOutput;
019: import java.security.cert.CertificateException;
020: import java.security.cert.CertificateFactory;
021: import java.security.cert.X509Certificate;
022: import java.util.List;
023:
024: import org.apache.commons.lang.StringUtils;
025: import org.apache.log4j.Logger;
026: import org.ejbca.core.model.log.Admin;
027: import org.ejbca.util.Base64;
028: import org.ejbca.util.CertTools;
029:
030: /**
031: * Abstract Base class representing one approval request created when
032: * an administrator performs an action that requires an approval.
033: *
034: *
035: * Contains information like:
036: * Admin that performs the request
037: * Data necessary to display the request to the approver
038: * Eventual data necessary to execute the request.
039: *
040: *
041: *
042: * @author Philip Vendil
043: * @version $Id: ApprovalRequest.java,v 1.10 2007/08/03 10:10:01 herrvendil Exp $
044: */
045:
046: public abstract class ApprovalRequest implements Externalizable {
047:
048: private static final long serialVersionUID = -1L;
049:
050: private static final Logger log = Logger
051: .getLogger(ApprovalRequest.class);
052:
053: private static final int LATEST_BASE_VERSION = 3;
054:
055: /**
056: * Simple request type means that the approver will only see new data about the
057: * action and will not compare it to old data
058: */
059: public static final int REQUESTTYPE_SIMPLE = 1;
060:
061: /**
062: * Comparing request type means that the approving administrator have to
063: * compare old data with new data in the request.
064: *
065: */
066: public static final int REQUESTTYPE_COMPARING = 2;
067:
068: /**
069: * The default request validity used if not method getRequestValidity is overridden
070: *
071: */
072: protected static final long DEFAULT_REQUESTVALIDITY = 28800 * 1000;
073: protected static final String DEFAULT_REQUESTVALIDITYSTRING = "@approval.defaultrequestvalidity@";
074:
075: /**
076: * The default approval validity used if not method getApprovalValidity is overridden
077: *
078: */
079: protected static final long DEFAULT_APPROVALVALIDITY = 28800 * 1000;
080: protected static final String DEFAULT_APPROVALVALIDITYSTRING = "@approval.defaultapprovalvalidity@";
081:
082: private Admin requestAdmin = null; // Base64 encoding of x509certificate
083:
084: private String requestSignature = null;
085:
086: private int approvalRequestType = REQUESTTYPE_SIMPLE;
087:
088: private int numOfRequiredApprovals = 0;
089:
090: private int cAId = 0;
091:
092: private int endEntityProfileId = 0;
093:
094: private boolean[] approvalSteps = { false };
095:
096: /**
097: * Main constructor of an approval request for standard one step approval request.
098: * @param requestAdminCert the certificate of the requesting admin
099: * @param requestSignature signature of the requestor (OPTIONAL, for future use)
100: * @param approvalRequestType one of TYPE_ constants
101: * @param numOfRequiredApprovals
102: * @param cAId the related cAId of the request that the approver must be authorized to or ApprovalDataVO.ANY_CA in applicable to any ca
103: * @param endEntityProfileId the related profile id that the approver must be authorized to or ApprovalDataVO.ANY_ENDENTITYPROFILE if applicable to any end entity profile
104: */
105: protected ApprovalRequest(Admin requestAdmin,
106: String requestSignature, int approvalRequestType,
107: int numOfRequiredApprovals, int cAId, int endEntityProfileId) {
108: super ();
109:
110: setRequestAdmin(requestAdmin);
111: this .requestSignature = requestSignature;
112: this .approvalRequestType = approvalRequestType;
113: this .numOfRequiredApprovals = numOfRequiredApprovals;
114: this .cAId = cAId;
115: this .endEntityProfileId = endEntityProfileId;
116: }
117:
118: /**
119: * Main constructor of an approval request.
120: * @param requestAdminCert the certificate of the requesting admin
121: * @param requestSignature signature of the requestor (OPTIONAL, for future use)
122: * @param approvalRequestType one of TYPE_ constants
123: * @param numOfRequiredApprovals
124: * @param cAId the related cAId of the request that the approver must be authorized to or ApprovalDataVO.ANY_CA in applicable to any ca
125: * @param endEntityProfileId the related profile id that the approver must be authorized to or ApprovalDataVO.ANY_ENDENTITYPROFILE if applicable to any end entity profile
126: * @param numberOfSteps that this type approval request supports.
127: */
128: protected ApprovalRequest(Admin requestAdmin,
129: String requestSignature, int approvalRequestType,
130: int numOfRequiredApprovals, int cAId,
131: int endEntityProfileId, int numberOfSteps) {
132: super ();
133:
134: setRequestAdmin(requestAdmin);
135: this .requestSignature = requestSignature;
136: this .approvalRequestType = approvalRequestType;
137: this .numOfRequiredApprovals = numOfRequiredApprovals;
138: this .cAId = cAId;
139: this .endEntityProfileId = endEntityProfileId;
140: this .approvalSteps = new boolean[numberOfSteps];
141: for (int i = 0; i < numberOfSteps; i++) {
142: this .approvalSteps[i] = false;
143: }
144: }
145:
146: /**
147: * Constuctor used in externaliziation only
148: */
149: public ApprovalRequest() {
150: }
151:
152: /**
153: * Should return true if the request if of the type that should be executed
154: * by the last approver.
155: *
156: * False if the request admin should do a polling action to try again.
157: */
158: public abstract boolean isExecutable();
159:
160: /**
161: * A main function of the ApprovalRequest, the execute() method
162: * is run when all required approvals have been made.
163: *
164: * execute should perform the action or nothing if the requesting admin
165: * is supposed to try his action again.
166: */
167: public abstract void execute()
168: throws ApprovalRequestExecutionException;
169:
170: /**
171: * Method that should generate an approval id for this type of
172: * approval, the same request i.e the same admin want's to do the
173: * same thing twice should result in the same approvalId.
174: */
175: public abstract int generateApprovalId();
176:
177: /**
178: * This method should return the request data in text representation.
179: * This text is presented for the approving administrator in order
180: * for him to make a desition about the request.
181: *
182: * Should return a List of ApprovalDataText, one for each row
183: */
184: public abstract List getNewRequestDataAsText(Admin admin);
185:
186: /**
187: * This method should return the original request data in text representation.
188: * Should only be implemented by TYPE_COMPARING ApprovalRequests.
189: * TYPE_SIMPLE requests should return null;
190: *
191: * This text is presented for the approving administrator for him to
192: * compare of what will be done.
193: *
194: * Should return a Collection of ApprovalDataText, one for each row
195: */
196: public abstract List getOldRequestDataAsText(Admin admin);
197:
198: /**
199: * This method is used to check if this is an allowed transition between
200: * two states, so that it does not require approval.
201: * Override this method to add allowed transitions.
202: *
203: * @return true if this transition does not require approval, false by default.
204: *
205: */
206: public boolean isAllowedTransition() {
207: return false;
208: }
209:
210: /**
211: * Should return the time in millisecond that the request should be valid
212: * or Long.MAX_VALUE if it should never expire
213: *
214: * Default if will return the value defined in the ejbca.properties
215: */
216: public long getRequestValidity() {
217: long ret = DEFAULT_REQUESTVALIDITY;
218: if (StringUtils.isNotEmpty(DEFAULT_REQUESTVALIDITYSTRING)) {
219: ret = Long.parseLong(DEFAULT_REQUESTVALIDITYSTRING) * 1000;
220: }
221: return ret;
222: }
223:
224: /**
225: * Should return the time in millisecond that the approval should be valid
226: * or Long.MAX_VALUE if it should never expire
227: *
228: * Default if will return the value defined in the ejbca.properties
229: */
230: public long getApprovalValidity() {
231: long ret = DEFAULT_APPROVALVALIDITY;
232: if (StringUtils.isNotEmpty(DEFAULT_APPROVALVALIDITYSTRING)) {
233: ret = Long.parseLong(DEFAULT_APPROVALVALIDITYSTRING) * 1000;
234: }
235: return ret;
236: }
237:
238: /**
239: * Should return one of the ApprovalDataVO.APPROVALTYPE_ constants
240: */
241: public abstract int getApprovalType();
242:
243: /**
244: * Method returning the number of required approvals in order to execute the request.
245: */
246: public int getNumOfRequiredApprovals() {
247: return numOfRequiredApprovals;
248: }
249:
250: /**
251: * The type of requesttype, one of TYPE_ constants
252: *
253: */
254: public int getApprovalRequestType() {
255: return approvalRequestType;
256: }
257:
258: /**
259: * @return Returns the requestSignature. OPTIONAL
260: */
261: public String getRequestSignature() {
262: return requestSignature;
263: }
264:
265: /**
266: * Returns the related ca id.
267: * The approving administrator must be authorized to this ca
268: * in order to approve it.
269: */
270: public int getCAId() {
271: return cAId;
272: }
273:
274: /**
275: * Returns the related end entity profile id.
276: * The approving administrator must be authorized to this profile
277: * in order to approve it.
278: */
279: public int getEndEntityProfileId() {
280: return endEntityProfileId;
281: }
282:
283: private void setRequestAdmin(Admin requestAdmin) {
284: this .requestAdmin = requestAdmin;
285: }
286:
287: /**
288: * Returns the certificate of the request admin.
289: */
290: public X509Certificate getRequestAdminCert() {
291: return requestAdmin.getAdminInformation().getX509Certificate();
292: }
293:
294: public Admin getRequestAdmin() {
295: return requestAdmin;
296: }
297:
298: /**
299: * Returns true if this step have been executed before.
300: * @param step to query
301: */
302: public boolean isStepDone(int step) {
303: return approvalSteps[step];
304: }
305:
306: /**
307: * Marks the given step as done.
308: * @param step to query
309: */
310: public void markStepAsDone(int step) {
311: approvalSteps[step] = true;
312: }
313:
314: /**
315: * Returns the number of steps that this approval request
316: * supports.
317: */
318: public int getNumberOfApprovalSteps() {
319: return approvalSteps.length;
320: }
321:
322: public void writeExternal(ObjectOutput out) throws IOException {
323: out.writeInt(LATEST_BASE_VERSION);
324: out.writeObject(this .requestAdmin);
325: out.writeObject(this .requestSignature);
326: out.writeInt(this .approvalRequestType);
327: out.writeInt(this .numOfRequiredApprovals);
328: out.writeInt(this .cAId);
329: out.writeInt(this .endEntityProfileId);
330: out.writeInt(this .approvalSteps.length);
331: for (int i = 0; i < approvalSteps.length; i++) {
332: out.writeBoolean(approvalSteps[i]);
333: }
334: }
335:
336: public void readExternal(ObjectInput in) throws IOException,
337: ClassNotFoundException {
338:
339: int version = in.readInt();
340: if (version == 1) {
341: String requestAdminCert = (String) in.readObject();
342: byte[] certbuf = Base64.decode(requestAdminCert.getBytes());
343: CertificateFactory cf = CertTools.getCertificateFactory();
344: X509Certificate x509cert = null;
345: try {
346: x509cert = (X509Certificate) cf
347: .generateCertificate(new ByteArrayInputStream(
348: certbuf));
349: } catch (CertificateException e) {
350: log.error(e);
351: }
352: this .requestAdmin = new Admin(x509cert);
353:
354: this .requestSignature = (String) in.readObject();
355: this .approvalRequestType = in.readInt();
356: this .numOfRequiredApprovals = in.readInt();
357: this .cAId = in.readInt();
358: this .endEntityProfileId = in.readInt();
359: this .approvalSteps = new boolean[1];
360: }
361: if (version == 2) {
362: this .requestAdmin = (Admin) in.readObject();
363: this .requestSignature = (String) in.readObject();
364: this .approvalRequestType = in.readInt();
365: this .numOfRequiredApprovals = in.readInt();
366: this .cAId = in.readInt();
367: this .endEntityProfileId = in.readInt();
368: this .approvalSteps = new boolean[1];
369: }
370: if (version == 3) {
371: this .requestAdmin = (Admin) in.readObject();
372: this .requestSignature = (String) in.readObject();
373: this .approvalRequestType = in.readInt();
374: this .numOfRequiredApprovals = in.readInt();
375: this .cAId = in.readInt();
376: this .endEntityProfileId = in.readInt();
377: int stepSize = in.readInt();
378: this .approvalSteps = new boolean[stepSize];
379: for (int i = 0; i < approvalSteps.length; i++) {
380: approvalSteps[i] = in.readBoolean();
381: }
382: }
383:
384: }
385:
386: }
|