|
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 and whitespace 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 svn comment. This allows Jira to track svn commits for the issue.
- Only one issue per commit. Work on one feature at a time. This is critical for tracability and to be able to make good change logs.
- 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.
- Keep whitespace patches and commits separate from feature patches, so the whitespace changes does not clutter up and hide the feature diffs.
- Think quality!
Using the Issue Tracker
All checkins to SVN 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.
Getting started with EJBCA development
Development tools
- An operating system that can run Java (Linux, OSX, Windows..). Most developers use Ubuntu/Debian.
- Eclipse JEE edition with an additional Subversion (SVN) plugin installed.
- OpenJDK 6 and Sun's JDK 1.5 (for the EJBCA 3.x-branch)
- Apache Ant 1.7.x (with all the extras that comes with the zip from apache.org or 'ant-optional' Ubuntu package)
- A supported application server (JBoss AS 4.2.3.GA, 5.x etc)
- A favourite database supported by EJBCA that is easy to work with (Hypersonic, MySQL, PostgreSQL…).
- A virtualization solution for testing additional combinations of application servers and databases and external OCSP responders etc.
Changes that affect the database requires more databases to test with, changes that affect the EJBs or setup requires additional application servers etc..
What you need to know to develop EJBCA
- The tools described in the last section
- Public Key Infrastructure and related technologies
- J2EE and JEE5
- Enterprise JavaBeans (excluding message passing)
- Java Persistence API
- Java ServerPages and Java ServerFaces
- Web Services
- Databases
- …
Sending patches
If you are not a comitter in SVN we are glad to accept patches. You can send us patches either
in diff format (svn 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 svn.
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!
To run 'ant' from the command line you still have to define the environment variable APPSRV_HOME, just like when you build from the distribution zip file.
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);
}
You cannot count on that JDBC updates of a database is available from the current transaction and vice versa. So don't mix dependencies on JDBC and Entity Beans. With JPA QL this will change.
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, so if you are developing in EJBCA you don't have to bother with this.
API documentation
Being open source EJBCA comes with the best API documentation there is for developers, source code.
Developers shouldn't need lengthy paper descriptions or UML diagrams. Source code and good examples are the best tools.
Getting familiar with the concepts are always good though, so read up on this site and ejbca.org first and familiarize yourself with the concepts and workings of EJBCA.
EJB API
The EJB API can be called from command line tools, web applications or other EJB applications.
Good samples can be found in the EJBCA command line interface.
src/java/org/ejbca/ui/cli. The java classes are named logically so you should be able to figure out what they do simply by the name.
Another good sample is the EJBCA public web pages, or the servlets that drives it.
src/java/org/ejbca/ui/web/pub
Webservice API
The webservice API can be called fom any webservice client, locally or remotely.
Good sample code can be found in the EJBCA webservice command line interface.
src/java/org/ejbca/core/protocol/ws/client. Also here the java classes are named logically.
There is javadoc of the WebService API built when you run 'ant doc', look under tmp/htdocs/ws. It is also available on-line at
http://ejbca.org/ws/index.html
JUnit tests
The last source of good example code is the JUnit tests. If you plan to contribute to EJBCA you should also learn to write your own JUnit tests.
Look in the directory src/test, there are plenty of java files under there.
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) {
if (log.isTraceEnabled()) {
log.trace(">myMethod("+arg+")");
}
int ret = 0;
…
if (log.isTraceEnabled()) {
log.trace("<meMethod: return "+ret);
}
return ret;
}
Checking if trace is enabled first (it is rarely so) will avoid doing the String concatenations.
SVN
All files should have the below part in the initial class comment:
@version $Id$
The $Id$ tag willl be expanded and handled automagically by svn.
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:
EJBCA 3.10 and later
- Add an abstract method to IEjbcaWS.java
- Implement the method in EJbcaWS.java
- run 'ant ejbca-ws-generate'
- Redeploy EJBCA
- Create JUnit tests.
EJBCA 3.9 and older
- 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>:3001
- 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
JBoss PermGenSpace
When re-deploying EJBCA in JBoss, and also other application servers, they soon run out of PermGenSpace, so the whole application server must be restarted. Often even a hard kill must be done. To avoid this you can add the following to the JAVA_OPTS in run.conf in JBoss (or similar place for other app servers).
-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=128m -Xmx512m
JBoss hot re-deploy with both EJBCA and SignServer
Both EJBCA and SignServer deploys some libraries such as the BouncyCastle and various commons-* libraries. In the default configuration of JBoss 4.2.3 (and other versions?) those are shared between the two applications (See JBossClassLoadingUseCases). This can cause problem if one of the applications is re-deployed. The result is that some Servlets fails during initialization and throws either an IllegalStateException (See JBAS-7183) or a ClassNotFoundException with something like "Invalid use of destroyed classloader, UCL destroyed". The workaround is to first undeploy the other application or simply to restart JBoss.
Adding certificate extensions
- Add a new class with the OID and the ASN.1 encoding in org.ejbca.core.model.ca.certextensions.standard
- Add the new extension to the HashMap standardCertificateExtensions in org.ejbca.core.model.ca.certextensions.CertificateExtensionFactory
- Add the new extension to the HashMap useStandardCertificateExtensions in org.ejbca.core.model.ca.certificateprofiles.CertificateProfile
- Add GUI stuff for selecting if the extension should be used or not, and if some values should be entered when registering users.
Adding a new signature algorithm for CAs
To make support for a new signature algorithm when creating CAs in the admin GUI is really simple.
- A a new constant in CATokenConstants
- Add the new constant for AVAILABLE_SIGALGS in CATokenConstants
- Check that CertTools.getSignatureAlgorithm() returns the correct value.
Tests EJBCA 3.x should pass before a release
All these test should pass before a release. Make sure you have tested relevant parts of these tests after checking changes.
Build scripts
EJBCA uses Apache Ant 1.7 or later.
EJBCA 3.10 introduced improved modularisation. It should be possible to build each module separately and it should be clear what other modules it depends on.
- EJBCA_HOME/build.xml: hold all references to all build targets regular EJBCA users should be exposed to. Invoking a build target from this file invokes the corresponding target in EJBCA_HOME/modules/build.xml
- EJBCA_HOME/modules/build.xml: keeps track of all target for building different modules and the dependencies required to build a specific module
- EJBCA_HOME/modules/build-properties.xml: Holds build variables, like the directories of different modules, location of resulting distributables, variables loaded from property files and path-declarations for different sets of libraries.
- EJBCA_HOME/modules/module-name/build.xml: Build file for the module "module-name". At least contains a default "build" target and a "clean" target.
Module dependencies have to be added both to the module's target in modules/build.xml and the "build"-target in the modules directory.





