|
Table of Contents
|
This page includes information for developers of EJBCA. Feel free to contribute!
Remember this, shortlist
For all non-trivial commits to EJBCA (mostly doc changes count as trivial):
- A Jira issue must exist for what you are doing
- Commits should have "ECA-xxx", where xxx is the jira issue number in the cvs comment. This allows Jira to track cvs commits for the issue.
- Only one issue per commit. Work on one feature at a time.
- JUnit tests must be there for all new features. Add also for bugfixes if possible.
- Backwards compatibility. All new features must be upgradeable from old version.
- Either no upgrade is needed.
- Profiles etc (all UpgradeableDataHashMap) have auto-upgrade features.
- 'ant upgrade' framework for database changes.
- Avoid code duplication, parameterize and re-factor code instead.
- Think quality!
Using the Issue Tracker
All checkins to CVS must be followed by an issue in the issue tracker at
https://jira.primekey.se/. This is needed to keep a good changelog, which is
vital for a succesfull release.
The only exceptions to this rule are trivial internal fixes like typos, or
removal of unused imports, constans and the like. Also documentation fixes
does not need to be tracked in jira.
If submitting patches to ejbca comitters, they should be able to create jira
issues if none exist.
Sending patches
If you are not a comitter in CVS we are glad to accept patches. You can send us patches either
in diff format (cvs diff) or created with Eclipse.
You can also send us you complete files that you changed, we can see the diffs in Eclipse.
Please follow these simple guidelines when submitting patches:
- Keep the patch limited, only change the parts related to your patch.
- Do not change other lines, such as whitespace, adding line breaks to java doc etc. It will make it very very hard for us to review the patch.
Using SVN
How to connect to the EJBCA svn repository is explained over at sourceforge, http://sourceforge.net/svn/?group_id=39716.
If you are using Eclipse we recommend the Subversive plug-in, http://www.eclipse.org/subversive/downloads.php.
Checking in to SVN
When checking in to SVN, make sure the following conditions are met:
- The checkin can be tracked to a Jira issue.
- There is JUnit test coverage for the code.
- There is sufficient documentation for the feature.
When checking in to SVN you must use a checkin comment starting with jira
issue (if linked to a jira issue). For example:
ECA-113: my comment here
In this way jira can make a reference from an issue to specified SVN
checkins, something that is very very useful.
When adding new files to SVN you must set the Id keyword property:
svn propset svn:keywords 'Id' filename.java
Eclipse
To build succesfully using Eclipse, there are .classpath and .project files in the package and in cvs.
Simply check out EJBCA as a project and you're almost set.
You must define the variable JBOSS_HOME in Window->Preferences->Java->Build Path->Classpath Variables.
Many classes are generated by XDoclet, so you must also do an 'ant' for Eclipse to find all classes needed to build the project. After checking out the project, defining JBOSS_HOME and running 'ant', you should simply refresh the project in Eclipse and voila!
You can build javadoc on all APIs used with 'ant javadoc'.
If using the J2EE version of eclipse it tries to validate JSP ans JSP fragments. Unfortunately it fails miserably at this because it is not able to see relationships between JSP and JSP fragments.
In Eclipse you can disable JSP validation in Window->Preferences->Validation. I have disabled all Build validation for all JSF, JSP, XML, HTML and Seam.
Debugging
You might notice that there is a j2ee:debug target, it will start JBoss in debug mode.
Just fire up your debugger to the default transport and address display on your console and
you're set. You can now debug your application.
You can also run JBoss from within Eclipse, this is perhaps even better.
Database connections and statements
It is very important to close connections and prepared statements when doing direct
JDBC queries. There is a utility class se.anatom.ejbca.util.JDBCUtil that helps minimize
code for this. All direct JDBC queries must be encapsulated in in a try/finally clause
as shown below:
Connection con = null;
PreparedStatement ps = null;
try {
// Do stuff,,,
} catch (Exception e) {
// handle error
} finally {
JDBCUtil.close(con);
JDBCUtil.close(ps);
}
BouncyCastle provider
EJBCA uses the BouncyCastle (BC) jce provider.
To install the provider you must use the static method:
CertTools.installBCProvier()
This is done automatically when EJBCA starts from the StartServicesServlet.
Subject and Issuer DNs
Handling of subject and issuer DNs must be done in an extremely predictable way,
and in the same way everywhere. Issue are ordering of DN elements, handling of
localized strings (UTF8) etc. Because of this, there are a few methods in
se.anatom.ejbca.util.CertTools that MUST be used when handling DNs:
stringToBCDNString() - when handling user input of a DN string to store od
match.
getSubjectDN(cert) - extracts subject DN from a certificate
getIssuerDN(cert) - extracts issuer DN from a certificate
getIssuerDN(crl) - extracts issuer DN from a CRL
Logging
Straight console output (System.out) MUST not be used in EJBCA except in
cases of console admin utilities.
There are two types of logging in EJBCA:
- CA logs, defining important events. These logs end up in the database and can
be searched through the administration Web-GUI.
- Error and debug logs. These logs use Log4j and end up in a log file defined
in JBoss.
Use the Utils
For the most mundane repetitive tasks there are usually util classes in either org.ejbca.util or in the apache
commons classes that will help avoid the same code beeing copied everywhere.
Check them out and learn to use the utils!
CA logs
There are three important classes:
Admin : Defines the administrator that performed the action.
LogEntry : Represents a line in the log database. Only the contants defined
here are used.
ILogSessionRemote/Local : The log functionality itself.
To perform logging, one must first aquire the remote interface to the log
session:
ILogSessionLocalHome logsessionhome = (ILogSessionLocalHome) getLocator().getLocalHome(ILogSessionLocalHome.COMP_NAME);
logsession = logsessionhome.create();
Next step is to log trough the function 'log', it's as easy as can be.
Parameters to the log function are:
admin : is of the class Admin and is created according to the following
criteria:
- In case a client certificate exists, new Admin(certificate)
- In other cases one of the types defined in Admin.TYPE_… ex: new Admin(Admin.TYPE_RACOMMANDLINE_USER, ip-adress). If possible, the ip-adress should be passed.
module : is one of the LogEntry.MODULE_ constants and defines in which module
the event occured.
ex : LogEntry.MODULE_CA.
time : the time of the event.
username : describes which user (endentity) that is involved in the event.
null in case no user can be considered to be involved.
certificate : defines which certificate is involved in the event. null in case
no certificate can be considered to be involved.
event : is one of the LogEntry.EVENT_ constants and defines which type of event
occured.
comment : a comment to the event.
If there are events that are not defined it is easy to add new ones, just follow
these steps:
- Add an EVENT_INFO/ERROR constant to LogEntry
- Add corresponting text in the constant LogEntry.EVENTNAMES_INFO/ERROR
- Open the file src/ra/web/raadmin/languages/languagefile.en.properies i a text editor. Go through the contants until you come to the EVENT_INFO/ERROR… constants and add the english translation. Try to keep the list sorted in alphabetical order.
If the three steps are followed the Web-GUI will be automagicaly updated and no
changes need to be done to it.
Error and debug logs
EJBCA uses the Apache Log4J package for debug-logging. This means that any class
that wants to do logging or console output MUST define:
/** Log4j instance */
private static Logger log = Logger.getLogger(<class>.class);
Logging is then done with:
log.error("message");
log.info("message");
log.debug("message");
There is also a version of the command that takes an additional Exception as
argument, were the exception stack will be printed to the log.
Where the log ends up is defined in 'log4j.properties'.
Some classes have special pre-prepared logging constructs. They are:
BaseSessionBean.java
BaseAdminCommand.java
This means that classes inheriting from one of these classes does not have to
define their own logger, but can simply use:
error("message");
info("message");
debug("message");
Debugging output for entrance and exit in methods can be added in the following
way:
public int myMethod(int arg) {
log.debug(">myMethod("+arg+")");
int ret = 0;
…
log.debug("<meMethod: return "+ret);
return ret;
}
CVS
All files should have the below part in the initial class comment:
@version $Id$
The $Id$ tag willl be expanded and handled automagically by cvs.
Example:
/**
* The main bean for the web interface, it contains all basic functions.
*
* @version $Id: DEVELOP,v 1.13 2007/12/27 16:21:46 anatom Exp $
*/
All java files should include the following header as the first lines in the file:
/*************************************************************************
* *
* 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. *
* *
*************************************************************************/
Creating new Webservice calls
To add a new call to EjbcaWS:
- Add an abstract method to IEjbcaWS.java
- Implement the method in EJbcaWS.java
- run 'ant ws.gen.server'
- Deploy EJBCA
- run 'ant ws.gen.client'
- Create JUnit tests.
Done.
Clear or hashed passwords
Passwords for users are normally stored SHA1-hashed in the database.
You can retrieve and use the password IF it is stored in clear text.
Use something like this to get the password (snip from BatchMakeP12.java):
IUserAdminSessionRemote admin = adminhome.create();
UserAdminData data = admin.findUser(administrator, username);
if ((data.getPassword() != null) && (data.getPassword().length() > 0) {
…
}
When creating the user, you must specify that the password should be in clear text,
otherwise it will be stored in hashed form, which will obvoiusly be of no use to you.
If using the Web-GUI there is a checkbox for storing the password in clear format.
If using the command line gui there is a command 'ra setclearpwd'
If using programatically:
In IUserAdminSession there is a flag 'clearpwd' to the method addUser, or you can use
the method setOpenPassword on the UserDataBean object returned from findUser.
Setting up a Utimaco HSM emulator
Utimaco have an emulator for their Cryptoserver LAN HSM, it works very good for testing and development.
CryptoServer PKCS#11 Emulation installation:
- Install Windows in VmWare, or on your machine if you are running on windows. This will emulate the CryptoServer LAN module.
- Run CESetup-2.4.exe in the windows machine. After this the CryptoServer emulator will run in a dos window.
- The CryptoServer LAN can now be reached at <ip-of-emulation-machine>:3000
- The CryptoServer LAN emulator is already initialized for PKCS#11 usage.
Setup software and initialize pkcs11 slot:
- cd <p11 directory>
- cp <Utimaco-CD>/Software/PKCS#11/lib/linux/* .
- cp <Utimaco-CD>/Software/PKCS#11/p11tool/linux/p11tool .
- ln -s libcs2_pkcs11-1.4.0.so libcs2_pkcs11.so
- vi cs2_pkcs11.ini
Device = TCP:3001@172.16.175.128
AppTimeout = 172800
- sudo cp cs2_pkcs11.ini /etc/utimaco (location can also be set with environment variable CS2_PKCS11_INI)
- ./p11tool lib=./libcs2_pkcs11.so slot=1 InitToken=officer1
- ./p11tool lib=./libcs2_pkcs11.so slot=1 loginSO=officer1 initpin=user1
Generate keys (password is user1 as initialized above):
- $EJBCA_HOME/bin/pkcs11HSM.sh generate ./libcs2_pkcs11.so 2048 defaultKey 1
- $EJBCA_HOME/bin/pkcs11HSM.sh generate ./libcs2_pkcs11.so 2048 signKey 1
- $EJBCA_HOME/bin/pkcs11HSM.sh generate ./libcs2_pkcs11.so 512 testKey 1
Create a CA in EJBCA:
- Restart JBoss if it was started. Important, you will get PKCS#11 error unless you restart JBoss after generating the keys.
- Create a new CA in EJBCA with the following properties:
slot 1
defaultKey defaultKey
certSignKey signKey
crlSignKey signKey
testKey testKey
pin user1
sharedLibrary <p11 directory>/libcs2_pkcs11.so