Java tutorial
/************************************************************************* * * * 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.ui.web.admin.rainterface; import java.beans.ExceptionListener; import java.beans.XMLDecoder; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.net.URLDecoder; import java.security.cert.Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.ejb.FinderException; import javax.ejb.RemoveException; import javax.servlet.http.HttpServletRequest; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.cesecore.authentication.tokens.AlwaysAllowLocalAuthenticationToken; import org.cesecore.authentication.tokens.AuthenticationToken; import org.cesecore.authentication.tokens.UsernamePrincipal; import org.cesecore.authorization.AuthorizationDeniedException; import org.cesecore.authorization.control.AccessControlSessionLocal; import org.cesecore.authorization.control.StandardRules; import org.cesecore.certificates.ca.CADoesntExistsException; import org.cesecore.certificates.ca.CaSessionLocal; import org.cesecore.certificates.certificate.CertificateStatus; import org.cesecore.certificates.certificate.CertificateStoreSession; import org.cesecore.certificates.certificateprofile.CertificateProfileConstants; import org.cesecore.certificates.certificateprofile.CertificateProfileSession; import org.cesecore.certificates.crl.RevokedCertInfo; import org.cesecore.certificates.endentity.EndEntityConstants; import org.cesecore.certificates.endentity.EndEntityInformation; import org.cesecore.util.CertTools; import org.cesecore.util.FileTools; import org.cesecore.util.StringTools; import org.ejbca.config.WebConfiguration; import org.ejbca.core.EjbcaException; import org.ejbca.core.ejb.authorization.ComplexAccessControlSessionLocal; import org.ejbca.core.ejb.hardtoken.HardTokenSession; import org.ejbca.core.ejb.keyrecovery.KeyRecoverySession; import org.ejbca.core.ejb.ra.EndEntityAccessSessionLocal; import org.ejbca.core.ejb.ra.EndEntityExistsException; import org.ejbca.core.ejb.ra.EndEntityManagementSessionLocal; import org.ejbca.core.ejb.ra.raadmin.EndEntityProfileSessionLocal; import org.ejbca.core.ejb.ra.userdatasource.UserDataSourceSession; import org.ejbca.core.model.InternalEjbcaResources; import org.ejbca.core.model.SecConst; import org.ejbca.core.model.approval.ApprovalException; import org.ejbca.core.model.approval.WaitingForApprovalException; import org.ejbca.core.model.authorization.AccessRulesConstants; import org.ejbca.core.model.ra.AlreadyRevokedException; import org.ejbca.core.model.ra.EndEntityManagementConstants; import org.ejbca.core.model.ra.NotFoundException; import org.ejbca.core.model.ra.raadmin.EndEntityProfile; import org.ejbca.core.model.ra.raadmin.EndEntityProfileExistsException; import org.ejbca.core.model.ra.raadmin.EndEntityProfileNotFoundException; import org.ejbca.core.model.ra.raadmin.UserDoesntFullfillEndEntityProfile; import org.ejbca.core.model.util.EjbLocalHelper; import org.ejbca.ui.web.CertificateView; import org.ejbca.ui.web.RevokedInfoView; import org.ejbca.ui.web.admin.configuration.EjbcaWebBean; import org.ejbca.ui.web.admin.configuration.InformationMemory; import org.ejbca.util.cert.CertificateNotBeforeComparator; import org.ejbca.util.query.IllegalQueryException; import org.ejbca.util.query.Query; /** * A java bean handling the interface between EJBCA ra module and JSP pages. * * @version $Id: RAInterfaceBean.java 20942 2015-03-19 15:17:48Z mikekushner $ */ public class RAInterfaceBean implements Serializable { private static final long serialVersionUID = 1L; private static Logger log = Logger.getLogger(RAInterfaceBean.class); /** Internal localization of logs and errors */ private static final InternalEjbcaResources intres = InternalEjbcaResources.getInstance(); public static final int MAXIMUM_QUERY_ROWCOUNT = EndEntityManagementConstants.MAXIMUM_QUERY_ROWCOUNT; public static final String[] tokentexts = SecConst.TOKENTEXTS; public static final int[] tokenids = SecConst.TOKENIDS; private EjbLocalHelper ejbLocalHelper = new EjbLocalHelper(); private EndEntityProfileDataHandler profiles; private AccessControlSessionLocal authorizationsession; private CaSessionLocal caSession; private CertificateProfileSession certificateProfileSession; private CertificateStoreSession certificatesession; private EndEntityAccessSessionLocal endEntityAccessSession; private EndEntityProfileSessionLocal endEntityProfileSession; private HardTokenSession hardtokensession; private KeyRecoverySession keyrecoverysession; private EndEntityManagementSessionLocal endEntityManagementSession; private UserDataSourceSession userdatasourcesession; private ComplexAccessControlSessionLocal complexAccessControlSession; private UsersView usersView; private CertificateView[] certificates; private AddedUserMemory addedusermemory; private AuthenticationToken administrator; private InformationMemory informationmemory; private boolean initialized = false; private String[] printerNames = null; private String importedProfileName = null; private EndEntityProfile temporateendentityprofile = null; /** Creates new RaInterfaceBean */ public RAInterfaceBean() { usersView = new UsersView(); addedusermemory = new AddedUserMemory(); } public void initialize(HttpServletRequest request, EjbcaWebBean ejbcawebbean) { log.trace(">initialize()"); if (!initialized) { if (request.getAttribute("javax.servlet.request.X509Certificate") != null) { administrator = ejbcawebbean.getAdminObject(); } else { administrator = new AlwaysAllowLocalAuthenticationToken( new UsernamePrincipal("RAInterface: " + request.getRemoteAddr())); } this.informationmemory = ejbcawebbean.getInformationMemory(); endEntityManagementSession = ejbLocalHelper.getEndEntityManagementSession(); certificatesession = ejbLocalHelper.getCertificateStoreSession(); caSession = ejbLocalHelper.getCaSession(); authorizationsession = ejbLocalHelper.getAccessControlSession(); endEntityProfileSession = ejbLocalHelper.getEndEntityProfileSession(); this.profiles = new EndEntityProfileDataHandler(administrator, endEntityProfileSession, informationmemory); hardtokensession = ejbLocalHelper.getHardTokenSession(); keyrecoverysession = ejbLocalHelper.getKeyRecoverySession(); userdatasourcesession = ejbLocalHelper.getUserDataSourceSession(); certificateProfileSession = ejbLocalHelper.getCertificateProfileSession(); this.endEntityAccessSession = ejbLocalHelper.getEndEntityAccessSession(); complexAccessControlSession = ejbLocalHelper.getComplexAccessControlSession(); initialized = true; } else { log.debug("=initialize(): already initialized"); } log.trace("<initialize()"); } /** Adds a user to the database, the string array must be in format defined in class UserView. */ public void addUser(UserView userdata) throws EndEntityExistsException, CADoesntExistsException, AuthorizationDeniedException, UserDoesntFullfillEndEntityProfile, WaitingForApprovalException, EjbcaException { log.trace(">addUser()"); if (userdata.getEndEntityProfileId() != 0) { EndEntityInformation uservo = new EndEntityInformation(userdata.getUsername(), userdata.getSubjectDN(), userdata.getCAId(), userdata.getSubjectAltName(), userdata.getEmail(), EndEntityConstants.STATUS_NEW, userdata.getType(), userdata.getEndEntityProfileId(), userdata.getCertificateProfileId(), null, null, userdata.getTokenType(), userdata.getHardTokenIssuerId(), null); uservo.setPassword(userdata.getPassword()); uservo.setExtendedinformation(userdata.getExtendedInformation()); uservo.setCardNumber(userdata.getCardNumber()); endEntityManagementSession.addUser(administrator, uservo, userdata.getClearTextPassword()); addedusermemory.addUser(userdata); } else { log.debug("=addUser(): profile id not set, user not created"); } log.trace("<addUser()"); } /** Removes a number of users from the database. * * @param usernames an array of usernames to delete. * @return false if administrator wasn't authorized to delete all of given users. * */ public boolean deleteUsers(String[] usernames) throws NotFoundException, RemoveException { log.trace(">deleteUsers()"); boolean success = true; for (String username : usernames) { try { endEntityManagementSession.deleteUser(administrator, username); addedusermemory.removeUser(username); } catch (AuthorizationDeniedException e) { success = false; } } log.trace("<deleteUsers(): " + success); return success; } /** Changes the status of a number of users from the database. * * @param usernames an array of usernames to change. * @param status gives the status to apply to users, should be one of UserDataRemote.STATUS constants. * @return false if administrator wasn't authorized to change all of the given users. * */ public boolean setUserStatuses(String[] usernames, String status) throws ApprovalException, FinderException, WaitingForApprovalException { log.trace(">setUserStatuses()"); boolean success = true; int intstatus = 0; try { intstatus = Integer.parseInt(status); } catch (Exception e) { } for (int i = 0; i < usernames.length; i++) { try { endEntityManagementSession.setUserStatus(administrator, usernames[i], intstatus); } catch (AuthorizationDeniedException e) { success = false; } } log.trace("<setUserStatuses(): " + success); return success; } /** * Revokes the given user. * @param users an array of usernames to revoke. * @param reason reason(s) of revocation. * @return false if administrator wasn't authorized to revoke all of the given users. */ public void revokeUser(String username, int reason) throws AuthorizationDeniedException, FinderException, ApprovalException, WaitingForApprovalException, AlreadyRevokedException { log.trace(">revokeUser()"); endEntityManagementSession.revokeUser(administrator, username, reason); log.trace("<revokeUser()"); } public void revokeAndDeleteUser(String username, int reason) throws AuthorizationDeniedException, ApprovalException, WaitingForApprovalException, RemoveException, NotFoundException { log.trace(">revokeUser()"); endEntityManagementSession.revokeAndDeleteUser(administrator, username, reason); log.trace("<revokeUser()"); } /** Revokes the certificate with certificate serno. * * @param serno serial number of certificate to revoke. * @param issuerdn the issuerdn of certificate to revoke. * @param reason reason(s) of revocation. * @return false if administrator wasn't authorized to revoke the given certificate. */ public boolean revokeCert(BigInteger serno, String issuerdn, String username, int reason) throws ApprovalException, WaitingForApprovalException { if (log.isTraceEnabled()) { log.trace(">revokeCert(): " + username + ", " + reason); } boolean success = false; try { endEntityManagementSession.revokeCert(administrator, serno, issuerdn, reason); success = true; } catch (AuthorizationDeniedException e) { } catch (FinderException e) { } catch (AlreadyRevokedException e) { } if (log.isTraceEnabled()) { log.trace("<revokeCert(): " + success); } return success; } /** * Reactivates the certificate with certificate serno. * * @param serno serial number of certificate to reactivate. * @param issuerdn the issuerdn of certificate to reactivate. * @param username the username joined to the certificate. * @return false if administrator wasn't authorized to unrevoke the given certificate. */ public boolean unrevokeCert(BigInteger serno, String issuerdn, String username) throws ApprovalException, WaitingForApprovalException { // Method needed because it is used as an ApprovalOveradableClassName return revokeCert(serno, issuerdn, username, RevokedCertInfo.NOT_REVOKED); } /** Changes the userdata */ public void changeUserData(UserView userdata) throws CADoesntExistsException, AuthorizationDeniedException, UserDoesntFullfillEndEntityProfile, WaitingForApprovalException, EjbcaException { log.trace(">changeUserData()"); addedusermemory.changeUser(userdata); if (userdata.getPassword() != null && userdata.getPassword().trim().equals("")) { userdata.setPassword(null); } EndEntityInformation uservo = new EndEntityInformation(userdata.getUsername(), userdata.getSubjectDN(), userdata.getCAId(), userdata.getSubjectAltName(), userdata.getEmail(), userdata.getStatus(), userdata.getType(), userdata.getEndEntityProfileId(), userdata.getCertificateProfileId(), null, null, userdata.getTokenType(), userdata.getHardTokenIssuerId(), null); uservo.setPassword(userdata.getPassword()); uservo.setExtendedinformation(userdata.getExtendedInformation()); uservo.setCardNumber(userdata.getCardNumber()); endEntityManagementSession.changeUser(administrator, uservo, userdata.getClearTextPassword()); log.trace("<changeUserData()"); } /** Method to filter out a user by it's username */ public UserView[] filterByUsername(String username) { log.trace(">filterByUserName()"); EndEntityInformation[] userarray = new EndEntityInformation[1]; EndEntityInformation user = null; try { user = endEntityAccessSession.findUser(administrator, username); } catch (AuthorizationDeniedException e) { } if (user != null) { userarray[0] = user; usersView.setUsers(userarray, informationmemory.getCAIdToNameMap()); } else { usersView.setUsers((EndEntityInformation[]) null, informationmemory.getCAIdToNameMap()); } log.trace("<filterByUserName()"); return usersView.getUsers(0, 1); } /** Method used to check if user exists */ public boolean userExist(String username) throws Exception { return endEntityManagementSession.existsUser(username); } /** Method to retrieve a user from the database without inserting it into users data, used by 'viewuser.jsp' and page*/ public UserView findUser(String username) throws Exception { if (log.isTraceEnabled()) { log.trace(">findUser(" + username + ")"); } EndEntityInformation user = endEntityAccessSession.findUser(administrator, username); UserView userview = null; if (user != null) { userview = new UserView(user, informationmemory.getCAIdToNameMap()); } if (log.isTraceEnabled()) { log.trace("<findUser(" + username + "): " + userview); } return userview; } /** Method to retrieve a user from the database without inserting it into users data, used by 'edituser.jsp' and page*/ public UserView findUserForEdit(String username) throws AuthorizationDeniedException { UserView userview = null; EndEntityInformation user = endEntityAccessSession.findUser(administrator, username); if (this.informationmemory.getGlobalConfiguration().getEnableEndEntityProfileLimitations()) { if (!endEntityAuthorization(administrator, user.getEndEntityProfileId(), AccessRulesConstants.EDIT_END_ENTITY, false)) { throw new AuthorizationDeniedException("Not authorized to edit user."); } } if (user != null) { userview = new UserView(user, informationmemory.getCAIdToNameMap()); } return userview; } /** Method to find all users in database */ public UserView[] findAllUsers(int index, int size) throws FinderException { usersView.setUsers(endEntityManagementSession.findAllUsersWithLimit(administrator), informationmemory.getCAIdToNameMap()); return usersView.getUsers(index, size); } /** Method to find all users in database */ public UserView[] filterByTokenSN(String tokensn, int index, int size) { UserView[] returnval = null; ArrayList<EndEntityInformation> userlist = new ArrayList<EndEntityInformation>(); Collection<String> usernames = hardtokensession.matchHardTokenByTokenSerialNumber(tokensn); Iterator<String> iter = usernames.iterator(); while (iter.hasNext()) { EndEntityInformation user = null; try { user = endEntityAccessSession.findUser(administrator, (String) iter.next()); } catch (AuthorizationDeniedException e) { } if (user != null) { userlist.add(user); } } usersView.setUsers(userlist, informationmemory.getCAIdToNameMap()); returnval = usersView.getUsers(index, size); return returnval; } /** Method that fetches a certificate by serialnumber and returns the user(s), else a null value if no certificate/user exists. */ public UserView[] filterByCertificateSerialNumber(String serialnumber, int index, int size) throws NumberFormatException { serialnumber = StringTools.stripWhitespace(serialnumber); BigInteger serno = new BigInteger(serialnumber, 16); Collection<Certificate> certs = certificatesession.findCertificatesBySerno(serno); ArrayList<EndEntityInformation> userlist = new ArrayList<EndEntityInformation>(); UserView[] returnval = null; if (certs != null) { for (Certificate next : certs) { try { String username = certificatesession.findUsernameByCertSerno(serno, CertTools.getIssuerDN(next)); if (username != null) { EndEntityInformation user = endEntityAccessSession.findUser(administrator, username); if (user != null) { userlist.add(user); } } if (userlist.isEmpty()) { // Perhaps it's such an old installation that we don't have username in the CertificateData table (has it even ever been like that?, I don't think so) List<EndEntityInformation> users = endEntityAccessSession.findUserBySubjectAndIssuerDN( administrator, CertTools.getSubjectDN(next), CertTools.getIssuerDN(next)); userlist.addAll(users); } } catch (AuthorizationDeniedException e) { } } usersView.setUsers(userlist, informationmemory.getCAIdToNameMap()); returnval = usersView.getUsers(index, size); } return returnval; } /** Method that lists all users with certificate's that expires within given days. */ public UserView[] filterByExpiringCertificates(String days, int index, int size) throws NumberFormatException { ArrayList<EndEntityInformation> userlist = new ArrayList<EndEntityInformation>(); UserView[] returnval = null; long d = Long.parseLong(days); Date finddate = new Date(); long millis = (d * 86400000); // One day in milliseconds. finddate.setTime(finddate.getTime() + millis); Collection<String> usernames = certificatesession.findUsernamesByExpireTimeWithLimit(finddate); if (!usernames.isEmpty()) { Iterator<String> i = usernames.iterator(); while (i.hasNext() && userlist.size() <= EndEntityManagementConstants.MAXIMUM_QUERY_ROWCOUNT + 1) { EndEntityInformation user = null; try { user = endEntityAccessSession.findUser(administrator, (String) i.next()); if (user != null) { userlist.add(user); } } catch (AuthorizationDeniedException e) { } } usersView.setUsers(userlist, informationmemory.getCAIdToNameMap()); returnval = usersView.getUsers(index, size); } return returnval; } public UserView[] filterByQuery(Query query, int index, int size) throws IllegalQueryException { Collection<EndEntityInformation> userlist = endEntityManagementSession.query(administrator, query, informationmemory.getUserDataQueryCAAuthoorizationString(), informationmemory.getUserDataQueryEndEntityProfileAuthorizationString(), 0); usersView.setUsers(userlist, informationmemory.getCAIdToNameMap()); return usersView.getUsers(index, size); } public int getResultSize() { return usersView.size(); } public boolean isAuthorizedToViewUserHistory(String username) throws AuthorizationDeniedException { EndEntityInformation user = endEntityAccessSession.findUser(administrator, username); return endEntityAuthorization(administrator, user.getEndEntityProfileId(), AccessRulesConstants.VIEW_END_ENTITY_HISTORY, false); } public boolean isAuthorizedToEditUser(String username) throws AuthorizationDeniedException { EndEntityInformation user = endEntityAccessSession.findUser(administrator, username); return endEntityAuthorization(administrator, user.getEndEntityProfileId(), AccessRulesConstants.EDIT_END_ENTITY, false); } /** Method to resort filtered user data. */ public void sortUserData(int sortby, int sortorder) { usersView.sortBy(sortby, sortorder); } /** Method to return the users between index and size, if userdata is smaller than size, a smaller array is returned. */ public UserView[] getUsers(int index, int size) { return usersView.getUsers(index, size); } /** Method that clears the userview memory. */ public void clearUsers() { usersView.clear(); } public boolean nextButton(int index, int size) { return index + size < usersView.size(); } public boolean previousButton(int index) { return index > 0; } // Method dealing with added user memory. /** A method to get the last added users in adduser.jsp. * * @see org.ejbca.ui.web.admin.rainterface.AddedUserMemory */ public UserView[] getAddedUsers(int size) { return addedusermemory.getUsers(size); } // Methods dealing with profiles. public TreeMap<String, Integer> getAuthorizedEndEntityProfileNames() { return informationmemory.getAuthorizedEndEntityProfileNames(); } public List<Integer> getAuthorizedEndEntityProfileIdsWithMissingCAs() { return informationmemory.getAuthorizedEndEntityProfileIdsWithMissingCAs(); } /** Returns the profile name from id proxied */ public String getEndEntityProfileName(int profileid) { return this.informationmemory.getEndEntityProfileNameProxy().getEndEntityProfileName(profileid); } /** * * @param profilename the name of the sought profile * @return the ID of the sought profile * @throws EndEntityProfileNotFoundException if no such profile exists */ public int getEndEntityProfileId(String profilename) throws EndEntityProfileNotFoundException { return profiles.getEndEntityProfileId(profilename); } public String getUserDataSourceName(int sourceid) { return this.userdatasourcesession.getUserDataSourceName(administrator, sourceid); } public int getUserDataSourceId(String sourcename) { return this.userdatasourcesession.getUserDataSourceId(administrator, sourcename); } public EndEntityProfile getEndEntityProfile(String name) throws AuthorizationDeniedException { return profiles.getEndEntityProfile(name); } public EndEntityProfile getEndEntityProfile(int id) throws AuthorizationDeniedException { return profiles.getEndEntityProfile(id); } public void addEndEntityProfile(String name) throws EndEntityProfileExistsException, AuthorizationDeniedException { EndEntityProfile profile = new EndEntityProfile(); Iterator<Integer> iter = this.informationmemory.getAuthorizedCAIds().iterator(); String availablecas = ""; if (iter.hasNext()) { availablecas = iter.next().toString(); } while (iter.hasNext()) { availablecas = availablecas + EndEntityProfile.SPLITCHAR + iter.next().toString(); } profile.setValue(EndEntityProfile.AVAILCAS, 0, availablecas); profile.setRequired(EndEntityProfile.AVAILCAS, 0, true); profiles.addEndEntityProfile(name, profile); } public void changeEndEntityProfile(String name, EndEntityProfile profile) throws AuthorizationDeniedException, EndEntityProfileNotFoundException { profiles.changeEndEntityProfile(name, profile); } /** * Removes an end entity profile * * @param name the name of the profile to be removed * @return false if profile is used by any user or in authorization rules. * @throws AuthorizationDeniedException * @throws EndEntityProfileNotFoundException if no such end entity profile was found */ public boolean removeEndEntityProfile(String name) throws AuthorizationDeniedException, EndEntityProfileNotFoundException { boolean profileused = false; int profileid = endEntityProfileSession.getEndEntityProfileId(name); // Check if any users or authorization rule use the profile. profileused = endEntityManagementSession.checkForEndEntityProfileId(profileid) || complexAccessControlSession.existsEndEntityProfileInRules(profileid); if (!profileused) { profiles.removeEndEntityProfile(name); } else { log.info("EndEntityProfile " + name + " is used by either user (UserData table) or access rules (AccessRulesData table), and can not be removed."); } return !profileused; } public void renameEndEntityProfile(String oldname, String newname) throws EndEntityProfileExistsException, AuthorizationDeniedException { profiles.renameEndEntityProfile(oldname, newname); } public void cloneEndEntityProfile(String originalname, String newname) throws EndEntityProfileExistsException, AuthorizationDeniedException { profiles.cloneEndEntityProfile(originalname, newname); } public void loadCertificates(String username) { Collection<Certificate> certs = certificatesession.findCertificatesByUsername(username); loadCertificateView(certs, username); } public void loadTokenCertificates(String tokensn, String username) { Collection<Certificate> certs = hardtokensession.findCertificatesInHardToken(tokensn); loadCertificateView(certs, username); } /** Helper method loading CertificateView and RevokedInfoView arrays given a collection of certificates. * * @param certs certificates to process * @param username user the certs belong to */ private void loadCertificateView(Collection<Certificate> certs, String username) { if (!certs.isEmpty()) { ArrayList<Certificate> list = new ArrayList<Certificate>(certs); if (certs.size() < 50) { Collections.sort(list, new CertificateNotBeforeComparator()); } else { log.debug("User has more than 50 certificates, we will not sort them"); } Iterator<Certificate> j = list.iterator(); certificates = new CertificateView[list.size()]; for (int i = 0; i < certificates.length; i++) { RevokedInfoView revokedinfo = null; Certificate cert = (Certificate) j.next(); CertificateStatus revinfo = certificatesession.getStatus(CertTools.getIssuerDN(cert), CertTools.getSerialNumber(cert)); if (revinfo != null) { revokedinfo = new RevokedInfoView(revinfo, CertTools.getSerialNumber(cert)); } certificates[i] = new CertificateView(cert, revokedinfo, username); } } else { certificates = null; } } public boolean revokeTokenCertificates(String tokensn, String username, int reason) throws ApprovalException, WaitingForApprovalException, AlreadyRevokedException { boolean success = true; ApprovalException lastAppException = null; WaitingForApprovalException lastWaitException = null; AlreadyRevokedException lastRevokedException = null; Collection<Certificate> certs = hardtokensession.findCertificatesInHardToken(tokensn); Iterator<Certificate> i = certs.iterator(); // Extract and revoke collection while (i.hasNext()) { Certificate cert = i.next(); try { endEntityManagementSession.revokeCert(administrator, CertTools.getSerialNumber(cert), CertTools.getIssuerDN(cert), reason); // Ignore errors if some were successful } catch (ApprovalException e) { lastAppException = e; } catch (WaitingForApprovalException e) { lastWaitException = e; } catch (AlreadyRevokedException e) { lastRevokedException = e; } catch (AuthorizationDeniedException e) { success = false; } catch (FinderException e) { success = false; } } if (lastWaitException != null) { throw lastWaitException; } if (lastAppException != null) { throw lastAppException; } if (lastRevokedException != null) { throw lastRevokedException; } return success; } public boolean isAllTokenCertificatesRevoked(String tokensn, String username) { Collection<Certificate> certs = hardtokensession.findCertificatesInHardToken(tokensn); boolean allrevoked = true; if (!certs.isEmpty()) { Iterator<Certificate> j = certs.iterator(); while (j.hasNext()) { Certificate cert = j.next(); boolean isrevoked = certificatesession.isRevoked(CertTools.getIssuerDN(cert), CertTools.getSerialNumber(cert)); if (!isrevoked) { allrevoked = false; } } } return allrevoked; } public void loadCACertificates(CertificateView[] cacerts) { certificates = cacerts; } public void loadCertificates(BigInteger serno, int caId) throws AuthorizationDeniedException { try { loadCertificates(serno, caSession.getCAInfo(administrator, caId).getSubjectDN()); } catch (CADoesntExistsException e) { log.info("Requested CA info for nonexisting CA with id " + caId); } } public void loadCertificates(BigInteger serno, String issuerdn) throws AuthorizationDeniedException { if (!authorizationsession.isAuthorizedNoLogging(administrator, StandardRules.CAACCESS.resource() + issuerdn.hashCode())) { final String msg = intres.getLocalizedMessage("authorization.notuathorizedtoresource", StandardRules.CAACCESS.resource() + issuerdn.hashCode(), "Not authorized to view certificate."); throw new AuthorizationDeniedException(msg); } Certificate cert = certificatesession.findCertificateByIssuerAndSerno(issuerdn, serno); if (cert != null) { RevokedInfoView revokedinfo = null; String username = certificatesession.findUsernameByCertSerno(serno, CertTools.getIssuerDN(cert)); if (this.endEntityAccessSession.findUser(administrator, username) != null) { int endentityprofileid = this.endEntityAccessSession.findUser(administrator, username) .getEndEntityProfileId(); this.endEntityAuthorization(administrator, endentityprofileid, AccessRulesConstants.VIEW_END_ENTITY, true); } CertificateStatus revinfo = certificatesession.getStatus(CertTools.getIssuerDN(cert), CertTools.getSerialNumber(cert)); if (revinfo != null) { revokedinfo = new RevokedInfoView(revinfo, CertTools.getSerialNumber(cert)); } certificates = new CertificateView[1]; certificates[0] = new CertificateView(cert, revokedinfo, username); } else { certificates = null; } } public int getNumberOfCertificates() { int returnval = 0; if (certificates != null) { returnval = certificates.length; } return returnval; } public CertificateView getCertificate(int index) { CertificateView returnval = null; if (certificates != null) { returnval = certificates[index]; } return returnval; } public boolean authorizedToEditUser(int profileid) { return endEntityAuthorization(administrator, profileid, AccessRulesConstants.EDIT_END_ENTITY, false); } public boolean authorizedToViewHistory(int profileid) { return endEntityAuthorization(administrator, profileid, AccessRulesConstants.VIEW_END_ENTITY_HISTORY, false); } public boolean authorizedToViewHardToken(String username) throws AuthorizationDeniedException { int profileid = endEntityAccessSession.findUser(administrator, username).getEndEntityProfileId(); if (!endEntityAuthorization(administrator, profileid, AccessRulesConstants.HARDTOKEN_RIGHTS, false)) { throw new AuthorizationDeniedException(); } if (!WebConfiguration.getHardTokenDiplaySensitiveInfo()) { return false; } return endEntityAuthorization(administrator, profileid, AccessRulesConstants.HARDTOKEN_PUKDATA_RIGHTS, false); } public boolean authorizedToViewHardToken(int profileid) { return endEntityAuthorization(administrator, profileid, AccessRulesConstants.HARDTOKEN_RIGHTS, false); } public boolean authorizedToRevokeCert(String username) throws AuthorizationDeniedException { boolean returnval = false; EndEntityInformation data = endEntityAccessSession.findUser(administrator, username); if (data == null) { return false; } int profileid = data.getEndEntityProfileId(); if (informationmemory.getGlobalConfiguration().getEnableEndEntityProfileLimitations()) { returnval = endEntityAuthorization(administrator, profileid, AccessRulesConstants.REVOKE_END_ENTITY, false); } else { returnval = true; } return returnval; } public boolean keyRecoveryPossible(Certificate cert, String username) throws AuthorizationDeniedException { boolean returnval = true; returnval = authorizationsession.isAuthorizedNoLogging(administrator, AccessRulesConstants.REGULAR_KEYRECOVERY); if (informationmemory.getGlobalConfiguration().getEnableEndEntityProfileLimitations()) { EndEntityInformation data = endEntityAccessSession.findUser(administrator, username); if (data != null) { int profileid = data.getEndEntityProfileId(); returnval = endEntityAuthorization(administrator, profileid, AccessRulesConstants.KEYRECOVERY_RIGHTS, false); } else { returnval = false; } } return returnval && keyrecoverysession.existsKeys(cert) && !keyrecoverysession.isUserMarked(username); } public void markForRecovery(String username, Certificate cert) throws AuthorizationDeniedException, ApprovalException, WaitingForApprovalException { boolean authorized = true; int endEntityProfileId = endEntityAccessSession.findUser(administrator, username).getEndEntityProfileId(); if (informationmemory.getGlobalConfiguration().getEnableEndEntityProfileLimitations()) { authorized = endEntityAuthorization(administrator, endEntityProfileId, AccessRulesConstants.KEYRECOVERY_RIGHTS, false); } if (authorized) { endEntityManagementSession.prepareForKeyRecovery(administrator, username, endEntityProfileId, cert); } } public String[] getCertificateProfileNames() { String[] dummy = { "" }; Collection<String> certprofilenames = this.informationmemory.getAuthorizedEndEntityCertificateProfileNames() .keySet(); if (certprofilenames == null) { return new String[0]; } return (String[]) certprofilenames.toArray(dummy); } public int getCertificateProfileId(String certificateprofilename) { return certificateProfileSession.getCertificateProfileId(certificateprofilename); } public String getCertificateProfileName(int certificateprofileid) { return this.informationmemory.getCertificateProfileNameProxy() .getCertificateProfileName(certificateprofileid); } public boolean getEndEntityParameter(String parameter) { if (parameter == null) { return false; } return parameter.equals(EndEntityProfile.TRUE); } /** Help function used to check end entity profile authorization. */ public boolean endEntityAuthorization(AuthenticationToken admin, int profileid, String rights, boolean log) { boolean returnval = false; if (log) { returnval = authorizationsession.isAuthorized(admin, AccessRulesConstants.ENDENTITYPROFILEPREFIX + Integer.toString(profileid) + rights, AccessRulesConstants.REGULAR_RAFUNCTIONALITY + rights); } else { returnval = authorizationsession.isAuthorizedNoLogging(admin, AccessRulesConstants.ENDENTITYPROFILEPREFIX + Integer.toString(profileid) + rights, AccessRulesConstants.REGULAR_RAFUNCTIONALITY + rights); } return returnval; } /** * Help function used by edit end entity pages used to temporary save a profile * so things can be canceled later */ public EndEntityProfile getTemporaryEndEntityProfile() { return this.temporateendentityprofile; } public void setTemporaryEndEntityProfile(EndEntityProfile profile) { this.temporateendentityprofile = profile; } UserDataSourceSession getUserDataSourceSession() { return userdatasourcesession; } public String[] listPrinters() { if (printerNames == null) { printerNames = org.ejbca.util.PrinterManager.listPrinters(); } return printerNames; } public String getFormatedCertSN(CertificateView certificateData) { String serialnumber = certificateData.getSerialNumber(); if (StringUtils.equals(certificateData.getType(), "X.509")) { if ((serialnumber.length() % 2) != 0) { serialnumber = "0" + serialnumber; } int octetChar = serialnumber.charAt(0) - '0'; if (octetChar > 7) { serialnumber = "00" + serialnumber; } } return serialnumber; } /** * Handle the combinations of AnyCA and default CA to get the correct available CAs line. * @param availableCasArray an array of CA Ids * @param defaultCa the CA Id of the selected default CA * @return the ;-seperated list of CA Ids */ public String getAvailableCasString(final String[] availableCasArray, final String defaultCa) { final List<String> availableCasList = Arrays.asList(availableCasArray); final StringBuilder sb = new StringBuilder(); if (availableCasList.contains(String.valueOf(SecConst.ALLCAS)) || availableCasList.contains(defaultCa)) { // If the AnyCA or the default CA is selected we will just keep list of selected CAs as is // (the admin might want to use AnyCA with additional selections for awkward access control) for (final String current : availableCasList) { if (sb.length() > 0) { sb.append(EndEntityProfile.SPLITCHAR); } sb.append(current); } } else { // If AnyCA isn't selected and the not the default either we need to add the default CA to the list of available CAs sb.append(defaultCa); for (final String current : availableCasList) { sb.append(EndEntityProfile.SPLITCHAR); sb.append(current); } } return sb.toString(); } //------------------------------------------------------- // Import/Export profiles related code //------------------------------------------------------- public byte[] getfileBuffer(HttpServletRequest request, Map<String, String> requestMap) throws IOException, FileUploadException { byte[] fileBuffer = null; if (ServletFileUpload.isMultipartContent(request)) { final DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory(); diskFileItemFactory.setSizeThreshold(59999); ServletFileUpload upload = new ServletFileUpload(diskFileItemFactory); upload.setSizeMax(60000); final List<FileItem> items = upload.parseRequest(request); for (final FileItem item : items) { if (item.isFormField()) { final String fieldName = item.getFieldName(); final String currentValue = requestMap.get(fieldName); if (currentValue != null) { requestMap.put(fieldName, currentValue + ";" + item.getString("UTF8")); } else { requestMap.put(fieldName, item.getString("UTF8")); } } else { importedProfileName = item.getName(); final InputStream file = item.getInputStream(); byte[] fileBufferTmp = FileTools.readInputStreamtoBuffer(file); if (fileBuffer == null && fileBufferTmp.length > 0) { fileBuffer = fileBufferTmp; } } } } else { final Set<String> keySet = request.getParameterMap().keySet(); for (final String key : keySet) { requestMap.put(key, request.getParameter(key)); } } return fileBuffer; } public String importProfilesFromZip(byte[] filebuffer) { if (log.isTraceEnabled()) { log.trace(">importProfiles(): " + importedProfileName + " - " + filebuffer.length + " bytes"); } String retmsg = ""; String faultXMLmsg = ""; if (StringUtils.isEmpty(importedProfileName) || filebuffer.length == 0) { retmsg = "Error: No input file"; log.error(retmsg); return retmsg; } int importedFiles = 0; int ignoredFiles = 0; int nrOfFiles = 0; try { ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(filebuffer)); ZipEntry ze = zis.getNextEntry(); if (ze == null) { retmsg = "Error: Expected a zip file. '" + importedProfileName + "' is not a zip file."; log.error(retmsg); return retmsg; } do { nrOfFiles++; String filename = ze.getName(); if (log.isDebugEnabled()) { log.debug("Importing file: " + filename); } if (ignoreFile(filename)) { ignoredFiles++; continue; } String profilename; filename = URLDecoder.decode(filename, "UTF-8"); int index1 = filename.indexOf("_"); int index2 = filename.lastIndexOf("-"); int index3 = filename.lastIndexOf(".xml"); profilename = filename.substring(index1 + 1, index2); int profileid = 0; try { profileid = Integer.parseInt(filename.substring(index2 + 1, index3)); } catch (NumberFormatException e) { if (log.isDebugEnabled()) { log.debug("NumberFormatException parsing certificate profile id: " + e.getMessage()); } ignoredFiles++; continue; } if (log.isDebugEnabled()) { log.debug("Extracted profile name '" + profilename + "' and profile ID '" + profileid + "'"); } if (ignoreProfile(filename, profilename, profileid)) { ignoredFiles++; continue; } if (endEntityProfileSession.getEndEntityProfile(profileid) != null) { int newprofileid = endEntityProfileSession.findFreeEndEntityProfileId(); log.warn("Entity profileid '" + profileid + "' already exist in database. Using " + newprofileid + " instead."); profileid = newprofileid; } byte[] filebytes = new byte[102400]; int i = 0; while ((zis.available() == 1) && (i < filebytes.length)) { filebytes[i++] = (byte) zis.read(); } EndEntityProfile eprofile = getEEProfileFromByteArray(profilename, filebytes); if (eprofile == null) { String msg = "Faulty XML file '" + filename + "'. Failed to read End Entity Profile."; log.info(msg + " Ignoring file."); ignoredFiles++; faultXMLmsg += filename + ", "; continue; } profiles.addEndEntityProfile(profilename, eprofile); importedFiles++; log.info("Added EndEntity profile: " + profilename); } while ((ze = zis.getNextEntry()) != null); zis.closeEntry(); zis.close(); } catch (UnsupportedEncodingException e) { retmsg = "Error: UTF-8 was not a known character encoding."; log.error(retmsg, e); return retmsg; } catch (IOException e) { log.error(e); retmsg = "Error: " + e.getLocalizedMessage(); return retmsg; } catch (AuthorizationDeniedException e) { log.error(e); retmsg = "Error: " + e.getLocalizedMessage(); return retmsg; } catch (EndEntityProfileExistsException e) { log.error(e); retmsg = "Error: " + e.getLocalizedMessage(); return retmsg; } if (StringUtils.isNotEmpty(faultXMLmsg)) { faultXMLmsg = faultXMLmsg.substring(0, faultXMLmsg.length() - 2); retmsg = "Faulty XML files: " + faultXMLmsg + ". " + importedFiles + " profiles were imported."; } else { retmsg = importedProfileName + " contained " + nrOfFiles + " files. " + importedFiles + " EndEntity Profiles were imported and " + ignoredFiles + " files were ignored."; } log.info(retmsg); return retmsg; } private EndEntityProfile getEEProfileFromByteArray(String profilename, byte[] profileBytes) throws AuthorizationDeniedException { ByteArrayInputStream is = new ByteArrayInputStream(profileBytes); EndEntityProfile eprofile = new EndEntityProfile(); try { XMLDecoder decoder = getXMLDecoder(is); // Add end entity profile Object data = null; try { data = decoder.readObject(); } catch (IllegalArgumentException e) { if (log.isDebugEnabled()) { log.debug("IllegalArgumentException parsing certificate profile data: " + e.getMessage()); } return null; } decoder.close(); eprofile.loadData(data); // Translate cert profile ids that have changed after import String availableCertProfiles = ""; String defaultCertProfile = eprofile.getValue(EndEntityProfile.DEFAULTCERTPROFILE, 0); for (String currentCertProfile : (Collection<String>) eprofile.getAvailableCertificateProfileIds()) { Integer currentCertProfileId = Integer.parseInt(currentCertProfile); if (certificateProfileSession.getCertificateProfile(currentCertProfileId) != null || CertificateProfileConstants.isFixedCertificateProfile(currentCertProfileId)) { availableCertProfiles += (availableCertProfiles.equals("") ? "" : ";") + currentCertProfile; } else { log.warn("End Entity Profile '" + profilename + "' references certificate profile " + currentCertProfile + " that does not exist."); if (currentCertProfile.equals(defaultCertProfile)) { defaultCertProfile = ""; } } } if (availableCertProfiles.equals("")) { log.warn( "End Entity Profile only references certificate profile(s) that does not exist. Using ENDUSER profile."); availableCertProfiles = "1"; // At least make sure the default profile is available } if (defaultCertProfile.equals("")) { defaultCertProfile = availableCertProfiles.split(";")[0]; // Use first available profile from list as default if original default was missing } eprofile.setValue(EndEntityProfile.AVAILCERTPROFILES, 0, availableCertProfiles); eprofile.setValue(EndEntityProfile.DEFAULTCERTPROFILE, 0, defaultCertProfile); // Remove any unknown CA and break if none is left String defaultCA = eprofile.getValue(EndEntityProfile.DEFAULTCA, 0); String availableCAs = eprofile.getValue(EndEntityProfile.AVAILCAS, 0); List<String> cas = Arrays.asList(availableCAs.split(";")); availableCAs = ""; for (String currentCA : cas) { Integer currentCAInt = Integer.parseInt(currentCA); // The constant ALLCAS will not be searched for among available CAs try { if (currentCAInt.intValue() != SecConst.ALLCAS) { caSession.getCAInfo(administrator, currentCAInt); } availableCAs += (availableCAs.equals("") ? "" : ";") + currentCA; // No Exception means CA exists } catch (CADoesntExistsException e) { log.warn("CA with id " + currentCA + " was not found and will not be used in end entity profile '" + profilename + "'."); if (defaultCA.equals(currentCA)) { defaultCA = ""; } } } if (availableCAs.equals("")) { log.error("No CAs left in end entity profile '" + profilename + "'. Using ALLCAs."); availableCAs = Integer.toString(SecConst.ALLCAS); } if (defaultCA.equals("")) { defaultCA = availableCAs.split(";")[0]; // Use first available log.warn("Changing default CA in end entity profile '" + profilename + "' to " + defaultCA + "."); } eprofile.setValue(EndEntityProfile.AVAILCAS, 0, availableCAs); eprofile.setValue(EndEntityProfile.DEFAULTCA, 0, defaultCA); } finally { try { is.close(); } catch (IOException e) { throw new IllegalStateException("Unknown IOException was caught when closing stream", e); } } return eprofile; } private boolean ignoreFile(String filename) { if (filename.lastIndexOf(".xml") != (filename.length() - 4)) { if (log.isDebugEnabled()) { log.debug(filename + " is not an XML file. IGNORED"); } return true; } if (filename.indexOf("_") < 0 || filename.lastIndexOf("-") < 0 || (filename.indexOf("entityprofile_") < 0)) { if (log.isDebugEnabled()) { log.debug(filename + " is not in the expected format. " + "The file name should look like: entityprofile_<profile name>-<profile id>.xml. IGNORED"); } return true; } return false; } private boolean ignoreProfile(String filename, String profilename, int profileid) { // We don't add the fixed profiles, EJBCA handles those automagically if (profileid == SecConst.EMPTY_ENDENTITYPROFILE) { log.info(filename + " contains a fixed profile. IGNORED"); return true; } // Check if the profiles already exist, and change the name and id if already taken if (endEntityProfileSession.getEndEntityProfile(profilename) != null) { log.info("Entity profile '" + profilename + "' already exist in database. IGNORED"); return true; } return false; } private XMLDecoder getXMLDecoder(ByteArrayInputStream is) { // Without the exception listener, when a faulty xml file is read, the XMLDecoder catches the exception, // writes an error message to stderr and continues reading. Ejbca wouldn't notice that the profile created // based on this XML file is faulty until it is used. ExceptionListener elistener = new ExceptionListener() { @Override public void exceptionThrown(Exception e) { // This probably means that an extra byte is found or something. The certprofile that raises this exception // does not seem to be faulty at all as far as I can test. if (StringUtils.equals("org.apache.xerces.impl.io.MalformedByteSequenceException", e.getClass().getName())) { log.error("org.apache.xerces.impl.io.MalformedByteSequenceException: " + e.getMessage()); log.error("Continuing ..."); } else { log.error(e.getClass().getName() + ": " + e.getMessage()); throw new IllegalArgumentException(e); } } }; return new XMLDecoder(is, null, elistener); } }