/************************************************************************* * * * SignServer: The OpenSource Automated Signing Server * * * * 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.signserver.ejb; import java.math.BigInteger; import java.security.KeyStoreException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.*; import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.ejb.EJBException; import javax.ejb.Stateless; import javax.persistence.EntityManager; import org.apache.log4j.Logger; import org.cesecore.audit.AuditLogEntry; import org.cesecore.audit.audit.SecurityEventsAuditorSessionLocal; import org.cesecore.audit.enums.EventStatus; import org.cesecore.audit.log.AuditRecordStorageException; import org.cesecore.audit.log.SecurityEventsLoggerSessionLocal; import org.cesecore.authentication.tokens.UsernamePrincipal; import org.cesecore.authorization.AuthorizationDeniedException; import org.cesecore.util.query.QueryCriteria; import org.ejbca.util.CertTools; import org.signserver.common.*; import org.signserver.common.KeyTestResult; import org.signserver.ejb.interfaces.IGlobalConfigurationSession; import org.signserver.ejb.interfaces.IServiceTimerSession; import org.signserver.ejb.interfaces.IWorkerSession; import org.signserver.ejb.worker.impl.IWorkerManagerSessionLocal; import org.signserver.server.*; import org.signserver.server.archive.Archivable; import org.signserver.server.archive.ArchiveException; import org.signserver.server.archive.Archiver; import org.signserver.server.archive.olddbarchiver.entities.ArchiveDataBean; import org.signserver.server.archive.olddbarchiver.entities.ArchiveDataService; import org.signserver.server.cesecore.AlwaysAllowLocalAuthenticationToken; import org.signserver.server.config.entities.FileBasedWorkerConfigDataService; import org.signserver.server.config.entities.IWorkerConfigDataService; import org.signserver.server.config.entities.WorkerConfigDataService; import org.signserver.server.entities.FileBasedKeyUsageCounterDataService; import org.signserver.server.entities.IKeyUsageCounterDataService; import org.signserver.server.entities.KeyUsageCounter; import org.signserver.server.entities.KeyUsageCounterDataService; import org.signserver.server.log.*; import org.signserver.server.nodb.FileBasedDatabaseManager; import org.signserver.server.statistics.Event; import org.signserver.server.statistics.StatisticsManager; /** * The main worker session bean. * * @version $Id: WorkerSessionBean.java 3452 2013-04-20 21:32:59Z netmackan $ */ @Stateless public class WorkerSessionBean implements IWorkerSession.ILocal, IWorkerSession.IRemote { /** Log4j instance for this class. */ private static final Logger LOG = Logger.getLogger(WorkerSessionBean.class); /** The local home interface of Worker Config entity bean. */ private IWorkerConfigDataService workerConfigService; /** The local home interface of archive entity bean. */ private ArchiveDataService archiveDataService; private IKeyUsageCounterDataService keyUsageCounterDataService; @EJB private IGlobalConfigurationSession.ILocal globalConfigurationSession; @EJB private IServiceTimerSession.ILocal serviceTimerSession; @EJB private IWorkerManagerSessionLocal workerManagerSession; @EJB private SecurityEventsLoggerSessionLocal logSession; @EJB private SecurityEventsAuditorSessionLocal auditorSession; EntityManager em; @PostConstruct public void create() { if (em == null) { if (LOG.isDebugEnabled()) { LOG.debug("No EntityManager injected. Running without database."); } workerConfigService = new FileBasedWorkerConfigDataService(FileBasedDatabaseManager.getInstance()); keyUsageCounterDataService = new FileBasedKeyUsageCounterDataService(FileBasedDatabaseManager.getInstance()); } else { if (LOG.isDebugEnabled()) { LOG.debug("EntityManager injected. Running with database."); } workerConfigService = new WorkerConfigDataService(em); archiveDataService = new ArchiveDataService(em); keyUsageCounterDataService = new KeyUsageCounterDataService(em); } } @Override public ProcessResponse process(final int workerId, final ProcessRequest request, final RequestContext requestContext) throws IllegalRequestException, CryptoTokenOfflineException, SignServerException { return process(new AdminInfo("Client user", null, null), workerId, request, requestContext); } /** * @see org.signserver.ejb.interfaces.IWorkerSession.ILocal#process(adminInfo, int, org.signserver.common.ProcessRequest, org.signserver.common.RequestContext) */ @Override public ProcessResponse process(final AdminInfo adminInfo, final int workerId, final ProcessRequest request, final RequestContext requestContext) throws IllegalRequestException, CryptoTokenOfflineException, SignServerException { if (LOG.isDebugEnabled()) { LOG.debug(">process: " + workerId); } // Start time final long startTime = System.currentTimeMillis(); // Map of log entries final LogMap logMap = LogMap.getInstance(requestContext); // Get transaction ID or create new if not created yet final String transactionID; if (requestContext.get(RequestContext.TRANSACTION_ID) == null) { transactionID = generateTransactionID(); } else { transactionID = (String) requestContext.get( RequestContext.TRANSACTION_ID); } // Store values for request context and logging requestContext.put(RequestContext.WORKER_ID, Integer.valueOf(workerId)); requestContext.put(RequestContext.TRANSACTION_ID, transactionID); logMap.put(IWorkerLogger.LOG_TIME, String.valueOf(startTime)); logMap.put(IWorkerLogger.LOG_ID, transactionID); logMap.put(IWorkerLogger.LOG_WORKER_ID, String.valueOf(workerId)); logMap.put(IWorkerLogger.LOG_CLIENT_IP, (String) requestContext.get(RequestContext.REMOTE_IP)); // Get worker instance final IWorker worker = workerManagerSession.getWorker(workerId, globalConfigurationSession); if (worker == null) { NoSuchWorkerException ex = new NoSuchWorkerException(String.valueOf(workerId)); Map details = new LinkedHashMap(); final String serNo = adminInfo.getCertSerialNumber() != null ? adminInfo.getCertSerialNumber().toString(16) : null; // produce backwards-compatible log entries here... details.put(IWorkerLogger.LOG_EXCEPTION, ex.getMessage()); details.put(IWorkerLogger.LOG_PROCESS_SUCCESS, String.valueOf(false)); // duplicate entries that would have gone to the worker log details.put(IWorkerLogger.LOG_TIME, String.valueOf(startTime)); details.put(IWorkerLogger.LOG_ID, transactionID); details.put(IWorkerLogger.LOG_CLIENT_IP, (String) requestContext.get(RequestContext.REMOTE_IP)); logSession.log(SignServerEventTypes.PROCESS, EventStatus.FAILURE, SignServerModuleTypes.WORKER, SignServerServiceTypes.SIGNSERVER, adminInfo.getSubjectDN(), adminInfo.getIssuerDN(), serNo, null, details); throw ex; } final WorkerConfig awc = worker.getConfig(); // Get worker log instance final IWorkerLogger workerLogger = workerManagerSession.getWorkerLogger(workerId, awc); if (LOG.isDebugEnabled()) { LOG.debug("Worker[" + workerId + "]: " + "WorkerLogger: " + workerLogger); } try { // Get processable if (!(worker instanceof IProcessable)) { final IllegalRequestException ex = new IllegalRequestException( "Worker exists but isn't a processable: " + workerId); // auditLog(startTime, workerId, false, requestContext, ex); logException(adminInfo, ex, logMap, workerLogger); throw ex; } final IProcessable processable = (IProcessable) worker; // Check authorization logMap.put(IWorkerLogger.LOG_WORKER_AUTHTYPE, processable.getAuthenticationType()); try { workerManagerSession.getAuthenticator(workerId, processable.getAuthenticationType(), awc).isAuthorized(request, requestContext); logMap.put(IWorkerLogger.LOG_CLIENT_AUTHORIZED, String.valueOf(true)); } catch (AuthorizationRequiredException ex) { throw ex; } catch (AccessDeniedException ex) { throw ex; } catch (IllegalRequestException ex) { final IllegalRequestException exception = new IllegalRequestException("Authorization failed: " + ex.getMessage(), ex); logMap.put(IWorkerLogger.LOG_CLIENT_AUTHORIZED, String.valueOf(false)); logException(adminInfo, ex, logMap, workerLogger); throw exception; } catch (SignServerException ex) { final SignServerException exception = new SignServerException("Authorization failed: " + ex.getMessage(), ex); logMap.put(IWorkerLogger.LOG_CLIENT_AUTHORIZED, String.valueOf(false)); logException(adminInfo, ex, logMap, workerLogger); throw exception; } // Log client certificate (if any) final Certificate clientCertificate = (Certificate) requestContext.get(RequestContext.CLIENT_CERTIFICATE); if (clientCertificate instanceof X509Certificate) { final X509Certificate cert = (X509Certificate) clientCertificate; logMap.put(IWorkerLogger.LOG_CLIENT_CERT_SUBJECTDN, cert.getSubjectDN().getName()); logMap.put(IWorkerLogger.LOG_CLIENT_CERT_ISSUERDN, cert.getIssuerDN().getName()); logMap.put(IWorkerLogger.LOG_CLIENT_CERT_SERIALNUMBER, cert.getSerialNumber().toString(16)); } // Check activation if (awc.getProperties().getProperty(SignServerConstants.DISABLED, "FALSE").equalsIgnoreCase("TRUE")) { final CryptoTokenOfflineException exception = new CryptoTokenOfflineException("Error Signer : " + workerId + " is disabled and cannot perform any signature operations"); logException(adminInfo, exception, logMap, workerLogger); throw exception; } // Check signer certificate final boolean counterDisabled = awc.getProperties().getProperty(SignServerConstants.DISABLEKEYUSAGECOUNTER, "FALSE").equalsIgnoreCase("TRUE"); final long keyUsageLimit; try { keyUsageLimit = Long.valueOf(awc.getProperty(SignServerConstants.KEYUSAGELIMIT, "-1")); } catch (NumberFormatException ex) { final SignServerException exception = new SignServerException("Incorrect value in worker property " + SignServerConstants.KEYUSAGELIMIT, ex); logException(adminInfo, exception, logMap, workerLogger); throw exception; } final boolean keyUsageLimitSpecified = keyUsageLimit != -1; if (counterDisabled && keyUsageLimitSpecified) { LOG.error("Worker]" + workerId + "]: Configuration error: " + SignServerConstants.DISABLEKEYUSAGECOUNTER + "=TRUE but " + SignServerConstants.KEYUSAGELIMIT + " is also configured. Key usage counter will still be used."); } try { // Check if the signer has a signer certificate and if that // certificate have ok validity and private key usage periods. checkSignerValidity(workerId, awc, logMap); // Check key usage limit (preliminary check only) if (LOG.isDebugEnabled()) { LOG.debug("Key usage counter disabled: " + counterDisabled); } if (!counterDisabled || keyUsageLimitSpecified) { checkSignerKeyUsageCounter(processable, workerId, awc, em, false); } } catch (CryptoTokenOfflineException ex) { final CryptoTokenOfflineException exception = new CryptoTokenOfflineException(ex); logException(adminInfo, exception, logMap, workerLogger); throw exception; } // Statistics: start event final Event event = StatisticsManager.startEvent(workerId, awc, em); requestContext.put(RequestContext.STATISTICS_EVENT, event); // Process the request final ProcessResponse res; try { res = processable.processData(request, requestContext); } catch (AuthorizationRequiredException ex) { throw ex; // This can happen in dispatching workers } catch (SignServerException e) { final SignServerException exception = new SignServerException( "SignServerException calling signer with id " + workerId + " : " + e.getMessage(), e); LOG.error(exception.getMessage(), exception); logException(adminInfo, exception, logMap, workerLogger); throw exception; } catch (IllegalRequestException ex) { final IllegalRequestException exception = new IllegalRequestException(ex.getMessage()); if (LOG.isInfoEnabled()) { LOG.info("Illegal request calling signer with id " + workerId + " : " + ex.getMessage()); } logException(adminInfo, exception, logMap, workerLogger); throw exception; } catch (CryptoTokenOfflineException ex) { final CryptoTokenOfflineException exception = new CryptoTokenOfflineException(ex); logException(adminInfo, exception, logMap, workerLogger); throw exception; } // Charge the client if the request was successfull if (Boolean.TRUE.equals(requestContext.get( RequestContext.WORKER_FULFILLED_REQUEST))) { // Billing time boolean purchased = false; try { IClientCredential credential = (IClientCredential) requestContext.get( RequestContext.CLIENT_CREDENTIAL); purchased = workerManagerSession.getAccounter(workerId, awc).purchase(credential, request, res, requestContext); logMap.put(IWorkerLogger.LOG_PURCHASED, "true"); } catch (AccounterException ex) { logMap.put(IWorkerLogger.LOG_PURCHASED, "false"); final SignServerException exception = new SignServerException("Accounter failed: " + ex.getMessage(), ex); logException(adminInfo, ex, logMap, workerLogger); throw exception; } if (!purchased) { final String error = "Purchase not granted"; logMap.put(IWorkerLogger.LOG_EXCEPTION, error); logMap.put(IWorkerLogger.LOG_PROCESS_SUCCESS, String.valueOf(false)); workerLogger.log(adminInfo, logMap); throw new NotGrantedException(error); } } else { logMap.put(IWorkerLogger.LOG_PURCHASED, "false"); } // Archiving if (res instanceof IArchivableProcessResponse) { final IArchivableProcessResponse arres = (IArchivableProcessResponse) res; final Collection archivables = arres.getArchivables(); if (archivables != null) { // Archive all Archivables using all ArchiverS final List archivers = workerManagerSession.getArchivers(workerId, awc); if (archivers != null) { try { for (Archiver archiver : archivers) { for (Archivable archivable : archivables) { final boolean archived = archiver.archive( archivable, requestContext); if (LOG.isDebugEnabled()) { final StringBuilder buff = new StringBuilder(); buff.append("Archiver "); buff.append(archiver); buff.append(" archived request: "); buff.append(archived); LOG.debug(buff.toString()); } } } } catch (ArchiveException ex) { LOG.error("Archiving failed", ex); throw new SignServerException( "Archiving failed. See server LOG."); } } } } // Statistics: end event StatisticsManager.endEvent(workerId, awc, em, event); // Check key usage limit if (!counterDisabled || keyUsageLimitSpecified) { checkSignerKeyUsageCounter(processable, workerId, awc, em, true); } // Output successfully if (LOG.isDebugEnabled()) { if (res instanceof ISignResponse) { LOG.debug("Worker " + workerId + " Processed request " + ((ISignResponse) res).getRequestID() + " successfully"); } else { LOG.debug("Worker " + workerId + " Processed request successfully"); } } // Old log entries (SignServer 3.1) added for backward compatibility // Log: REQUESTID if (res instanceof ISignResponse) { logMap.put("REQUESTID", String.valueOf(((ISignResponse) res).getRequestID())); } // Log String logVal = logMap.get(IWorkerLogger.LOG_PROCESS_SUCCESS); // log process status true if not already set by the worker... if (logVal == null) { logMap.put(IWorkerLogger.LOG_PROCESS_SUCCESS, String.valueOf(true)); } workerLogger.log(adminInfo, logMap); LOG.debug(" -1) { if (!keyUsageCounterDataService.isWithinLimit(keyHash, keyUsageLimit)) { final String message = "Key usage limit exceeded or not initialized for worker " + workerId; LOG.debug(message); throw new CryptoTokenOfflineException(message); } } } } else { if (LOG.isDebugEnabled()) { LOG.debug("Worker[" + workerId + "]: " + "No certificate so not checking signing key usage counter"); } } } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#getStatus(int) */ @Override public WorkerStatus getStatus(int workerId) throws InvalidWorkerIdException { IWorker worker = workerManagerSession.getWorker(workerId, globalConfigurationSession); if (worker == null) { throw new InvalidWorkerIdException("Given SignerId " + workerId + " doesn't exist"); } final List errorsAtEjbLevel = new LinkedList(); if (worker instanceof IProcessable) { final IProcessable processable = (IProcessable) worker; try { final IAuthorizer authenticator = workerManagerSession.getAuthenticator( workerId, processable.getAuthenticationType(), worker.getConfig()); errorsAtEjbLevel.addAll(authenticator.getFatalErrors()); } catch (IllegalRequestException ex) { if (LOG.isDebugEnabled()) { LOG.debug("Unable to get authenticator for worker: " + workerId, ex); } errorsAtEjbLevel.add(ex.getLocalizedMessage()); } } return worker.getStatus(errorsAtEjbLevel); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#getWorkerId(java.lang.String) */ @Override public int getWorkerId(String signerName) { return workerManagerSession.getIdFromName(signerName, globalConfigurationSession); } @Override public void reloadConfiguration(int workerId) { reloadConfiguration(new AdminInfo("CLI user", null, null), workerId); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession.ILocal#reloadConfiguration(adminInfo, int) */ @Override public void reloadConfiguration(final AdminInfo adminInfo, int workerId) { if (workerId == 0) { globalConfigurationSession.reload(adminInfo); } else { workerManagerSession.reloadWorker(workerId, globalConfigurationSession); auditLog(adminInfo, SignServerEventTypes.RELOAD_WORKER_CONFIG, SignServerModuleTypes.WORKER_CONFIG, Integer.toString(workerId), Collections.emptyMap()); // Try to insert a key usage counter entry for this worker's public // key // Get worker instance final IWorker worker = workerManagerSession.getWorker(workerId, globalConfigurationSession); if (worker instanceof BaseProcessable) { try { final Certificate cert = ((BaseProcessable)worker) .getSigningCertificate(); if (cert != null) { final String keyHash = KeyUsageCounterHash .create(cert.getPublicKey()); KeyUsageCounter counter = keyUsageCounterDataService.getCounter(keyHash); if (counter == null) { keyUsageCounterDataService.create(keyHash); if (LOG.isDebugEnabled()) { LOG.debug("Worker[" + workerId + "]: " + "new key usage counter initialized"); } } else { if (LOG.isDebugEnabled()) { LOG.debug("Worker[" + workerId + "]: " + "key usage counter: " + counter.getCounter()); } } } } catch (CryptoTokenOfflineException ex) { if (LOG.isDebugEnabled()) { LOG.debug("Worker[ " + workerId + "]: " + "Crypto token offline trying to create key usage counter"); } } } } if (workerId == 0 || getWorkers( GlobalConfiguration.WORKERTYPE_SERVICES).contains(new Integer( workerId))) { serviceTimerSession.unload(workerId); serviceTimerSession.load(workerId); } StatisticsManager.flush(workerId); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#activateSigner(int, java.lang.String) */ @Override public void activateSigner(int signerId, String authenticationCode) throws CryptoTokenAuthenticationFailureException, CryptoTokenOfflineException, InvalidWorkerIdException { IWorker worker = workerManagerSession.getWorker(signerId, globalConfigurationSession); if (worker == null) { throw new InvalidWorkerIdException("Given SignerId " + signerId + " doesn't exist"); } if (!(worker instanceof IProcessable)) { throw new InvalidWorkerIdException( "Worker exists but isn't a signer."); } IProcessable signer = (IProcessable) worker; signer.activateSigner(authenticationCode); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#deactivateSigner(int) */ @Override public boolean deactivateSigner(int signerId) throws CryptoTokenOfflineException, InvalidWorkerIdException { IWorker worker = workerManagerSession.getWorker(signerId, globalConfigurationSession); if (worker == null) { throw new InvalidWorkerIdException("Given SignerId " + signerId + " doesn't exist"); } if (!(worker instanceof IProcessable)) { throw new InvalidWorkerIdException( "Worker exists but isn't a signer."); } IProcessable signer = (IProcessable) worker; return signer.deactivateSigner(); } @Override public String generateSignerKey(final int signerId, String keyAlgorithm, String keySpec, String alias, final char[] authCode) throws CryptoTokenOfflineException, InvalidWorkerIdException, IllegalArgumentException { return generateSignerKey(new AdminInfo("CLI user", null, null), signerId, keyAlgorithm, keySpec, alias, authCode); } /** * @see IWorkerSession#generateSignerKey(int, java.lang.String, * java.lang.String, java.lang.String, char[]) */ @Override public String generateSignerKey(final AdminInfo adminInfo, final int signerId, String keyAlgorithm, String keySpec, String alias, final char[] authCode) throws CryptoTokenOfflineException, InvalidWorkerIdException, IllegalArgumentException { IWorker worker = workerManagerSession.getWorker(signerId, globalConfigurationSession); if (worker == null) { throw new InvalidWorkerIdException("Given SignerId " + signerId + " doesn't exist"); } if (!(worker instanceof IProcessable)) { throw new InvalidWorkerIdException( "Worker exists but isn't a signer."); } final IProcessable signer = (IProcessable) worker; final WorkerConfig config = worker.getConfig(); if (keyAlgorithm == null) { keyAlgorithm = config.getProperty("KEYALG"); } if (keySpec == null) { keySpec = config.getProperty("KEYSPEC"); } if (alias == null) { final String currentAlias = config.getProperty("DEFAULTKEY"); if (currentAlias == null) { throw new IllegalArgumentException("No key alias specified"); } else { alias = nextAliasInSequence(currentAlias); } } signer.generateKey(keyAlgorithm, keySpec, alias, authCode); final HashMap auditMap = new HashMap(); auditMap.put("KEYALG", keyAlgorithm); auditMap.put("KEYSPEC", keySpec); auditMap.put("KEYALIAS", alias); auditLog(adminInfo, SignServerEventTypes.KEYGEN, SignServerModuleTypes.KEY_MANAGEMENT, String.valueOf(signerId), auditMap); return alias; } static String nextAliasInSequence(final String currentAlias) { String prefix = currentAlias; String nextSequence = "2"; final String[] entry = currentAlias.split("[0-9]+$"); if (entry.length == 1) { prefix = entry[0]; final String currentSequence = currentAlias.substring(prefix.length()); final int sequenceChars = currentSequence.length(); if (sequenceChars > 0) { final long nextSequenceNumber = Long.parseLong(currentSequence) + 1; final String nextSequenceNumberString = String.valueOf(nextSequenceNumber); if (sequenceChars > nextSequenceNumberString.length()) { nextSequence = currentSequence.substring(0, sequenceChars - nextSequenceNumberString.length()) + nextSequenceNumberString; } else { nextSequence = nextSequenceNumberString; } } } return prefix + nextSequence; } @Override public Collection testKey(final int signerId, String alias, char[] authCode) throws CryptoTokenOfflineException, InvalidWorkerIdException, KeyStoreException { return testKey(new AdminInfo("CLI user", null, null), signerId, alias, authCode); } /** * @see IWorkerSession#testKey(int, java.lang.String, char[]) */ @Override public Collection testKey(final AdminInfo adminInfo, final int signerId, String alias, char[] authCode) throws CryptoTokenOfflineException, InvalidWorkerIdException, KeyStoreException { IWorker worker = workerManagerSession.getWorker(signerId, globalConfigurationSession); if (worker == null) { throw new InvalidWorkerIdException("Given SignerId " + signerId + " doesn't exist"); } if (!(worker instanceof IProcessable)) { throw new InvalidWorkerIdException( "Worker exists but isn't a signer."); } final IProcessable signer = (IProcessable) worker; final WorkerConfig config = worker.getConfig(); if (alias == null) { alias = config.getProperty("DEFAULTKEY"); } final Collection result = signer.testKey(alias, authCode); final HashMap auditMap = new HashMap(); auditMap.put("KEYALIAS", alias); auditMap.put("TESTRESULTS", createResultsReport(result)); auditLog(adminInfo, SignServerEventTypes.KEYTEST, SignServerModuleTypes.KEY_MANAGEMENT, String.valueOf(signerId), auditMap); return result; } /* (non-Javadoc) * @see org.signserver.ejb.IWorkerSession#getCurrentSignerConfig(int) */ @Override public WorkerConfig getCurrentWorkerConfig(int signerId) { return getWorkerConfig(signerId); } @Override public void setWorkerProperty(int workerId, String key, String value) { setWorkerProperty(new AdminInfo("CLI user", null, null), workerId, key, value); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#setWorkerProperty(int, java.lang.String, java.lang.String) */ @Override public void setWorkerProperty(final AdminInfo adminInfo, int workerId, String key, String value) { WorkerConfig config = getWorkerConfig(workerId); config.setProperty(key.toUpperCase(), value); setWorkerConfig(adminInfo, workerId, config, null, null); auditLogWorkerPropertyChange(adminInfo, workerId, key, value); } private void auditLogCertInstalled(final AdminInfo adminInfo, final int workerId, final String value, final String scope, final String node) { final HashMap auditMap = new HashMap(); auditMap.put("CERTIFICATE", value); auditMap.put("SCOPE", scope); if ("NODE".equalsIgnoreCase(scope)) { auditMap.put("NODE", node); } auditLog(adminInfo, SignServerEventTypes.CERTINSTALLED, SignServerModuleTypes.WORKER_CONFIG, String.valueOf(workerId), auditMap); } private void auditLogCertChainInstalled(final AdminInfo adminInfo, final int workerId, final String value, final String scope, final String node) { final HashMap auditMap = new HashMap(); auditMap.put("CERTIFICATECHAIN", value); auditMap.put("SCOPE", scope); if ("NODE".equalsIgnoreCase(scope)) { auditMap.put("NODE", node); } auditLog(adminInfo, SignServerEventTypes.CERTCHAININSTALLED, SignServerModuleTypes.WORKER_CONFIG, String.valueOf(workerId), auditMap); } @Override public boolean removeWorkerProperty(int workerId, String key) { return removeWorkerProperty(new AdminInfo("CLI user", null, null), workerId, key); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#removeWorkerProperty(int, java.lang.String) */ @Override public boolean removeWorkerProperty(final AdminInfo adminInfo, int workerId, String key) { final boolean result; WorkerConfig config = getWorkerConfig(workerId); result = config.removeProperty(key.toUpperCase()); if (config.getProperties().size() == 0) { workerConfigService.removeWorkerConfig(workerId); LOG.debug("WorkerConfig is empty and therefore removed."); auditLog(adminInfo, SignServerEventTypes.SET_WORKER_CONFIG, SignServerModuleTypes.WORKER_CONFIG, String.valueOf(workerId)); } else { setWorkerConfig(adminInfo, workerId, config, null, null); } auditLogWorkerPropertyChange(adminInfo, workerId, key, ""); return result; } private void auditLogWorkerPropertyChange(final AdminInfo adminInfo, final int workerId, final String key, final String value) { if ("DEFAULTKEY".equalsIgnoreCase(key)) { final HashMap auditMap = new HashMap(); auditMap.put("KEYALIAS", value); auditMap.put("SCOPE", "GLOBAL"); auditLog(adminInfo, SignServerEventTypes.KEYSELECTED, SignServerModuleTypes.WORKER_CONFIG, String.valueOf(workerId), auditMap); } else if (key != null && key.lastIndexOf(".") != -1 && key.substring(key.lastIndexOf(".")).equalsIgnoreCase(".DEFAULTKEY")) { final HashMap auditMap = new HashMap(); auditMap.put("KEYALIAS", value); auditMap.put("SCOPE", "NODE"); auditMap.put("NODE", key.substring(0, key.lastIndexOf("."))); auditLog(adminInfo, SignServerEventTypes.KEYSELECTED, SignServerModuleTypes.WORKER_CONFIG, String.valueOf(workerId), auditMap); } else if (ProcessableConfig.SIGNERCERT.equalsIgnoreCase(key)) { auditLogCertInstalled(adminInfo, workerId, value, "GLOBAL", null); } else if (key != null && key.lastIndexOf(".") != -1 && key.substring(key.lastIndexOf(".")).equalsIgnoreCase("." + ProcessableConfig.SIGNERCERT)) { auditLogCertInstalled(adminInfo, workerId, value, "NODE", key.substring(0, key.lastIndexOf("."))); } else if (ProcessableConfig.SIGNERCERTCHAIN.equalsIgnoreCase(key)) { auditLogCertChainInstalled(adminInfo, workerId, value, "GLOBAL", null); } else if (key != null && key.lastIndexOf(".") != -1 && key.substring(key.lastIndexOf(".")).equalsIgnoreCase("." + ProcessableConfig.SIGNERCERTCHAIN)) { auditLogCertChainInstalled(adminInfo, workerId, value, "NODE", key.substring(0, key.lastIndexOf("."))); } } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#getAuthorizedClients(int) */ @Override public Collection getAuthorizedClients(int signerId) { return new ProcessableConfig(getWorkerConfig(signerId)). getAuthorizedClients(); } @Override public void addAuthorizedClient(int signerId, AuthorizedClient authClient) { addAuthorizedClient(new AdminInfo("CLI user", null, null), signerId, authClient); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#addAuthorizedClient(int, org.signserver.common.AuthorizedClient) */ @Override public void addAuthorizedClient(final AdminInfo adminInfo, int signerId, AuthorizedClient authClient) { WorkerConfig config = getWorkerConfig(signerId); (new ProcessableConfig(config)).addAuthorizedClient(authClient); setWorkerConfig(adminInfo, signerId, config, "added:authorized_client", "SN: " + authClient.getCertSN() + ", issuer DN: " + authClient.getIssuerDN()); } @Override public boolean removeAuthorizedClient(int signerId, AuthorizedClient authClient) { return removeAuthorizedClient(new AdminInfo("CLI user", null, null), signerId, authClient); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#removeAuthorizedClient(int, org.signserver.common.AuthorizedClient) */ @Override public boolean removeAuthorizedClient(final AdminInfo adminInfo, int signerId, AuthorizedClient authClient) { boolean result = false; WorkerConfig config = getWorkerConfig(signerId); result = (new ProcessableConfig(config)).removeAuthorizedClient( authClient); setWorkerConfig(adminInfo, signerId, config, "removed:authorized_client", "SN: " + authClient.getCertSN() + ", issuer DN: " + authClient.getIssuerDN()); return result; } @Override public ICertReqData getCertificateRequest(final int signerId, final ISignerCertReqInfo certReqInfo, final boolean explicitEccParameters) throws CryptoTokenOfflineException, InvalidWorkerIdException { return getCertificateRequest(new AdminInfo("CLI user", null, null), signerId, certReqInfo, explicitEccParameters); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#getCertificateRequest(int, org.signserver.common.ISignerCertReqInfo) */ @Override public ICertReqData getCertificateRequest(final AdminInfo adminInfo, final int signerId, final ISignerCertReqInfo certReqInfo, final boolean explicitEccParameters) throws CryptoTokenOfflineException, InvalidWorkerIdException { return getCertificateRequest(adminInfo, signerId, certReqInfo, explicitEccParameters, true); } @Override public ICertReqData getCertificateRequest(int signerId, ISignerCertReqInfo certReqInfo, final boolean explicitEccParameters, final boolean defaultKey) throws CryptoTokenOfflineException, InvalidWorkerIdException { return getCertificateRequest(new AdminInfo("CLI user", null, null), signerId, certReqInfo, explicitEccParameters, defaultKey); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#getCertificateRequest(int, org.signserver.common.ISignerCertReqInfo) */ @Override public ICertReqData getCertificateRequest(final AdminInfo adminInfo, int signerId, ISignerCertReqInfo certReqInfo, final boolean explicitEccParameters, final boolean defaultKey) throws CryptoTokenOfflineException, InvalidWorkerIdException { if (LOG.isTraceEnabled()) { LOG.trace(">getCertificateRequest: signerId=" + signerId); } IWorker worker = workerManagerSession.getWorker(signerId, globalConfigurationSession); if (worker == null) { throw new InvalidWorkerIdException("Given SignerId " + signerId + " doesn't exist"); } if (!(worker instanceof IProcessable)) { throw new InvalidWorkerIdException( "Worker exists but isn't a signer."); } IProcessable processable = (IProcessable) worker; if (LOG.isDebugEnabled()) { LOG.debug("Found processable worker of type: " + processable. getClass().getName()); } ICertReqData ret = processable.genCertificateRequest(certReqInfo, explicitEccParameters, defaultKey); final HashMap auditMap = new HashMap(); final String csr; if (ret instanceof Base64SignerCertReqData) { csr = new String(((Base64SignerCertReqData) ret).getBase64CertReq()); } else { csr = ret.toString(); } auditMap.put("CSR", csr); auditLog(adminInfo, SignServerEventTypes.GENCSR, SignServerModuleTypes.KEY_MANAGEMENT, String.valueOf(signerId), auditMap); if (LOG.isTraceEnabled()) { LOG.trace(" signerCerts, String scope) throws CertificateException { uploadSignerCertificateChain(new AdminInfo("CLI user", null, null), signerId, signerCerts, scope); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#uploadSignerCertificateChain(int, java.util.Collection, java.lang.String) */ @Override public void uploadSignerCertificateChain(final AdminInfo adminInfo, int signerId, Collection signerCerts, String scope) throws CertificateException { WorkerConfig config = getWorkerConfig(signerId); ArrayList certs = new ArrayList(); Iterator iter = signerCerts.iterator(); while(iter.hasNext()){ X509Certificate cert; cert = (X509Certificate) CertTools.getCertfromByteArray(iter.next()); certs.add(cert); } // Collections.reverse(certs); // TODO: Why? (new ProcessableConfig( config)).setSignerCertificateChain(certs, scope); setWorkerConfig(adminInfo, signerId, config, null, null); final boolean scopeGlobal = GlobalConfiguration.SCOPE_GLOBAL.equalsIgnoreCase(scope); auditLogCertChainInstalled(adminInfo, signerId, new String (CertTools.getPEMFromCerts(certs)), scopeGlobal ? "GLOBAL" : "NODE", scopeGlobal ? null : WorkerConfig.getNodeId()); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#genFreeWorkerId() */ @Override public int genFreeWorkerId() { /* Collection ids = getWorkers( GlobalConfiguration.WORKERTYPE_ALL); int max = 0; Iterator iter = ids.iterator(); while (iter.hasNext()) { Integer id = iter.next(); if (id.intValue() > max) { max = id.intValue(); } } return max + 1; */ return DBConnector.getInstances().getWorkerUUID(); } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#findArchiveDataFromArchiveId(int, java.lang.String) */ @Override public List findArchiveDataFromArchiveId(int signerId, String archiveId) { final LinkedList result = new LinkedList(); if (archiveDataService == null) { if (LOG.isDebugEnabled()) { LOG.debug("Archiving to database is not supported when running without database"); } } else { final List list = archiveDataService.findAllByArchiveId(signerId, archiveId); for (Object o : list) { if (o instanceof ArchiveDataBean) { final ArchiveDataBean adb = (ArchiveDataBean) o; result.add(adb.getArchiveDataVO()); } } } return result; } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#findArchiveDatasFromRequestIP(int, java.lang.String) */ @Override public List findArchiveDatasFromRequestIP(int signerId, String requestIP) { List retval = new LinkedList(); if (archiveDataService == null) { if (LOG.isDebugEnabled()) { LOG.debug("Archiving to database is not supported when running without database"); } } else { Collection archives = archiveDataService.findAllByRequestIP(signerId, requestIP); for (ArchiveDataBean archive : archives) { retval.add(archive.getArchiveDataVO()); } } return retval; } /* (non-Javadoc) * @see org.signserver.ejb.interfaces.IWorkerSession#findArchiveDatasFromRequestCertificate(int, java.math.BigInteger, java.lang.String) */ @Override public List findArchiveDatasFromRequestCertificate( int signerId, BigInteger requestCertSerialnumber, String requestCertIssuerDN) { ArrayList retval = new ArrayList(); if (archiveDataService == null) { if (LOG.isDebugEnabled()) { LOG.debug("Archiving to database is not supported when running without database"); } } else { String issuerDN = CertTools.stringToBCDNString(requestCertIssuerDN); String serialNumber = requestCertSerialnumber.toString(16); Collection archives = archiveDataService. findAllByRequestCertificate(signerId, issuerDN, serialNumber); for (ArchiveDataBean archive : archives) { retval.add(archive.getArchiveDataVO()); } } return retval; } private WorkerConfig getWorkerConfig(int workerId) { return workerConfigService.getWorkerProperties(workerId); } private String generateTransactionID() { return UUID.randomUUID().toString(); } /** * @see org.signserver.ejb.interfaces.IWorkerSession#getWorkers(int) */ @Override public List getWorkers(int workerType) { return workerManagerSession.getWorkers(workerType, globalConfigurationSession); } private void auditLog(final AdminInfo adminInfo, SignServerEventTypes eventType, SignServerModuleTypes module, final String workerId) { auditLog(adminInfo, eventType, module, workerId, Collections.emptyMap()); } private void auditLog(final AdminInfo adminInfo, SignServerEventTypes eventType, SignServerModuleTypes module, final String workerId, Map additionalDetails) { try { final String serialNo = adminInfo.getCertSerialNumber() == null ? null : adminInfo.getCertSerialNumber().toString(16); logSession.log(eventType, EventStatus.SUCCESS, module, SignServerServiceTypes.SIGNSERVER, adminInfo.getSubjectDN(), adminInfo.getIssuerDN(), serialNo, workerId, additionalDetails); } catch (AuditRecordStorageException ex) { LOG.error("Audit log failure", ex); throw new EJBException("Audit log failure", ex); } } private void setWorkerConfig(final AdminInfo adminInfo, final int workerId, final WorkerConfig config, final String additionalLogKey, final String additionalLogValue) { final WorkerConfig oldConfig = workerConfigService.getWorkerProperties(workerId); Map configChanges = WorkerConfig.propertyDiff(oldConfig, config); if (additionalLogKey != null) { configChanges.put(additionalLogKey, additionalLogValue); } auditLog(adminInfo, SignServerEventTypes.SET_WORKER_CONFIG, SignServerModuleTypes.WORKER_CONFIG, String.valueOf(workerId), configChanges); workerConfigService.setWorkerConfig(workerId, config); } private String createResultsReport(final Collection results) { final StringBuilder buff = new StringBuilder(); for (KeyTestResult result : results) { buff.append(result.toString()).append("\n"); } return buff.toString(); } @Override public List selectAuditLogs(AdminInfo adminInfo, int startIndex, int max, QueryCriteria criteria, String logDeviceId) throws AuthorizationDeniedException { return auditorSession.selectAuditLogs(new AlwaysAllowLocalAuthenticationToken(new UsernamePrincipal(adminInfo.getSubjectDN())), startIndex, max, criteria, logDeviceId); } @Override public List selectAuditLogs(int startIndex, int max, QueryCriteria criteria, String logDeviceId) throws AuthorizationDeniedException { return selectAuditLogs(new AdminInfo("CLI user", null, null), startIndex, max, criteria, logDeviceId); } }