org.ejbca.core.ejb.ra.EndEntityManagementSessionTest.java Source code

Java tutorial

Introduction

Here is the source code for org.ejbca.core.ejb.ra.EndEntityManagementSessionTest.java

Source

/*************************************************************************
 *                                                                       *
 *  EJBCA Community: 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.ra;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.security.KeyPair;
import java.security.Principal;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import javax.security.auth.x500.X500Principal;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.bouncycastle.jce.X509KeyUsage;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.cesecore.ErrorCode;
import org.cesecore.authentication.tokens.AuthenticationSubject;
import org.cesecore.authentication.tokens.AuthenticationToken;
import org.cesecore.authentication.tokens.UsernamePrincipal;
import org.cesecore.authorization.AuthorizationDeniedException;
import org.cesecore.authorization.control.AccessControlSessionRemote;
import org.cesecore.authorization.control.StandardRules;
import org.cesecore.authorization.rules.AccessRuleData;
import org.cesecore.authorization.rules.AccessRuleState;
import org.cesecore.authorization.user.AccessMatchType;
import org.cesecore.authorization.user.AccessUserAspectData;
import org.cesecore.authorization.user.matchvalues.X500PrincipalAccessMatchValue;
import org.cesecore.certificates.ca.CADoesntExistsException;
import org.cesecore.certificates.ca.CAInfo;
import org.cesecore.certificates.ca.CaSessionRemote;
import org.cesecore.certificates.certificate.CertificateConstants;
import org.cesecore.certificates.certificate.CertificateDataWrapper;
import org.cesecore.certificates.certificate.CertificateStatus;
import org.cesecore.certificates.certificate.CertificateStoreSessionRemote;
import org.cesecore.certificates.certificate.InternalCertificateStoreSessionRemote;
import org.cesecore.certificates.certificateprofile.CertificateProfileConstants;
import org.cesecore.certificates.crl.RevokedCertInfo;
import org.cesecore.certificates.endentity.EndEntityConstants;
import org.cesecore.certificates.endentity.EndEntityInformation;
import org.cesecore.certificates.endentity.EndEntityType;
import org.cesecore.certificates.endentity.EndEntityTypes;
import org.cesecore.certificates.util.AlgorithmConstants;
import org.cesecore.certificates.util.DnComponents;
import org.cesecore.configuration.GlobalConfigurationSessionRemote;
import org.cesecore.keys.util.KeyTools;
import org.cesecore.keys.util.PublicKeyWrapper;
import org.cesecore.mock.authentication.SimpleAuthenticationProviderSessionRemote;
import org.cesecore.mock.authentication.tokens.TestAlwaysAllowLocalAuthenticationToken;
import org.cesecore.mock.authentication.tokens.TestX509CertificateAuthenticationToken;
import org.cesecore.roles.RoleData;
import org.cesecore.roles.access.RoleAccessSessionRemote;
import org.cesecore.roles.management.RoleManagementSessionRemote;
import org.cesecore.util.CertTools;
import org.cesecore.util.CryptoProviderTools;
import org.cesecore.util.EjbRemoteHelper;
import org.ejbca.config.GlobalConfiguration;
import org.ejbca.core.EjbcaException;
import org.ejbca.core.ejb.ca.CaTestCase;
import org.ejbca.core.ejb.ca.caadmin.CAAdminSessionRemote;
import org.ejbca.core.ejb.ca.publisher.PublisherQueueProxySessionRemote;
import org.ejbca.core.ejb.ca.sign.SignSessionRemote;
import org.ejbca.core.ejb.ra.raadmin.EndEntityProfileSessionRemote;
import org.ejbca.core.model.SecConst;
import org.ejbca.core.model.authorization.AccessRulesConstants;
import org.ejbca.core.model.ca.publisher.PublisherConst;
import org.ejbca.core.model.ca.publisher.PublisherQueueVolatileInformation;
import org.ejbca.core.model.ra.AlreadyRevokedException;
import org.ejbca.core.model.ra.NotFoundException;
import org.ejbca.core.model.ra.raadmin.EndEntityProfile;
import org.ejbca.core.model.ra.raadmin.UserDoesntFullfillEndEntityProfile;
import org.ejbca.util.query.BasicMatch;
import org.ejbca.util.query.Query;
import org.ejbca.util.query.UserMatch;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

/**
 * Tests the EndEntityInformation entity bean and some parts of EndEntityManagementSession.
 * 
 * @version $Id$
 */
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class EndEntityManagementSessionTest extends CaTestCase {

    private static final Logger log = Logger.getLogger(EndEntityManagementSessionTest.class);
    private static final AuthenticationToken admin = new TestAlwaysAllowLocalAuthenticationToken(
            new UsernamePrincipal("EndEntityManagementSessionTest"));
    private int caid = getTestCAId();

    private static String username;
    private static String pwd;
    private static ArrayList<String> usernames = new ArrayList<String>();
    private static String serialnumber;

    private CAAdminSessionRemote caAdminSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(CAAdminSessionRemote.class);
    private CaSessionRemote caSession = EjbRemoteHelper.INSTANCE.getRemoteSession(CaSessionRemote.class);
    private EndEntityAccessSessionRemote endEntityAccessSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(EndEntityAccessSessionRemote.class);
    private EndEntityProfileSessionRemote endEntityProfileSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(EndEntityProfileSessionRemote.class);;
    private EndEntityManagementSessionRemote endEntityManagementSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(EndEntityManagementSessionRemote.class);
    private InternalCertificateStoreSessionRemote internalCertStoreSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(InternalCertificateStoreSessionRemote.class, EjbRemoteHelper.MODULE_TEST);
    private CertificateStoreSessionRemote certificateStoreSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(CertificateStoreSessionRemote.class);
    private SignSessionRemote signSession = EjbRemoteHelper.INSTANCE.getRemoteSession(SignSessionRemote.class);
    private SimpleAuthenticationProviderSessionRemote simpleAuthenticationProvider = EjbRemoteHelper.INSTANCE
            .getRemoteSession(SimpleAuthenticationProviderSessionRemote.class, EjbRemoteHelper.MODULE_TEST);
    private RoleManagementSessionRemote roleManagementSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(RoleManagementSessionRemote.class);
    private RoleAccessSessionRemote roleAccessSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(RoleAccessSessionRemote.class);
    private AccessControlSessionRemote accessControlSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(AccessControlSessionRemote.class);
    private GlobalConfigurationSessionRemote globalConfSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(GlobalConfigurationSessionRemote.class);
    private EndEntityManagementProxySessionRemote endEntityManagementProxySession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(EndEntityManagementProxySessionRemote.class, EjbRemoteHelper.MODULE_TEST);
    private PublisherQueueProxySessionRemote publisherQueueSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(PublisherQueueProxySessionRemote.class, EjbRemoteHelper.MODULE_TEST);

    @BeforeClass
    public static void beforeClass() {
        CryptoProviderTools.installBCProviderIfNotAvailable();
        // Make user that we know later...
        username = genRandomUserName();
        pwd = genRandomPwd();
    }

    @Before
    public void setUp() throws Exception {
        super.setUp();
    }

    @After
    public void tearDown() throws Exception {
        super.tearDown();
        for (int i = 0; i < usernames.size(); i++) {
            try {
                endEntityManagementSession.deleteUser(admin, (String) usernames.get(i));
            } catch (Exception e) {
            } // NOPMD, ignore errors so we don't stop deleting users because
              // one of them does not exist.
        }
        try {
            endEntityProfileSession.removeEndEntityProfile(admin, "TESTMERGEWITHWS");
        } catch (Exception e) {
        } // NOPMD, ignore errors
    }

    public String getRoleName() {
        return this.getClass().getSimpleName();
    }

    private void genRandomSerialnumber() throws Exception {
        // Gen random number
        Random rand = new Random(new Date().getTime() + 4913);
        serialnumber = "";
        for (int i = 0; i < 8; i++) {
            int randint = rand.nextInt(9);
            serialnumber += (Integer.valueOf(randint)).toString();
        }
        log.debug("Generated random serialnumber: serialnumber =" + serialnumber);

    } // genRandomSerialnumber

    /**
     * tests creation of new user and duplicate user
     * 
     * @throws Exception error
     */
    private void addUser() throws Exception {
        log.trace(">addUser()");

        String email = username + "@anatom.se";
        endEntityManagementSession.addUser(admin, username, pwd, "C=SE, O=AnaTom, CN=" + username,
                "rfc822name=" + email, email, true, SecConst.EMPTY_ENDENTITYPROFILE,
                CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER, EndEntityTypes.ENDUSER.toEndEntityType(),
                SecConst.TOKEN_SOFT_P12, 0, caid);
        usernames.add(username);
        log.debug("created user: " + username + ", " + pwd + ", C=SE, O=AnaTom, CN=" + username);
        // Add the same user again
        boolean userexists = false;
        try {
            endEntityManagementSession.addUser(admin, username, pwd, "C=SE, O=AnaTom, CN=" + username,
                    "rfc822name=" + email, email, true, SecConst.EMPTY_ENDENTITYPROFILE,
                    CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER, EndEntityTypes.ENDUSER.toEndEntityType(),
                    SecConst.TOKEN_SOFT_P12, 0, caid);
        } catch (EndEntityExistsException e) {
            userexists = true; // This is what we want
        }
        assertTrue("Trying to create the same user twice didn't throw EndEntityExistsException", userexists);

        // try to add user with non-existing CA-id
        String username2 = genRandomUserName();
        int fakecaid = -1;
        boolean thrown = false;
        try {
            endEntityManagementSession.addUser(admin, username2, pwd, "C=SE, O=AnaTom, CN=" + username2, null, null,
                    true, SecConst.EMPTY_ENDENTITYPROFILE, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                    EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, fakecaid);
            assertTrue(false);
        } catch (CADoesntExistsException e) {
            thrown = true;
        }
        assertTrue(thrown);

        log.trace("<addUser()");
    }

    /**
     * tests creation of new user testing behavior of empty passwords
     * 
     * @throws Exception error
     */
    @Test
    public void testAddUserWithEmptyPwd() throws Exception {
        // First make sure we have end entity profile limitations enabled
        final GlobalConfiguration gc = (GlobalConfiguration) globalConfSession
                .getCachedConfiguration(GlobalConfiguration.GLOBAL_CONFIGURATION_ID);
        final boolean eelimitation = gc.getEnableEndEntityProfileLimitations();
        gc.setEnableEndEntityProfileLimitations(true);
        globalConfSession.saveConfiguration(roleMgmgToken, gc);
        final String eeprofileName = "TESTADDUSER";
        try {
            // Add a new end entity profile, by default password is required and we should not be able to add a user with empty or null password.
            EndEntityProfile profile = new EndEntityProfile();
            profile.addField(DnComponents.COMMONNAME);
            profile.addField(DnComponents.COUNTRY);
            profile.setValue(EndEntityProfile.AVAILCAS, 0, Integer.toString(SecConst.ALLCAS));
            profile.setAllowMergeDnWebServices(true);
            // Profile will be removed in finally clause
            endEntityProfileSession.addEndEntityProfile(admin, eeprofileName, profile);
            int profileId = endEntityProfileSession.getEndEntityProfileId(eeprofileName);
            String thisusername = genRandomUserName();
            String email = thisusername + "@anatom.se";
            try {
                endEntityManagementSession.addUser(admin, thisusername, "", "C=SE, CN=" + thisusername, null, email,
                        false, profileId, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                        EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
                usernames.add(thisusername);
                fail("User " + thisusername + " was added to the database although it should not have been.");
            } catch (UserDoesntFullfillEndEntityProfile e) {
                assertTrue("Error message should be about password",
                        e.getMessage().contains("Password cannot be empty or null"));
            }
            try {
                endEntityManagementSession.addUser(admin, thisusername, null, "C=SE, CN=" + thisusername, null,
                        email, false, profileId, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                        EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
                usernames.add(thisusername);
                fail("User " + thisusername + " was added to the database although it should not have been.");
            } catch (UserDoesntFullfillEndEntityProfile e) {
                assertTrue("Error message should be about password",
                        e.getMessage().contains("Password cannot be empty or null"));
            }
            // Set required = false for password, then an empty password should be allowed
            profile.setRequired(EndEntityProfile.PASSWORD, 0, false);
            endEntityProfileSession.changeEndEntityProfile(admin, eeprofileName, profile);
            try {
                endEntityManagementSession.addUser(admin, thisusername, "", "C=SE, CN=" + thisusername, null, email,
                        false, profileId, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                        EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
                usernames.add(thisusername);
            } catch (UserDoesntFullfillEndEntityProfile e) {
                fail("User " + thisusername + " was not added to the database although it should have been.");
            }
            thisusername = genRandomUserName();
            email = thisusername + "@anatom.se";
            try {
                endEntityManagementSession.addUser(admin, thisusername, null, "C=SE, CN=" + thisusername, null,
                        email, false, profileId, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                        EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
                usernames.add(thisusername);
            } catch (UserDoesntFullfillEndEntityProfile e) {
                fail("User " + thisusername + " was not added to the database although it should have been.");
            }
        } finally {
            gc.setEnableEndEntityProfileLimitations(eelimitation);
            globalConfSession.saveConfiguration(roleMgmgToken, gc);
            endEntityProfileSession.removeEndEntityProfile(admin, eeprofileName);
        }
    }

    /**
     * tests creation of new user with unique serialnumber
     * 
     * @throws Exception error
     */
    @Test
    public void test02AddUserWithUniqueDNSerialnumberAndChange() throws Exception {
        log.trace(">test02AddUserWithUniqueDNSerialnumber()");

        // Make user that we know later...
        String thisusername = genRandomUserName();
        String email = thisusername + "@anatom.se";
        genRandomSerialnumber();
        endEntityManagementSession.addUser(admin, thisusername, pwd,
                "C=SE, CN=" + thisusername + ", SN=" + serialnumber, "rfc822name=" + email, email, false,
                SecConst.EMPTY_ENDENTITYPROFILE, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
        assertTrue("User " + thisusername + " was not added to the database.",
                endEntityManagementSession.existsUser(thisusername));
        usernames.add(thisusername);

        // Set the CA to enforce unique subjectDN serialnumber
        CAInfo cainfo = caSession.getCAInfo(admin, caid);
        boolean requiredUniqueSerialnumber = cainfo.isDoEnforceUniqueSubjectDNSerialnumber();
        cainfo.setDoEnforceUniqueSubjectDNSerialnumber(true);
        caAdminSession.editCA(admin, cainfo);

        // Add another user with the same serialnumber
        thisusername = genRandomUserName();
        try {
            endEntityManagementSession.addUser(admin, thisusername, pwd,
                    "C=SE, CN=" + thisusername + ", SN=" + serialnumber, "rfc822name=" + email, email, false,
                    SecConst.EMPTY_ENDENTITYPROFILE, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                    EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
            usernames.add(thisusername);
        } catch (EjbcaException e) {
            assertEquals(ErrorCode.SUBJECTDN_SERIALNUMBER_ALREADY_EXISTS, e.getErrorCode());
        }
        assertFalse("Succeeded in adding another end entity with the same serialnumber",
                endEntityManagementSession.existsUser(thisusername));

        // Set the CA to NOT enforcing unique subjectDN serialnumber
        cainfo.setDoEnforceUniqueSubjectDNSerialnumber(false);
        caAdminSession.editCA(admin, cainfo);
        endEntityManagementSession.addUser(admin, thisusername, pwd,
                "C=SE, CN=" + thisusername + ", SN=" + serialnumber, "rfc822name=" + email, email, false,
                SecConst.EMPTY_ENDENTITYPROFILE, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
        assertTrue(endEntityManagementSession.existsUser(thisusername));
        usernames.add(thisusername);

        // Set the CA back to its original settings of enforcing unique
        // subjectDN serialnumber.
        cainfo.setDoEnforceUniqueSubjectDNSerialnumber(requiredUniqueSerialnumber);
        caAdminSession.editCA(admin, cainfo);

        log.trace("<test02AddUserWithUniqueDNSerialnumber()");

        // Make user that we know later...
        String secondUserName;
        if (usernames.size() > 1) {
            secondUserName = (String) usernames.get(1);
        } else {
            secondUserName = username;
        }
        String secondEmail = secondUserName + username + "@anatomanatom.se";

        CAInfo secondCainfo = caSession.getCAInfo(admin, caid);
        boolean secondRequiredUniqueSerialnumber = secondCainfo.isDoEnforceUniqueSubjectDNSerialnumber();

        // Set the CA to enforce unique serialnumber
        cainfo.setDoEnforceUniqueSubjectDNSerialnumber(true);
        caAdminSession.editCA(admin, cainfo);
        try {
            EndEntityInformation user = new EndEntityInformation(secondUserName,
                    "C=SE, CN=" + secondUserName + ", SN=" + serialnumber, caid, "rfc822name=" + secondEmail,
                    secondEmail, new EndEntityType(EndEntityTypes.ENDUSER), SecConst.EMPTY_ENDENTITYPROFILE,
                    CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER, SecConst.TOKEN_SOFT_P12, 0, null);
            endEntityManagementSession.changeUser(admin, user, false);
        } catch (EjbcaException e) {
            assertEquals(ErrorCode.SUBJECTDN_SERIALNUMBER_ALREADY_EXISTS, e.getErrorCode());
        }
        assertTrue("The user '" + secondUserName + "' was changed even though the serialnumber already exists.",
                endEntityAccessSession.findUserByEmail(admin, secondEmail).size() == 0);

        // Set the CA to NOT enforcing unique subjectDN serialnumber
        cainfo.setDoEnforceUniqueSubjectDNSerialnumber(false);
        caAdminSession.editCA(admin, cainfo);
        EndEntityInformation user = new EndEntityInformation(secondUserName,
                "C=SE, CN=" + secondUserName + ", SN=" + serialnumber, caid, "rfc822name=" + secondEmail,
                secondEmail, new EndEntityType(EndEntityTypes.ENDUSER), SecConst.EMPTY_ENDENTITYPROFILE,
                CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER, SecConst.TOKEN_SOFT_P12, 0, null);
        endEntityManagementSession.changeUser(admin, user, false);
        assertTrue(
                "The user '" + thisusername + "' was not changed even though unique serialnumber is not enforced",
                endEntityAccessSession.findUserByEmail(admin, secondEmail).size() > 0);

        // Set the CA back to its original settings of enforcing unique
        // subjectDN serialnumber.
        cainfo.setDoEnforceUniqueSubjectDNSerialnumber(secondRequiredUniqueSerialnumber);
        caAdminSession.editCA(admin, secondCainfo);

        log.trace("<test03ChangeUserWithUniqueDNSerialnumber()");

    }

    /**
     * tests findUser and existsUser
     * 
     * @throws Exception error
     */
    @Test
    public void test03FindUser() throws Exception {
        addUser();

        log.trace(">test03FindUser()");
        EndEntityInformation data = endEntityAccessSession.findUser(admin, username);
        assertNotNull(data);
        assertEquals(username, data.getUsername());
        boolean exists = endEntityManagementSession.existsUser(username);
        assertTrue(exists);

        String notexistusername = genRandomUserName();
        exists = endEntityManagementSession.existsUser(notexistusername);
        assertFalse(exists);
        data = endEntityAccessSession.findUser(admin, notexistusername);
        assertNull(data);
        log.trace("<test03FindUser()");

    }

    /**
     * tests query function
     * 
     * @throws Exception error
     */
    @Test
    public void test03_1QueryUser() throws Exception {
        addUser();

        log.trace(">test03_1QueryUser()");
        Query query = new Query(Query.TYPE_USERQUERY);
        query.add(UserMatch.MATCH_WITH_USERNAME, BasicMatch.MATCH_TYPE_EQUALS, username);
        String caauthstring = null;
        String eeprofilestr = null;
        Collection<EndEntityInformation> col = endEntityManagementProxySession.query(admin, query, caauthstring,
                eeprofilestr, 0, AccessRulesConstants.VIEW_END_ENTITY);
        assertNotNull(col);
        assertEquals(1, col.size());
        log.trace("<test03_1QueryUser()");

    }

    /**
     * tests changeUser
     * 
     * @throws Exception error
     */
    @Test
    public void test04ChangeUser() throws Exception {
        addUser();

        log.trace(">test04ChangeUser()");
        EndEntityInformation data = endEntityAccessSession.findUser(admin, username);
        assertNotNull(data);
        assertEquals(username, data.getUsername());
        assertNull(data.getCardNumber());
        assertEquals(pwd, data.getPassword()); // Note that changing the user
                                               // sets the password to null!!!
        assertEquals("CN=" + username + ",O=AnaTom,C=SE", data.getDN());
        String email = username + "@anatom.se";
        assertEquals("rfc822name=" + email, data.getSubjectAltName());
        data.setCardNumber("123456");
        data.setPassword("bar123");
        data.setDN("C=SE, O=AnaTom1, CN=" + username);
        data.setSubjectAltName("dnsName=a.b.se, rfc822name=" + email);

        endEntityManagementSession.changeUser(admin, data, true);
        EndEntityInformation data1 = endEntityAccessSession.findUser(admin, username);
        assertNotNull(data1);
        assertEquals(username, data1.getUsername());
        assertEquals("123456", data1.getCardNumber());
        assertEquals("bar123", data1.getPassword());
        assertEquals("CN=" + username + ",O=AnaTom1,C=SE", data1.getDN());
        assertEquals("dnsName=a.b.se, rfc822name=" + email, data1.getSubjectAltName());
        log.trace("<test04ChangeUser()");
    }

    @Test
    public void test05RevokeCert() throws Exception {
        addUser();

        KeyPair keypair = KeyTools.genKeys("512", "RSA");

        EndEntityInformation data1 = endEntityAccessSession.findUser(admin, username);
        assertNotNull(data1);
        data1.setPassword("foo123");
        endEntityManagementSession.changeUser(admin, data1, true);

        Certificate cert = signSession.createCertificate(admin, username, "foo123",
                new PublicKeyWrapper(keypair.getPublic()));
        CertificateStatus status = certificateStoreSession.getStatus(CertTools.getIssuerDN(cert),
                CertTools.getSerialNumber(cert));
        assertEquals(RevokedCertInfo.NOT_REVOKED, status.revocationReason);
        // Revoke the certificate, put on hold
        endEntityManagementSession.revokeCert(admin, CertTools.getSerialNumber(cert), CertTools.getIssuerDN(cert),
                RevokedCertInfo.REVOCATION_REASON_CERTIFICATEHOLD);
        status = certificateStoreSession.getStatus(CertTools.getIssuerDN(cert), CertTools.getSerialNumber(cert));
        assertEquals(RevokedCertInfo.REVOCATION_REASON_CERTIFICATEHOLD, status.revocationReason);

        // Unrevoke the certificate
        endEntityManagementSession.revokeCert(admin, CertTools.getSerialNumber(cert), CertTools.getIssuerDN(cert),
                RevokedCertInfo.NOT_REVOKED);
        status = certificateStoreSession.getStatus(CertTools.getIssuerDN(cert), CertTools.getSerialNumber(cert));
        assertEquals(RevokedCertInfo.NOT_REVOKED, status.revocationReason);

        // Revoke again certificate
        endEntityManagementSession.revokeCert(admin, CertTools.getSerialNumber(cert), CertTools.getIssuerDN(cert),
                RevokedCertInfo.REVOCATION_REASON_CERTIFICATEHOLD);
        status = certificateStoreSession.getStatus(CertTools.getIssuerDN(cert), CertTools.getSerialNumber(cert));
        assertEquals(RevokedCertInfo.REVOCATION_REASON_CERTIFICATEHOLD, status.revocationReason);

        // Unrevoke the certificate, but with different code
        endEntityManagementSession.revokeCert(admin, CertTools.getSerialNumber(cert), CertTools.getIssuerDN(cert),
                RevokedCertInfo.REVOCATION_REASON_REMOVEFROMCRL);
        status = certificateStoreSession.getStatus(CertTools.getIssuerDN(cert), CertTools.getSerialNumber(cert));
        assertEquals(RevokedCertInfo.NOT_REVOKED, status.revocationReason);

        // Revoke again certificate permanently
        endEntityManagementSession.revokeCert(admin, CertTools.getSerialNumber(cert), CertTools.getIssuerDN(cert),
                RevokedCertInfo.REVOCATION_REASON_CACOMPROMISE);
        status = certificateStoreSession.getStatus(CertTools.getIssuerDN(cert), CertTools.getSerialNumber(cert));
        assertEquals(RevokedCertInfo.REVOCATION_REASON_CACOMPROMISE, status.revocationReason);

        // Unrevoke the certificate, should not work
        try {
            endEntityManagementSession.revokeCert(admin, CertTools.getSerialNumber(cert),
                    CertTools.getIssuerDN(cert), RevokedCertInfo.REVOCATION_REASON_REMOVEFROMCRL);
            assertTrue(false); // should not reach this
        } catch (AlreadyRevokedException e) {
        }
        status = certificateStoreSession.getStatus(CertTools.getIssuerDN(cert), CertTools.getSerialNumber(cert));
        assertEquals(RevokedCertInfo.REVOCATION_REASON_CACOMPROMISE, status.revocationReason);
    }

    /**
     * tests deletion of user, and user that does not exist
     * 
     * @throws Exception error
     */
    @Test
    public void test06DeleteUser() throws Exception {
        addUser();

        log.trace(">test06DeleteUser()");
        endEntityManagementSession.deleteUser(admin, username);
        log.debug("deleted user: " + username);
        // Delete the the same user again
        boolean removed = false;
        try {
            endEntityManagementSession.deleteUser(admin, username);
        } catch (NotFoundException e) {
            removed = true;
        }
        assertTrue("User does not exist does not throw NotFoundException", removed);
        log.trace("<test06DeleteUser()");
    }

    /**
     * Test adding a user, merging the DN request in the End Entity with the default DN fields in the end entity profile.
     * 
     * @throws Exception error
     */
    @Test
    public void test07MergeWithWS() throws Exception {
        // First make sure we have end entity profile limitations enabled
        final GlobalConfiguration gc = (GlobalConfiguration) globalConfSession
                .getCachedConfiguration(GlobalConfiguration.GLOBAL_CONFIGURATION_ID);
        final boolean eelimitation = gc.getEnableEndEntityProfileLimitations();
        gc.setEnableEndEntityProfileLimitations(true);
        globalConfSession.saveConfiguration(roleMgmgToken, gc);
        try {
            // An end entity profile that has CN,DNEMAIL,OU=FooOrgUnit,O,C
            EndEntityProfile profile = new EndEntityProfile();
            profile.addField(DnComponents.COMMONNAME);
            profile.addField(DnComponents.DNEMAILADDRESS);
            profile.addField(DnComponents.ORGANIZATIONALUNIT);
            profile.setUse(DnComponents.ORGANIZATIONALUNIT, 0, true);
            profile.setValue(DnComponents.ORGANIZATIONALUNIT, 0, "FooOrgUnit");
            // The merge only handles 1 default value for each DN component, i.e. one OU one O etc. You can not have two default OUs to merge.
            // You can not even define two OUs to be used in the profile, it will be merged with the value of the first duplicated, i.e. FooOrgUnit twice
            //profile.addField(DnComponents.ORGANIZATIONALUNIT);
            profile.addField(DnComponents.ORGANIZATION);
            profile.addField(DnComponents.COUNTRY);
            profile.setValue(EndEntityProfile.AVAILCAS, 0, Integer.toString(SecConst.ALLCAS));
            profile.setAllowMergeDnWebServices(true);

            endEntityProfileSession.addEndEntityProfile(admin, "TESTMERGEWITHWS", profile);
            int profileId = endEntityProfileSession.getEndEntityProfileId("TESTMERGEWITHWS");

            // An end entity with CN=username,O=AnaTom,C=SE
            // Merged with the EE profile default it should become CN=username,OU=FooOrgUnit,OU=BarOrgUnit,O=AnaTom,C=SE
            EndEntityInformation addUser = new EndEntityInformation(username, "C=SE, O=AnaTom, CN=" + username,
                    caid, null, null, EndEntityConstants.STATUS_NEW, new EndEntityType(EndEntityTypes.ENDUSER),
                    profileId, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER, new Date(), new Date(),
                    SecConst.TOKEN_SOFT_P12, 0, null);
            addUser.setPassword("foo123");
            endEntityManagementSession.addUserFromWS(admin, addUser, false);
            EndEntityInformation data = endEntityAccessSession.findUser(admin, username);
            assertEquals("CN=" + username + ",OU=FooOrgUnit,O=AnaTom,C=SE", data.getDN());

            addUser.setDN("EMAIL=foo@bar.com, OU=hoho");
            // Changing the user feeding in EMAIL=foo@bar.com,OU=hohoit will actuallybe merged with the existing end entity user DN into
            // EMAIL:foo@bar.com,CN=username,OU=hoho,O=AnaTom,C=SE
            // Since there is an order EMAIL and OU gets in their proper order. Since we pass in OU=hoho, it override the profile default OU=FooOrgUnit
            endEntityManagementSession.changeUser(admin, addUser, false, true);
            data = endEntityAccessSession.findUser(admin, username);
            // E=foo@bar.com,CN=430208,OU=FooOrgUnit,O=hoho,C=NO
            assertEquals("E=foo@bar.com,CN=" + username + ",OU=hoho,O=AnaTom,C=SE", data.getDN());

            //Skip this test on Community
            if (DnComponents.enterpriseMappingsExist()) {
                endEntityManagementSession.deleteUser(admin, username);
                // A real use case. Add EV SSL items as default values and merge those into the End Entity
                profile.addField(DnComponents.JURISDICTIONCOUNTRY);
                profile.setUse(DnComponents.JURISDICTIONCOUNTRY, 0, true);
                profile.setValue(DnComponents.JURISDICTIONCOUNTRY, 0, "NO");
                profile.addField(DnComponents.JURISDICTIONSTATE);
                profile.setUse(DnComponents.JURISDICTIONSTATE, 0, true);
                profile.setValue(DnComponents.JURISDICTIONSTATE, 0, "California");
                profile.addField(DnComponents.JURISDICTIONLOCALITY);
                profile.setUse(DnComponents.JURISDICTIONLOCALITY, 0, true);
                profile.setValue(DnComponents.JURISDICTIONLOCALITY, 0, "Stockholm");
                endEntityProfileSession.changeEndEntityProfile(admin, "TESTMERGEWITHWS", profile);
                final String subjectDN = "CN=foo subject,O=Bar";
                addUser = new EndEntityInformation(username, subjectDN, caid,
                        "dnsName=foo.bar.com,dnsName=foo1.bar.com,rfc822Name=foo@bar.com", null,
                        EndEntityConstants.STATUS_NEW, new EndEntityType(EndEntityTypes.ENDUSER), profileId,
                        CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER, new Date(), new Date(),
                        SecConst.TOKEN_SOFT_P12, 0, null);
                addUser.setPassword("foo123");
                try {
                    endEntityManagementSession.addUserFromWS(admin, addUser, false);
                    fail("Should not be allowed since we have altNames that are not allowed in the profile.");
                } catch (UserDoesntFullfillEndEntityProfile e) {
                } // NOPMD
                  // Add the required end entity profile fields
                profile.addField(DnComponents.DNSNAME);
                profile.addField(DnComponents.DNSNAME);
                profile.addField(DnComponents.DNSNAME);
                profile.addField(DnComponents.RFC822NAME);
                endEntityProfileSession.changeEndEntityProfile(admin, "TESTMERGEWITHWS", profile);
                endEntityManagementSession.addUserFromWS(admin, addUser, false);
                data = endEntityAccessSession.findUser(admin, username);
                assertEquals(
                        "JurisdictionCountry=NO,JurisdictionState=California,JurisdictionLocality=Stockholm,CN=foo subject,OU=FooOrgUnit,O=Bar",
                        data.getDN());
                // Make sure altNames are not stripped, they shall actually be merged as well
                // This returns slightly different between JDK 7 and JDK 8
                String[] javaVersionElements = System.getProperty("java.version").split("\\.");
                int major = Integer.parseInt(javaVersionElements[1]);
                if (major > 7) {
                    assertEquals("rfc822Name=foo@bar.com,dnsName=foo.bar.com,dnsName=foo1.bar.com",
                            data.getSubjectAltName());
                } else {
                    assertEquals("dnsName=foo.bar.com,dnsName=foo1.bar.com,rfc822Name=foo@bar.com",
                            data.getSubjectAltName());
                }
                // Try with some altName value to merge
                endEntityManagementSession.deleteUser(admin, username);
                profile.setValue(DnComponents.DNSNAME, 0, "server.bad.com");
                profile.setValue(DnComponents.DNSNAME, 1, "server.superbad.com");
                // The merge only handles consecutive default value for each DN component, i.e. defaultname for 0 and 1, not for 0 and 2
                // The resulting altName will have 4 dnsNames, so we must allow this amount
                profile.addField(DnComponents.DNSNAME);
                endEntityProfileSession.changeEndEntityProfile(admin, "TESTMERGEWITHWS", profile);
                endEntityManagementSession.addUserFromWS(admin, addUser, false);
                data = endEntityAccessSession.findUser(admin, username);
                assertEquals(
                        "JurisdictionCountry=NO,JurisdictionState=California,JurisdictionLocality=Stockholm,CN=foo subject,OU=FooOrgUnit,O=Bar",
                        data.getDN());
                // Make sure altNames are not stripped, they shall actually be merged as well. Ok cases are different but that does not matter.
                // This returns slightly different between JDK 7 and JDK 8
                if (major > 7) {
                    assertEquals(
                            "DNSNAME=server.superbad.com,DNSNAME=server.bad.com,rfc822Name=foo@bar.com,dnsName=foo.bar.com,dnsName=foo1.bar.com",
                            data.getSubjectAltName());
                } else {
                    assertEquals(
                            "DNSNAME=server.superbad.com,DNSNAME=server.bad.com,dnsName=foo.bar.com,dnsName=foo1.bar.com,rfc822Name=foo@bar.com",
                            data.getSubjectAltName());
                }
            } else {
                log.debug("Skipped test related to Enterprise DN properties.");
            }
        } finally {
            gc.setEnableEndEntityProfileLimitations(eelimitation);
            globalConfSession.saveConfiguration(roleMgmgToken, gc);
        }
    }

    /** Tests that CA and End Entity profile authorization methods in EndEntityManagementSessionBean works.
     * When called with a user that does not have access to the CA (that you try to add a user for), or the
     * end entity profile specified for the user, an AuthorizationDeniedException should be thrown.
     * For end entity profile authorization to be effective, this must be configured in global configuration.
     */
    @Test
    public void test08Authorization() throws Exception {

        Set<Principal> principals = new HashSet<Principal>();
        principals.add(new X500Principal("C=SE,O=Test,CN=Test EndEntityManagementSessionNoAuth"));

        TestX509CertificateAuthenticationToken adminTokenNoAuth = (TestX509CertificateAuthenticationToken) simpleAuthenticationProvider
                .authenticate(new AuthenticationSubject(principals, null));
        final X509Certificate adminCert = adminTokenNoAuth.getCertificate();

        final String testRole = "EndEntityManagementSessionTestAuthRole";
        GlobalConfiguration gc = (GlobalConfiguration) globalConfSession
                .getCachedConfiguration(GlobalConfiguration.GLOBAL_CONFIGURATION_ID);
        boolean eelimitation = gc.getEnableEndEntityProfileLimitations();

        final String authUsername = genRandomUserName();
        String email = authUsername + "@anatom.se";
        EndEntityInformation userdata = new EndEntityInformation(authUsername, "C=SE, O=AnaTom, CN=" + username,
                caid, null, email, new EndEntityType(EndEntityTypes.ENDUSER), SecConst.EMPTY_ENDENTITYPROFILE,
                CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER, SecConst.TOKEN_SOFT_P12, 0, null);
        userdata.setPassword("foo123");
        // Test CA authorization
        usernames.add(authUsername + "_renamed");
        try {
            try {
                endEntityManagementSession.addUser(adminTokenNoAuth, userdata, false);
                fail("should throw");
            } catch (AuthorizationDeniedException e) {
                assertTrue("Wrong auth denied message: " + e.getMessage(),
                        StringUtils.startsWith(e.getMessage(), "Administrator not authorized to CA"));
            }
            try {
                endEntityManagementSession.changeUser(adminTokenNoAuth, userdata, true);
                fail("should throw");
            } catch (AuthorizationDeniedException e) {
                assertTrue("Wrong auth denied message: " + e.getMessage(),
                        StringUtils.startsWith(e.getMessage(), "Administrator not authorized to CA"));
            }
            endEntityManagementSession.addUser(admin, userdata, false);
            try {
                boolean result = endEntityManagementSession.renameEndEntity(adminTokenNoAuth, authUsername,
                        authUsername + "_renamed");
                log.debug("Rename result: " + result);
                fail("should throw");
            } catch (AuthorizationDeniedException e) {
                assertTrue("Wrong auth denied message: " + e.getMessage(),
                        StringUtils.startsWith(e.getMessage(), "Administrator not authorized to CA"));
            }
            try {
                endEntityManagementSession.deleteUser(adminTokenNoAuth, authUsername);
                fail("should throw");
            } catch (AuthorizationDeniedException e) {
                assertTrue("Wrong auth denied message: " + e.getMessage(),
                        StringUtils.startsWith(e.getMessage(), "Administrator not authorized to CA"));
            }
            // Now add the administrator to a role that has access to /ca/* but not ee profiles
            RoleData role = roleAccessSession.findRole(testRole);
            if (role == null) {
                role = roleManagementSession.create(roleMgmgToken, testRole);
            }
            final List<AccessRuleData> accessRules = new ArrayList<AccessRuleData>();
            accessRules.add(new AccessRuleData(testRole, StandardRules.CAACCESSBASE.resource(),
                    AccessRuleState.RULE_ACCEPT, true));
            role = roleManagementSession.addAccessRulesToRole(roleMgmgToken, role, accessRules);

            final List<AccessUserAspectData> accessUsers = new ArrayList<AccessUserAspectData>();
            accessUsers.add(new AccessUserAspectData(testRole, CertTools.getIssuerDN(adminCert).hashCode(),
                    X500PrincipalAccessMatchValue.WITH_COMMONNAME, AccessMatchType.TYPE_EQUALCASE,
                    CertTools.getPartFromDN(CertTools.getSubjectDN(adminCert), "CN")));
            roleManagementSession.addSubjectsToRole(roleMgmgToken, role, accessUsers);
            accessControlSession.forceCacheExpire();
            // We must enforce end entity profile limitations for this, with false it should be ok now
            gc.setEnableEndEntityProfileLimitations(false);
            globalConfSession.saveConfiguration(roleMgmgToken, gc);
            // Do the same test, now it should work since we are authorized to CA and we don't enforce EE profile authorization
            endEntityManagementSession.changeUser(adminTokenNoAuth, userdata, false);
            endEntityManagementSession.renameEndEntity(adminTokenNoAuth, authUsername, authUsername + "_renamed");
            endEntityManagementSession.renameEndEntity(adminTokenNoAuth, authUsername + "_renamed", authUsername);
            // Enforce EE profile limitations
            gc.setEnableEndEntityProfileLimitations(true);
            globalConfSession.saveConfiguration(roleMgmgToken, gc);
            // Do the same test, now we should get auth denied on EE profiles instead
            try {
                endEntityManagementSession.changeUser(adminTokenNoAuth, userdata, false);
                fail("should throw");
            } catch (AuthorizationDeniedException e) {
                assertTrue("Wrong auth denied message: " + e.getMessage(), StringUtils.startsWith(e.getMessage(),
                        "Administrator not authorized to end entity profile"));
            }
            try {
                endEntityManagementSession.renameEndEntity(adminTokenNoAuth, authUsername,
                        authUsername + "_renamed");
                fail("should throw");
            } catch (AuthorizationDeniedException e) {
                assertTrue("Wrong auth denied message: " + e.getMessage(), StringUtils.startsWith(e.getMessage(),
                        "Administrator not authorized to end entity profile"));
            }
        } finally {
            gc.setEnableEndEntityProfileLimitations(eelimitation);
            globalConfSession.saveConfiguration(roleMgmgToken, gc);
            try {
                endEntityManagementSession.deleteUser(admin, authUsername);
            } catch (Exception e) { // NOPMD
                log.info("Error in finally: ", e);
            }
            RoleData role = roleAccessSession.findRole(testRole);
            if (role != null) {
                roleManagementSession.remove(roleMgmgToken, role);
            }
        }
    }

    /** Test rename of an end entity. */
    @Test
    public void testRenameEndEntity() throws Exception {
        final String username1 = "testRenameEndEntityA";
        final String username2 = "testRenameEndEntityB";
        final String username3 = "testRenameEndEntityC";
        endEntityManagementSession.addUser(admin, username1, pwd, "C=SE, O=PrimeKey, CN=" + username1, null, null,
                true, SecConst.EMPTY_ENDENTITYPROFILE, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
        endEntityManagementSession.addUser(admin, username2, pwd, "C=SE, O=PrimeKey, CN=" + username2, null, null,
                true, SecConst.EMPTY_ENDENTITYPROFILE, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
        usernames.add(username1);
        usernames.add(username2);
        usernames.add(username3);
        try {
            endEntityManagementSession.renameEndEntity(admin, username1, username2);
            fail("Was able to rename an end entity using an already occupied username.");
        } catch (EndEntityExistsException e) {
            // Expected
            final EndEntityInformation endEntityInformation = endEntityAccessSession.findUser(admin, username1);
            assertNotNull("End entity should still exist after a failed rename.", endEntityInformation);
        }
        endEntityManagementSession.renameEndEntity(admin, username1, username3);
        final EndEntityInformation endEntityInformation1 = endEntityAccessSession.findUser(admin, username1);
        assertNull("Renamed user should no longer exist under old username.", endEntityInformation1);
        final EndEntityInformation endEntityInformation2 = endEntityAccessSession.findUser(admin, username3);
        assertNotNull("End entity should still exist after a failed rename to its username.",
                endEntityInformation2);
        final EndEntityInformation endEntityInformation3 = endEntityAccessSession.findUser(admin, username3);
        assertNotNull("Renamed user should exist under new username.", endEntityInformation3);
    }

    /** Test rename of an end entity with issued certificates and publishing queue. */
    @Test
    public void testRenameEndEntityWithCerts() throws Exception {
        final String username1 = "testRenameEndEntityWithCertsA";
        final String username2 = "testRenameEndEntityWithCertsB";
        final String username3 = "testRenameEndEntityWithCertsC";
        usernames.add(username1);
        usernames.add(username2);
        usernames.add(username3);
        // Add users
        endEntityManagementSession.addUser(admin, username1, pwd, "C=SE, O=PrimeKey, CN=" + username1, null, null,
                true, SecConst.EMPTY_ENDENTITYPROFILE, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
        endEntityManagementSession.addUser(admin, username2, pwd, "C=SE, O=PrimeKey, CN=" + username2, null, null,
                true, SecConst.EMPTY_ENDENTITYPROFILE, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
        // Issue certificates
        final KeyPair keyPair = KeyTools.genKeys("512", AlgorithmConstants.KEYALGORITHM_RSA);
        String fingerprint = null;
        try {
            final X509Certificate x509Certificate = (X509Certificate) signSession.createCertificate(admin,
                    username1, pwd, new PublicKeyWrapper(keyPair.getPublic()));
            assertNotNull("Failed to issue certificate", x509Certificate);
            fingerprint = CertTools.getFingerprintAsString(x509Certificate);
            // Create publisher queue data
            final PublisherQueueVolatileInformation publisherQueueInfo1 = new PublisherQueueVolatileInformation();
            publisherQueueInfo1.setUsername(username1);
            publisherQueueSession.addQueueData(4217, PublisherConst.PUBLISH_TYPE_CERT, fingerprint,
                    publisherQueueInfo1, PublisherConst.STATUS_PENDING);
            // Try to rename a user to an existing username
            try {
                endEntityManagementSession.renameEndEntity(admin, username1, username2);
                fail("Was able to rename an end entity using an already occupied username.");
            } catch (EndEntityExistsException e) {
                // Expected
                final EndEntityInformation endEntityInformation = endEntityAccessSession.findUser(admin, username1);
                assertNotNull("End entity should still exist after a failed rename.", endEntityInformation);
                assertEquals("Publisher queue data should have retained username after failed rename", username1,
                        publisherQueueSession.getEntriesByFingerprint(fingerprint).iterator().next()
                                .getVolatileData().getUsername());
                assertEquals("Certificate data should have retained username after failed rename", username1,
                        certificateStoreSession.getCertificateInfo(fingerprint).getUsername());
            }
            endEntityManagementSession.renameEndEntity(admin, username1, username3);
            final EndEntityInformation endEntityInformation1 = endEntityAccessSession.findUser(admin, username1);
            assertNull("Renamed user should no longer exist under old username.", endEntityInformation1);
            final EndEntityInformation endEntityInformation2 = endEntityAccessSession.findUser(admin, username3);
            assertNotNull("End entity should still exist after a failed rename to its username.",
                    endEntityInformation2);
            final EndEntityInformation endEntityInformation3 = endEntityAccessSession.findUser(admin, username3);
            assertNotNull("Renamed user should exist under new username.", endEntityInformation3);
            assertEquals("Publisher queue data should use new username.", username3, publisherQueueSession
                    .getEntriesByFingerprint(fingerprint).iterator().next().getVolatileData().getUsername());
            assertEquals("Certificate data should use new username.", username3,
                    certificateStoreSession.getCertificateInfo(fingerprint).getUsername());
        } finally {
            if (fingerprint != null) {
                internalCertStoreSession.removeCertificate(fingerprint);
            }
        }
    }

    /** Test revocation of an end entity. */
    @Test
    public void testRevokeEndEntity() throws Exception {
        final String TEST_NAME = Thread.currentThread().getStackTrace()[1].getMethodName();
        final String USERNAME = TEST_NAME + "A";
        endEntityManagementSession.addUser(admin, USERNAME, pwd, "C=SE, O=PrimeKey, CN=" + USERNAME, null, null,
                true, SecConst.EMPTY_ENDENTITYPROFILE, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_P12, 0, caid);
        usernames.add(USERNAME);
        final long now = System.currentTimeMillis();
        final Date date10sAgo = new Date(now - 10000L);
        final Date date2sAgo = new Date(now - 2000L);
        final Date date1hFromNow = new Date(now + 3600000L);
        final KeyPair keyPair = KeyTools.genKeys("512", AlgorithmConstants.KEYALGORITHM_RSA);
        // Generate self signed certificates
        // This is really a bit strange with no "real" certificates. We can however revoke them anyhow even though they don't belong to a CA in the system
        // This may be useful in order to be able to create "dummy" certificates for specific compromised cases where you want to answer specifically for strange things.
        final X509Certificate x509Certificate1 = CertTools.genSelfCertForPurpose("CN=" + USERNAME, date10sAgo,
                date1hFromNow, null, keyPair.getPrivate(), keyPair.getPublic(),
                AlgorithmConstants.SIGALG_SHA256_WITH_RSA, false, X509KeyUsage.keyCertSign + X509KeyUsage.cRLSign,
                null, null, BouncyCastleProvider.PROVIDER_NAME, true, null);
        final String fingerprint1 = CertTools.getFingerprintAsString(x509Certificate1);
        final X509Certificate x509Certificate2 = CertTools.genSelfCertForPurpose("CN=" + USERNAME, date10sAgo,
                date2sAgo, null, keyPair.getPrivate(), keyPair.getPublic(),
                AlgorithmConstants.SIGALG_SHA256_WITH_RSA, false, X509KeyUsage.keyCertSign + X509KeyUsage.cRLSign,
                null, null, BouncyCastleProvider.PROVIDER_NAME, true, null);
        final String fingerprint2 = CertTools.getFingerprintAsString(x509Certificate2);
        final X509Certificate x509Certificate3 = CertTools.genSelfCertForPurpose("CN=" + USERNAME, date10sAgo,
                date1hFromNow, null, keyPair.getPrivate(), keyPair.getPublic(),
                AlgorithmConstants.SIGALG_SHA256_WITH_RSA, false, X509KeyUsage.keyCertSign + X509KeyUsage.cRLSign,
                null, null, BouncyCastleProvider.PROVIDER_NAME, true, null);
        final String fingerprint3 = CertTools.getFingerprintAsString(x509Certificate3);
        final X509Certificate x509Certificate4 = CertTools.genSelfCertForPurpose("CN=" + USERNAME, date10sAgo,
                date1hFromNow, null, keyPair.getPrivate(), keyPair.getPublic(),
                AlgorithmConstants.SIGALG_SHA256_WITH_RSA, false, X509KeyUsage.keyCertSign + X509KeyUsage.cRLSign,
                null, null, BouncyCastleProvider.PROVIDER_NAME, true, null);
        final String fingerprint4 = CertTools.getFingerprintAsString(x509Certificate4);
        final X509Certificate x509Certificate5 = CertTools.genSelfCertForPurpose("CN=" + USERNAME, date10sAgo,
                date2sAgo, null, keyPair.getPrivate(), keyPair.getPublic(),
                AlgorithmConstants.SIGALG_SHA256_WITH_RSA, false, X509KeyUsage.keyCertSign + X509KeyUsage.cRLSign,
                null, null, BouncyCastleProvider.PROVIDER_NAME, true, null);
        final String fingerprint5 = CertTools.getFingerprintAsString(x509Certificate5);
        final X509Certificate x509Certificate6 = CertTools.genSelfCertForPurpose("CN=" + USERNAME, date10sAgo,
                date1hFromNow, null, keyPair.getPrivate(), keyPair.getPublic(),
                AlgorithmConstants.SIGALG_SHA256_WITH_RSA, false, X509KeyUsage.keyCertSign + X509KeyUsage.cRLSign,
                null, null, BouncyCastleProvider.PROVIDER_NAME, true, null);
        final String fingerprint6 = CertTools.getFingerprintAsString(x509Certificate6);
        try {
            // Persists self signed certificates
            internalCertStoreSession.storeCertificateNoAuth(admin, x509Certificate1, USERNAME, fingerprint1,
                    CertificateConstants.CERT_ACTIVE, CertificateConstants.CERTTYPE_ENDENTITY,
                    CertificateProfileConstants.CERTPROFILE_NO_PROFILE, EndEntityInformation.NO_ENDENTITYPROFILE,
                    null, now);
            internalCertStoreSession.storeCertificateNoAuth(admin, x509Certificate2, USERNAME, fingerprint2,
                    CertificateConstants.CERT_ARCHIVED, CertificateConstants.CERTTYPE_ENDENTITY,
                    CertificateProfileConstants.CERTPROFILE_NO_PROFILE, EndEntityInformation.NO_ENDENTITYPROFILE,
                    null, now);
            internalCertStoreSession.storeCertificateNoAuth(admin, x509Certificate3, USERNAME, fingerprint3,
                    CertificateConstants.CERT_NOTIFIEDABOUTEXPIRATION, CertificateConstants.CERTTYPE_ENDENTITY,
                    CertificateProfileConstants.CERTPROFILE_NO_PROFILE, EndEntityInformation.NO_ENDENTITYPROFILE,
                    null, now);
            internalCertStoreSession.storeCertificateNoAuth(admin, x509Certificate4, USERNAME, fingerprint4,
                    CertificateConstants.CERT_REVOKED, CertificateConstants.CERTTYPE_ENDENTITY,
                    CertificateProfileConstants.CERTPROFILE_NO_PROFILE, EndEntityInformation.NO_ENDENTITYPROFILE,
                    null, now);
            // A certificate that has expired, but status has not been changed to ARCHIVED by the CRL worker
            internalCertStoreSession.storeCertificateNoAuth(admin, x509Certificate5, USERNAME, fingerprint5,
                    CertificateConstants.CERT_ACTIVE, CertificateConstants.CERTTYPE_ENDENTITY,
                    CertificateProfileConstants.CERTPROFILE_NO_PROFILE, EndEntityInformation.NO_ENDENTITYPROFILE,
                    null, now);
            // Artificial test vector where certificate has not expired, but the status is still set to archived
            internalCertStoreSession.storeCertificateNoAuth(admin, x509Certificate6, USERNAME, fingerprint5,
                    CertificateConstants.CERT_ARCHIVED, CertificateConstants.CERTTYPE_ENDENTITY,
                    CertificateProfileConstants.CERTPROFILE_NO_PROFILE, EndEntityInformation.NO_ENDENTITYPROFILE,
                    null, now);
            // Revoke user
            endEntityManagementSession.revokeUser(admin, USERNAME, RevokedCertInfo.REVOCATION_REASON_UNSPECIFIED);
            // Get all certificate except the revoked ones
            final List<CertificateDataWrapper> cdws = certificateStoreSession.getCertificateDataByUsername(USERNAME,
                    false, Arrays.asList(CertificateConstants.CERT_REVOKED));
            assertEquals("Expected that revokeUser call would not touch ARCHIVED or expired certificates.", 3,
                    cdws.size());
            final List<String> remainingFingerprints = Arrays.asList(
                    cdws.get(0).getCertificateData().getFingerprint(),
                    cdws.get(1).getCertificateData().getFingerprint(),
                    cdws.get(2).getCertificateData().getFingerprint());
            assertTrue("Expected archived and expired certificate to not be revoked.",
                    remainingFingerprints.contains(fingerprint2));
            assertTrue("Expected active and expired certificate to not be revoked.",
                    remainingFingerprints.contains(fingerprint5));
            assertTrue("Expected archived and non-expired certificate to not be revoked.",
                    remainingFingerprints.contains(fingerprint6));
        } finally {
            // Clean up
            final List<CertificateDataWrapper> cdws = certificateStoreSession.getCertificateDataByUsername(USERNAME,
                    false, null);
            for (final CertificateDataWrapper cdw : cdws) {
                internalCertStoreSession.removeCertificate(cdw.getCertificateData().getFingerprint());
            }
        }
    }
}