diff options
author | Endi S. Dewata <edewata@redhat.com> | 2014-02-20 16:58:34 -0500 |
---|---|---|
committer | Endi S. Dewata <edewata@redhat.com> | 2014-02-28 12:54:05 -0500 |
commit | d6d197d1a4513a3262a59c3989845f69285a38ad (patch) | |
tree | 4c9becb4c5dc3ef66cf4be6c0bdd2406ab779f03 /base/kra | |
parent | 819fd31d34b3159e895f15bfad41bf483adca79e (diff) | |
download | pki-d6d197d1a4513a3262a59c3989845f69285a38ad.tar.gz pki-d6d197d1a4513a3262a59c3989845f69285a38ad.tar.xz pki-d6d197d1a4513a3262a59c3989845f69285a38ad.zip |
Reorganized REST service classes.
The REST service classes have been moved into org.dogtagpki.server
namespace. A new upgrade script has been added to update existing
instances.
Ticket #114
Diffstat (limited to 'base/kra')
-rw-r--r-- | base/kra/shared/webapps/kra/WEB-INF/web.xml | 2 | ||||
-rw-r--r-- | base/kra/src/CMakeLists.txt | 45 | ||||
-rw-r--r-- | base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java | 2 | ||||
-rw-r--r-- | base/kra/src/com/netscape/kra/SecurityDataService.java | 2 | ||||
-rw-r--r-- | base/kra/src/com/netscape/kra/SymKeyGenService.java | 4 | ||||
-rw-r--r-- | base/kra/src/org/dogtagpki/server/kra/rest/KRAApplication.java (renamed from base/kra/src/com/netscape/kra/KeyRecoveryAuthorityApplication.java) | 31 | ||||
-rw-r--r-- | base/kra/src/org/dogtagpki/server/kra/rest/KeyRequestService.java | 463 | ||||
-rw-r--r-- | base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java | 560 |
8 files changed, 1079 insertions, 30 deletions
diff --git a/base/kra/shared/webapps/kra/WEB-INF/web.xml b/base/kra/shared/webapps/kra/WEB-INF/web.xml index d27d88d71..0a5f92ae2 100644 --- a/base/kra/shared/webapps/kra/WEB-INF/web.xml +++ b/base/kra/shared/webapps/kra/WEB-INF/web.xml @@ -830,7 +830,7 @@ <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> - <param-value>com.netscape.kra.KeyRecoveryAuthorityApplication</param-value> + <param-value>org.dogtagpki.server.kra.rest.KRAApplication</param-value> </init-param> </servlet> diff --git a/base/kra/src/CMakeLists.txt b/base/kra/src/CMakeLists.txt index ccbc6a6c3..bcac9704c 100644 --- a/base/kra/src/CMakeLists.txt +++ b/base/kra/src/CMakeLists.txt @@ -46,6 +46,21 @@ find_file(LDAPJDK_JAR /usr/share/java ) +# '${JAVA_LIB_INSTALL_DIR}' jars +find_file(JSS_JAR + NAMES + jss4.jar + PATHS + ${JAVA_LIB_INSTALL_DIR} +) + +find_file(COMMONS_CODEC_JAR + NAMES + commons-codec.jar + PATHS + /usr/share/java +) + find_file(JAXRS_API_JAR NAMES jaxrs-api.jar @@ -53,18 +68,25 @@ find_file(JAXRS_API_JAR ${RESTEASY_LIB} ) -# '${JAVA_LIB_INSTALL_DIR}' jars -find_file(JSS_JAR +find_file(RESTEASY_JAXRS_JAR NAMES - jss4.jar + resteasy-jaxrs.jar PATHS - ${JAVA_LIB_INSTALL_DIR} + ${RESTEASY_LIB} ) -find_file(COMMONS_CODEC_JAR +find_file(RESTEASY_ATOM_PROVIDER_JAR NAMES - commons-codec.jar + resteasy-atom-provider.jar PATHS + ${RESTEASY_LIB} +) + +find_file(SERVLET_JAR + NAMES + servlet.jar + PATHS + ${JAVA_LIB_INSTALL_DIR} /usr/share/java ) @@ -87,11 +109,15 @@ find_file(COMMONS_LANG_JAR javac(pki-kra-classes SOURCES com/netscape/kra/*.java + org/dogtagpki/server/kra/*.java CLASSPATH - ${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR} + ${COMMONS_CODEC_JAR} ${COMMONS_LANG_JAR} + ${JSS_JAR} ${SYMKEY_JAR} + ${LDAPJDK_JAR} + ${SERVLET_JAR} + ${JAXRS_API_JAR} ${RESTEASY_JAXRS_JAR} ${RESTEASY_ATOM_PROVIDER_JAR} ${PKI_CMSUTIL_JAR} ${PKI_NSUTIL_JAR} - ${LDAPJDK_JAR} ${JAXRS_API_JAR} - ${JSS_JAR} ${COMMONS_CODEC_JAR} ${COMMONS_LANG_JAR} ${SYMKEY_JAR} + ${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR} OUTPUT_DIR ${CMAKE_BINARY_DIR}/classes DEPENDS @@ -114,6 +140,7 @@ jar(pki-kra-jar ${CMAKE_BINARY_DIR}/classes FILES com/netscape/kra/*.class + org/dogtagpki/server/kra/*.class DEPENDS pki-kra-classes ) diff --git a/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java index f3b7709e7..269fa8df4 100644 --- a/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java +++ b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java @@ -30,6 +30,7 @@ import java.util.Random; import javax.crypto.spec.RC2ParameterSpec; +import org.dogtagpki.server.kra.rest.KeyRequestService; import org.mozilla.jss.CryptoManager; import org.mozilla.jss.asn1.OCTET_STRING; import org.mozilla.jss.crypto.Cipher; @@ -64,7 +65,6 @@ import com.netscape.certsrv.request.IService; import com.netscape.certsrv.request.RequestId; import com.netscape.certsrv.security.IStorageKeyUnit; import com.netscape.certsrv.security.ITransportKeyUnit; -import com.netscape.cms.servlet.request.KeyRequestService; import com.netscape.cmscore.dbs.KeyRecord; import com.netscape.cmsutil.util.Utils; diff --git a/base/kra/src/com/netscape/kra/SecurityDataService.java b/base/kra/src/com/netscape/kra/SecurityDataService.java index b9620f5d2..8201414db 100644 --- a/base/kra/src/com/netscape/kra/SecurityDataService.java +++ b/base/kra/src/com/netscape/kra/SecurityDataService.java @@ -19,6 +19,7 @@ package com.netscape.kra; import java.math.BigInteger; +import org.dogtagpki.server.kra.rest.KeyRequestService; import org.mozilla.jss.crypto.SymmetricKey; import com.netscape.certsrv.apps.CMS; @@ -35,7 +36,6 @@ import com.netscape.certsrv.request.IService; import com.netscape.certsrv.request.RequestId; import com.netscape.certsrv.security.IStorageKeyUnit; import com.netscape.certsrv.security.ITransportKeyUnit; -import com.netscape.cms.servlet.request.KeyRequestService; import com.netscape.cmscore.dbs.KeyRecord; import com.netscape.cmsutil.util.Utils; diff --git a/base/kra/src/com/netscape/kra/SymKeyGenService.java b/base/kra/src/com/netscape/kra/SymKeyGenService.java index d1e60fa70..774bbcda9 100644 --- a/base/kra/src/com/netscape/kra/SymKeyGenService.java +++ b/base/kra/src/com/netscape/kra/SymKeyGenService.java @@ -45,7 +45,7 @@ import com.netscape.certsrv.request.IRequest; import com.netscape.certsrv.request.IService; import com.netscape.certsrv.request.RequestId; import com.netscape.certsrv.security.IStorageKeyUnit; -import com.netscape.cms.servlet.request.KeyRequestService; +import com.netscape.cms.servlet.key.KeyRequestDAO; import com.netscape.cmscore.dbs.KeyRecord; /** @@ -113,7 +113,7 @@ public class SymKeyGenService implements IService { } CryptoToken token = mStorageUnit.getToken(); - KeyGenAlgorithm kgAlg = KeyRequestService.KEYGEN_ALGORITHMS.get(algorithm); + KeyGenAlgorithm kgAlg = KeyRequestDAO.KEYGEN_ALGORITHMS.get(algorithm); if (kgAlg == null) { throw new EBaseException("Invalid algorithm"); } diff --git a/base/kra/src/com/netscape/kra/KeyRecoveryAuthorityApplication.java b/base/kra/src/org/dogtagpki/server/kra/rest/KRAApplication.java index 0b311427f..ea8a6c038 100644 --- a/base/kra/src/com/netscape/kra/KeyRecoveryAuthorityApplication.java +++ b/base/kra/src/org/dogtagpki/server/kra/rest/KRAApplication.java @@ -1,33 +1,32 @@ -package com.netscape.kra; +package org.dogtagpki.server.kra.rest; import java.util.LinkedHashSet; import java.util.Set; import javax.ws.rs.core.Application; +import org.dogtagpki.server.rest.ACLInterceptor; +import org.dogtagpki.server.rest.AccountService; +import org.dogtagpki.server.rest.AuditService; +import org.dogtagpki.server.rest.AuthMethodInterceptor; +import org.dogtagpki.server.rest.GroupService; +import org.dogtagpki.server.rest.SecurityDomainService; +import org.dogtagpki.server.rest.SelfTestService; +import org.dogtagpki.server.rest.SystemCertService; +import org.dogtagpki.server.rest.SystemConfigService; +import org.dogtagpki.server.rest.UserService; + import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.base.PKIException; -import com.netscape.cms.authorization.ACLInterceptor; -import com.netscape.cms.authorization.AuthMethodInterceptor; -import com.netscape.cms.servlet.account.AccountService; -import com.netscape.cms.servlet.admin.GroupService; -import com.netscape.cms.servlet.admin.SystemCertService; -import com.netscape.cms.servlet.admin.UserService; -import com.netscape.cms.servlet.csadmin.SecurityDomainService; -import com.netscape.cms.servlet.csadmin.SystemConfigService; -import com.netscape.cms.servlet.key.KeyService; -import com.netscape.cms.servlet.request.KeyRequestService; -import com.netscape.cmscore.logging.AuditService; -import com.netscape.cmscore.selftests.SelfTestService; - -public class KeyRecoveryAuthorityApplication extends Application { + +public class KRAApplication extends Application { private Set<Object> singletons = new LinkedHashSet<Object>(); private Set<Class<?>> classes = new LinkedHashSet<Class<?>>(); - public KeyRecoveryAuthorityApplication() { + public KRAApplication() { // account classes.add(AccountService.class); diff --git a/base/kra/src/org/dogtagpki/server/kra/rest/KeyRequestService.java b/base/kra/src/org/dogtagpki/server/kra/rest/KeyRequestService.java new file mode 100644 index 000000000..4f3ef57af --- /dev/null +++ b/base/kra/src/org/dogtagpki/server/kra/rest/KeyRequestService.java @@ -0,0 +1,463 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2011 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +package org.dogtagpki.server.kra.rest; + +import java.lang.reflect.InvocationTargetException; +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.cert.CertificateException; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import netscape.security.x509.X509CertImpl; + +import org.mozilla.jss.crypto.SymmetricKey; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.BadRequestException; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.PKIException; +import com.netscape.certsrv.base.ResourceMessage; +import com.netscape.certsrv.dbs.keydb.KeyId; +import com.netscape.certsrv.key.KeyArchivalRequest; +import com.netscape.certsrv.key.KeyRecoveryRequest; +import com.netscape.certsrv.key.KeyRequestInfo; +import com.netscape.certsrv.key.KeyRequestInfoCollection; +import com.netscape.certsrv.key.KeyRequestResource; +import com.netscape.certsrv.key.KeyRequestResponse; +import com.netscape.certsrv.key.SymKeyGenerationRequest; +import com.netscape.certsrv.kra.IKeyRecoveryAuthority; +import com.netscape.certsrv.kra.IKeyService; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestNotFoundException; +import com.netscape.cms.servlet.base.PKIService; +import com.netscape.cms.servlet.key.KeyRequestDAO; +import com.netscape.cmsutil.ldap.LDAPUtil; +import com.netscape.cmsutil.util.Utils; + +/** + * @author alee + * + */ +public class KeyRequestService extends PKIService implements KeyRequestResource { + + @Context + private UriInfo uriInfo; + + @Context + private HttpHeaders headers; + + @Context + private Request request; + + @Context + private HttpServletRequest servletRequest; + + private static final String LOGGING_SIGNED_AUDIT_SECURITY_DATA_ARCHIVAL_REQUEST = + "LOGGING_SIGNED_AUDIT_SECURITY_DATA_ARCHIVAL_REQUEST_4"; + + private static final String LOGGING_SIGNED_AUDIT_SYMKEY_GENERATION_REQUEST = + "LOGGING_SIGNED_AUDIT_SYMKEY_GENERATION_REQUEST_4"; + + private static final String LOGGING_SIGNED_AUDIT_SECURITY_DATA_RECOVERY_REQUEST = + "LOGGING_SIGNED_AUDIT_SECURITY_DATA_RECOVERY_REQUEST_4"; + + private static final String LOGGING_SIGNED_AUDIT_SECURITY_DATA_RECOVERY_REQUEST_STATE_CHANGE = + "LOGGING_SIGNED_AUDIT_SECURITY_DATA_RECOVERY_REQUEST_STATE_CHANGE_4"; + + public static final int DEFAULT_START = 0; + public static final int DEFAULT_PAGESIZE = 20; + public static final int DEFAULT_MAXRESULTS = 100; + public static final int DEFAULT_MAXTIME = 10; + + private IKeyRecoveryAuthority kra; + private IRequestQueue queue; + private IKeyService service; + + public static final Map<String, SymmetricKey.Type> SYMKEY_TYPES; + static { + SYMKEY_TYPES = new HashMap<String, SymmetricKey.Type>(); + SYMKEY_TYPES.put(KeyRequestResource.DES_ALGORITHM, SymmetricKey.DES); + SYMKEY_TYPES.put(KeyRequestResource.DESEDE_ALGORITHM, SymmetricKey.DES3); + SYMKEY_TYPES.put(KeyRequestResource.DES3_ALGORITHM, SymmetricKey.DES3); + SYMKEY_TYPES.put(KeyRequestResource.RC2_ALGORITHM, SymmetricKey.RC2); + SYMKEY_TYPES.put(KeyRequestResource.RC4_ALGORITHM, SymmetricKey.RC4); + SYMKEY_TYPES.put(KeyRequestResource.AES_ALGORITHM, SymmetricKey.AES); + } + + public KeyRequestService() { + kra = ( IKeyRecoveryAuthority ) CMS.getSubsystem( "kra" ); + queue = kra.getRequestQueue(); + service = (IKeyService) kra; + } + + /** + * Used to retrieve key request info for a specific request + */ + @Override + public Response getRequestInfo(RequestId id) { + if (id == null) { + CMS.debug("getRequestInfo: is is null"); + throw new BadRequestException("Unable to get Request: invalid ID"); + } + // auth and authz + KeyRequestDAO dao = new KeyRequestDAO(); + KeyRequestInfo info; + try { + info = dao.getRequest(id, uriInfo); + } catch (EBaseException e) { + // log error + e.printStackTrace(); + throw new PKIException(e.getMessage(), e); + } + if (info == null) { + // request does not exist + throw new RequestNotFoundException(id); + } + return createOKResponse(info); + } + + public Response archiveKey(KeyArchivalRequest data) { + // auth and authz + // Catch this before internal server processing has to deal with it + + if (data == null || data.getClientKeyId() == null || data.getDataType() == null) { + throw new BadRequestException("Invalid key archival request."); + } + + if (data.getWrappedPrivateData() != null) { + if (data.getTransWrappedSessionKey() == null || + data.getAlgorithmOID() == null || + data.getSymmetricAlgorithmParams() == null) { + throw new BadRequestException( + "Invalid key archival request. " + + "Missing wrapped session key, algoriithmOIS or symmetric key parameters"); + } + } else if (data.getPKIArchiveOptions() == null) { + throw new BadRequestException( + "Invalid key archival request. No data to archive"); + } + + if (data.getDataType().equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) { + if ((data.getKeyAlgorithm() == null) || + (! SYMKEY_TYPES.containsKey(data.getKeyAlgorithm()))) { + throw new BadRequestException("Invalid key archival request. Bad algorithm."); + } + } + + KeyRequestDAO dao = new KeyRequestDAO(); + KeyRequestResponse response; + try { + response = dao.submitRequest(data, uriInfo); + auditArchivalRequestMade(response.getRequestInfo().getRequestId(), ILogger.SUCCESS, data.getClientKeyId()); + + return createCreatedResponse(response, new URI(response.getRequestInfo().getRequestURL())); + + } catch (EBaseException | URISyntaxException e) { + e.printStackTrace(); + auditArchivalRequestMade(null, ILogger.FAILURE, data.getClientKeyId()); + throw new PKIException(e.toString()); + } + } + + public Response recoverKey(KeyRecoveryRequest data) { + // auth and authz + + //Check for entirely illegal data combination here + //Catch this before the internal server processing has to deal with it + //If data has been provided, we need at least the wrapped session key, + //or the command is invalid. + + if (data == null) { + throw new BadRequestException("Invalid request."); + } + if (data.getCertificate() == null && + data.getTransWrappedSessionKey() == null && + data.getSessionWrappedPassphrase() != null) { + throw new BadRequestException("No wrapped session key."); + } + KeyRequestDAO dao = new KeyRequestDAO(); + KeyRequestResponse response; + try { + response = (data.getCertificate() != null)? + requestKeyRecovery(data): dao.submitRequest(data, uriInfo); + auditRecoveryRequestMade(response.getRequestInfo().getRequestId(), + ILogger.SUCCESS, data.getKeyId()); + + return createCreatedResponse(response, new URI(response.getRequestInfo().getRequestURL())); + + } catch (EBaseException | URISyntaxException e) { + e.printStackTrace(); + auditRecoveryRequestMade(null, ILogger.FAILURE, data.getKeyId()); + throw new PKIException(e.toString()); + } + } + + private KeyRequestResponse requestKeyRecovery(KeyRecoveryRequest data) { + KeyRequestResponse response = null; + if (data == null) { + throw new BadRequestException("Invalid request."); + } + String keyId = data.getKeyId().toString(); + String b64Certificate = data.getCertificate(); + byte[] certData = Utils.base64decode(b64Certificate); + String agentID = servletRequest.getUserPrincipal().getName(); + String requestId = null; + try { + requestId = service.initAsyncKeyRecovery(new BigInteger(keyId), new X509CertImpl(certData), agentID); + } catch (EBaseException | CertificateException e) { + e.printStackTrace(); + throw new PKIException(e.toString()); + } + IRequest request = null; + try { + request = queue.findRequest(new RequestId(requestId)); + } catch (EBaseException e) { + } + KeyRequestDAO dao = new KeyRequestDAO(); + response = dao.createCMSRequestResponse(request, uriInfo); + + return response; + } + + @Override + public Response approveRequest(RequestId id) { + if (id == null) { + throw new BadRequestException("Invalid request id."); + } + // auth and authz + KeyRequestDAO dao = new KeyRequestDAO(); + try { + IRequest request = queue.findRequest(id); + String type = request.getRequestType(); + if (IRequest.KEYRECOVERY_REQUEST.equals(type)) { + service.addAgentAsyncKeyRecovery(id.toString(), servletRequest.getUserPrincipal().getName()); + auditRecoveryRequestChange(id, ILogger.SUCCESS, "approve"); + } else if (IRequest.SECURITY_DATA_RECOVERY_REQUEST.equals(type)) { + dao.approveRequest(id); + auditRecoveryRequestChange(id, ILogger.SUCCESS, "approve"); + } + } catch (EBaseException e) { + e.printStackTrace(); + auditRecoveryRequestChange(id, ILogger.FAILURE, "approve"); + throw new PKIException(e.toString()); + } + + return createNoContentResponse(); + } + + @Override + public Response rejectRequest(RequestId id) { + if (id == null) { + throw new BadRequestException("Invalid request id."); + } + // auth and authz + KeyRequestDAO dao = new KeyRequestDAO(); + try { + dao.rejectRequest(id); + auditRecoveryRequestChange(id, ILogger.SUCCESS, "reject"); + } catch (EBaseException e) { + e.printStackTrace(); + auditRecoveryRequestChange(id, ILogger.FAILURE, "reject"); + throw new PKIException(e.toString()); + } + + return createNoContentResponse(); + } + + @Override + public Response cancelRequest(RequestId id) { + if (id == null) { + throw new BadRequestException("Invalid request id."); + } + // auth and authz + KeyRequestDAO dao = new KeyRequestDAO(); + try { + dao.cancelRequest(id); + auditRecoveryRequestChange(id, ILogger.SUCCESS, "cancel"); + } catch (EBaseException e) { + e.printStackTrace(); + auditRecoveryRequestChange(id, ILogger.FAILURE, "cancel"); + throw new PKIException(e.toString()); + } + + return createNoContentResponse(); + } + + /** + * Used to generate list of key requests based on the search parameters + */ + @Override + public Response listRequests(String requestState, String requestType, String clientKeyID, + RequestId start, Integer pageSize, Integer maxResults, Integer maxTime) { + // auth and authz + + // get ldap filter + String filter = createSearchFilter(requestState, requestType, clientKeyID); + CMS.debug("listRequests: filter is " + filter); + + start = start == null ? new RequestId(KeyRequestService.DEFAULT_START) : start; + pageSize = pageSize == null ? DEFAULT_PAGESIZE : pageSize; + maxResults = maxResults == null ? DEFAULT_MAXRESULTS : maxResults; + maxTime = maxTime == null ? DEFAULT_MAXTIME : maxTime; + + KeyRequestDAO reqDAO = new KeyRequestDAO(); + KeyRequestInfoCollection requests; + try { + requests = reqDAO.listRequests(filter, start, pageSize, maxResults, maxTime, uriInfo); + } catch (EBaseException e) { + CMS.debug("listRequests: error in obtaining request results" + e); + e.printStackTrace(); + throw new PKIException(e.toString()); + } + return createOKResponse(requests); + } + + private String createSearchFilter(String requestState, String requestType, String clientKeyID) { + String filter = ""; + int matches = 0; + + if ((requestState == null) && (requestType == null) && (clientKeyID == null)) { + filter = "(requeststate=*)"; + return filter; + } + + if (requestState != null) { + filter += "(requeststate=" + LDAPUtil.escapeFilter(requestState) + ")"; + matches ++; + } + + if (requestType != null) { + filter += "(requesttype=" + LDAPUtil.escapeFilter(requestType) + ")"; + matches ++; + } + + if (clientKeyID != null) { + filter += "(clientID=" + LDAPUtil.escapeFilter(clientKeyID) + ")"; + matches ++; + } + + if (matches > 1) { + filter = "(&" + filter + ")"; + } + + return filter; + } + + public void auditRecoveryRequestChange(RequestId requestId, String status, String operation) { + String msg = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_SECURITY_DATA_RECOVERY_REQUEST_STATE_CHANGE, + servletRequest.getUserPrincipal().getName(), + status, + requestId.toString(), + operation); + auditor.log(msg); + } + + public void auditRecoveryRequestMade(RequestId requestId, String status, KeyId dataId) { + String msg = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_SECURITY_DATA_RECOVERY_REQUEST, + servletRequest.getUserPrincipal().getName(), + status, + requestId != null? requestId.toString(): "null", + dataId.toString()); + auditor.log(msg); + } + + public void auditArchivalRequestMade(RequestId requestId, String status, String clientKeyID) { + String msg = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_SECURITY_DATA_ARCHIVAL_REQUEST, + servletRequest.getUserPrincipal().getName(), + status, + requestId != null? requestId.toString(): "null", + clientKeyID); + auditor.log(msg); + } + + public void auditSymKeyGenRequestMade(RequestId requestId, String status, String clientKeyID) { + String msg = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_SYMKEY_GENERATION_REQUEST, + servletRequest.getUserPrincipal().getName(), + status, + requestId != null ? requestId.toString() : "null", + clientKeyID); + auditor.log(msg); + } + + @Override + public Response createRequest(MultivaluedMap<String, String> form) { + ResourceMessage data = new ResourceMessage(form); + return createRequest(data); + } + + @Override + public Response createRequest(ResourceMessage data) { + Object request = null; + try { + Class<?> requestClazz = Class.forName(data.getClassName()); + request = requestClazz.getDeclaredConstructor(ResourceMessage.class).newInstance(data); + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException + | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new BadRequestException("Invalid request class." + e); + } + + if (request instanceof KeyArchivalRequest) { + return archiveKey(new KeyArchivalRequest(data)); + } else if (request instanceof KeyRecoveryRequest) { + return recoverKey(new KeyRecoveryRequest(data)); + } else if (request instanceof SymKeyGenerationRequest) { + return generateSymKey(new SymKeyGenerationRequest(data)); + } else { + throw new BadRequestException("Invalid request class."); + } + } + + public Response generateSymKey(SymKeyGenerationRequest data) { + if (data == null) { + throw new BadRequestException("Invalid key generation request."); + } + + KeyRequestDAO dao = new KeyRequestDAO(); + KeyRequestResponse response; + try { + response = dao.submitRequest(data, uriInfo); + auditSymKeyGenRequestMade(response.getRequestInfo().getRequestId(), ILogger.SUCCESS, + data.getClientKeyId()); + + return createCreatedResponse(response, new URI(response.getRequestInfo().getRequestURL())); + + } catch (EBaseException | URISyntaxException e) { + e.printStackTrace(); + auditArchivalRequestMade(null, ILogger.FAILURE, data.getClientKeyId()); + throw new PKIException(e.toString()); + } + } +} diff --git a/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java b/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java new file mode 100644 index 000000000..93fc53b12 --- /dev/null +++ b/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java @@ -0,0 +1,560 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2011 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +package org.dogtagpki.server.kra.rest; + + +import java.math.BigInteger; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.core.UriInfo; + +import org.jboss.resteasy.plugins.providers.atom.Link; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.BadRequestException; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.HTTPGoneException; +import com.netscape.certsrv.base.PKIException; +import com.netscape.certsrv.base.ResourceNotFoundException; +import com.netscape.certsrv.base.UnauthorizedException; +import com.netscape.certsrv.dbs.EDBRecordNotFoundException; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.dbs.keydb.IKeyRecord; +import com.netscape.certsrv.dbs.keydb.IKeyRepository; +import com.netscape.certsrv.dbs.keydb.KeyId; +import com.netscape.certsrv.key.KeyData; +import com.netscape.certsrv.key.KeyInfo; +import com.netscape.certsrv.key.KeyInfoCollection; +import com.netscape.certsrv.key.KeyNotFoundException; +import com.netscape.certsrv.key.KeyRecoveryRequest; +import com.netscape.certsrv.key.KeyRequestInfo; +import com.netscape.certsrv.key.KeyResource; +import com.netscape.certsrv.kra.IKeyRecoveryAuthority; +import com.netscape.certsrv.kra.IKeyService; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.base.PKIService; +import com.netscape.cms.servlet.key.KeyRequestDAO; +import com.netscape.cmsutil.ldap.LDAPUtil; +import com.netscape.cmsutil.util.Utils; + +/** + * @author alee + * + */ +public class KeyService extends PKIService implements KeyResource { + + @Context + private UriInfo uriInfo; + + @Context + private HttpHeaders headers; + + @Context + private Request request; + + @Context + private HttpServletRequest servletRequest; + + private final static String LOGGING_SIGNED_AUDIT_SECURITY_DATA_RETRIEVE_KEY = + "LOGGING_SIGNED_AUDIT_SECURITY_DATA_RETRIEVE_KEY_5"; + + public static final int DEFAULT_MAXRESULTS = 100; + public static final int DEFAULT_MAXTIME = 10; + public final static int DEFAULT_SIZE = 20; + + private IKeyRepository repo; + private IKeyRecoveryAuthority kra; + private IRequestQueue queue; + private IKeyService service; + + public KeyService() { + kra = ( IKeyRecoveryAuthority ) CMS.getSubsystem( "kra" ); + repo = kra.getKeyRepository(); + queue = kra.getRequestQueue(); + service = (IKeyService) kra; + } + + /** + * Used to retrieve a key + * @param data + * @return + */ + @Override + public Response retrieveKey(KeyRecoveryRequest data) { + if (data == null) { + CMS.debug("retrieveKey: data is null"); + throw new BadRequestException("Cannot retrieve key. Invalid request"); + } + // auth and authz + RequestId requestID = data.getRequestId(); + IRequest request; + try { + request = queue.findRequest(requestID); + } catch (EBaseException e) { + e.printStackTrace(); + auditRetrieveKey(ILogger.FAILURE, requestID, null, e.getMessage()); + throw new PKIException(e.getMessage()); + } + String type = request.getRequestType(); + KeyId keyId = null; + KeyData keyData; + try { + if (IRequest.KEYRECOVERY_REQUEST.equals(type)) { + keyData = recoverKey(data); + } else { + keyId = validateRequest(data); + keyData = getKey(keyId, data); + } + } catch (EBaseException e) { + e.printStackTrace(); + auditRetrieveKey(ILogger.FAILURE, requestID, keyId, e.getMessage()); + throw new PKIException(e.getMessage()); + } + if (keyData == null) { + // no key record + auditRetrieveKey(ILogger.FAILURE, requestID, keyId, "No key record"); + throw new HTTPGoneException("No key record."); + } + auditRetrieveKey(ILogger.SUCCESS, requestID, keyId, "None"); + + return createOKResponse(keyData); + } + + // retrieval - used to test integration with a browser + @Override + public Response retrieveKey(MultivaluedMap<String, String> form) { + KeyRecoveryRequest data = new KeyRecoveryRequest(form); + return retrieveKey(data); + } + + public KeyData getKey(KeyId keyId, KeyRecoveryRequest data) throws EBaseException { + KeyData keyData; + + RequestId rId = data.getRequestId(); + + String transWrappedSessionKey; + String sessionWrappedPassphrase; + + IRequest request = queue.findRequest(rId); + + if (request == null) { + return null; + } + + // get wrapped key + IKeyRecord rec = repo.readKeyRecord(keyId.toBigInteger()); + if (rec == null) { + return null; + } + + Hashtable<String, Object> requestParams = kra.getVolatileRequest( + request.getRequestId()); + + if(requestParams == null) { + auditRetrieveKey(ILogger.FAILURE, rId, keyId, "cannot obtain volatile requestParams"); + throw new EBaseException("Can't obtain Volatile requestParams in getKey!"); + } + + String sessWrappedKeyData = (String) requestParams.get(IRequest.SECURITY_DATA_SESS_WRAPPED_DATA); + String passWrappedKeyData = (String) requestParams.get(IRequest.SECURITY_DATA_PASS_WRAPPED_DATA); + String nonceData = (String) requestParams.get(IRequest.SECURITY_DATA_IV_STRING_OUT); + + if (sessWrappedKeyData != null || passWrappedKeyData != null) { + //The recovery process has already placed a valid recovery + //package, either session key wrapped or pass wrapped, into the request. + //Request already has been processed. + keyData = new KeyData(); + + } else { + // The request has not yet been processed, let's see if the RecoveryRequestData contains + // the info now needed to process the recovery request. + + transWrappedSessionKey = data.getTransWrappedSessionKey(); + sessionWrappedPassphrase = data.getSessionWrappedPassphrase(); + nonceData = data.getNonceData(); + + if (transWrappedSessionKey == null) { + //There must be at least a transWrappedSessionKey input provided. + //The command AND the request have provided insufficient data, end of the line. + auditRetrieveKey(ILogger.FAILURE, rId, keyId, "insufficient input data"); + throw new EBaseException("Can't retrieve key, insufficient input data!"); + } + + if (sessionWrappedPassphrase != null) { + requestParams.put(IRequest.SECURITY_DATA_SESS_PASS_PHRASE, sessionWrappedPassphrase); + } + + if (transWrappedSessionKey != null) { + requestParams.put(IRequest.SECURITY_DATA_TRANS_SESS_KEY, transWrappedSessionKey); + } + + if (nonceData != null) { + requestParams.put(IRequest.SECURITY_DATA_IV_STRING_IN, nonceData); + } + + try { + // Has to be in this state or it won't go anywhere. + request.setRequestStatus(RequestStatus.BEGIN); + queue.processRequest(request); + } catch (EBaseException e) { + kra.destroyVolatileRequest(request.getRequestId()); + throw new EBaseException(e.toString()); + } + + nonceData = null; + keyData = new KeyData(); + + sessWrappedKeyData = (String) requestParams.get(IRequest.SECURITY_DATA_SESS_WRAPPED_DATA); + passWrappedKeyData = (String) requestParams.get(IRequest.SECURITY_DATA_PASS_WRAPPED_DATA); + nonceData = (String) requestParams.get(IRequest.SECURITY_DATA_IV_STRING_OUT); + + } + + if (sessWrappedKeyData != null) { + keyData.setWrappedPrivateData(sessWrappedKeyData); + } + if (passWrappedKeyData != null) { + keyData.setWrappedPrivateData(passWrappedKeyData); + } + if (nonceData != null) { + keyData.setNonceData(nonceData); + } + + String algorithm = rec.getAlgorithm(); + Integer keySize = rec.getKeySize(); + + if (algorithm != null) { + keyData.setAlgorithm(algorithm); + } + + if (keySize != null) { + keyData.setSize(keySize); + } + + kra.destroyVolatileRequest(request.getRequestId()); + + queue.markAsServiced(request); + + return keyData; + } + + private KeyId validateRequest(KeyRecoveryRequest data) { + + // confirm request exists + RequestId reqId = data.getRequestId(); + if (reqId == null) { + auditRetrieveKey(ILogger.FAILURE, null, null, "Request id not found"); + // log error + throw new BadRequestException("Request id not found."); + } + + // confirm that at least one wrapping method exists + // There must be at least the wrapped session key method. + if ((data.getTransWrappedSessionKey() == null)) { + auditRetrieveKey(ILogger.FAILURE, reqId, null, "No wrapping method found"); + // log error + throw new BadRequestException("No wrapping method found."); + } + + KeyRequestDAO reqDAO = new KeyRequestDAO(); + KeyRequestInfo reqInfo; + try { + reqInfo = reqDAO.getRequest(reqId, uriInfo); + } catch (EBaseException e1) { + auditRetrieveKey(ILogger.FAILURE, reqId, null, "failed to get request"); + // failed to get request + e1.printStackTrace(); + throw new PKIException(e1.getMessage()); + } + if (reqInfo == null) { + auditRetrieveKey(ILogger.FAILURE, reqId, null, "no request info available"); + // request not found + throw new HTTPGoneException("No request information available."); + } + + //confirm request is of the right type + String type = reqInfo.getRequestType(); + if (!type.equals(IRequest.SECURITY_DATA_RECOVERY_REQUEST)) { + auditRetrieveKey(ILogger.FAILURE, reqId, null, "invalid request type"); + // log error + throw new BadRequestException("Invalid request type"); + } + + //confirm that agent is originator of request, else throw 401 + // TO-DO + + // confirm request is in approved state + RequestStatus status = reqInfo.getRequestStatus(); + if (!status.equals(RequestStatus.APPROVED)) { + auditRetrieveKey(ILogger.FAILURE, reqId, null, "recovery request not approved"); + // log error + throw new UnauthorizedException("Unauthorized request. Recovery request not approved."); + } + + return reqInfo.getKeyId(); + } + + /** + * Used to generate list of key infos based on the search parameters + */ + @Override + public Response listKeys(String clientKeyID, String status, Integer maxResults, Integer maxTime, + Integer start, Integer size) { + return createOKResponse(listKeyInfos(clientKeyID, status, maxResults, maxTime, start, size)); + } + + public KeyInfoCollection listKeyInfos(String clientKeyID, String status, Integer maxResults, Integer maxTime, + Integer start, Integer size) { + + start = start == null ? 0 : start; + size = size == null ? DEFAULT_SIZE : size; + + // get ldap filter + String filter = createSearchFilter(status, clientKeyID); + CMS.debug("listKeys: filter is " + filter); + + maxResults = maxResults == null ? DEFAULT_MAXRESULTS : maxResults; + maxTime = maxTime == null ? DEFAULT_MAXTIME : maxTime; + + KeyInfoCollection infos = new KeyInfoCollection(); + try { + Enumeration<IKeyRecord> e = repo.searchKeys(filter, maxResults, maxTime); + if (e == null) { + return infos; + } + + // store non-null results in a list + List<KeyInfo> results = new ArrayList<KeyInfo>(); + while (e.hasMoreElements()) { + IKeyRecord rec = e.nextElement(); + if (rec == null) continue; + results.add(createKeyDataInfo(rec)); + } + + int total = results.size(); + infos.setTotal(total); + + // return entries in the requested page + for (int i = start; i < start + size && i < total; i++) { + infos.addEntry(results.get(i)); + } + + if (start > 0) { + URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", Math.max(start-size, 0)).build(); + infos.addLink(new Link("prev", uri)); + } + + if (start + size < total) { + URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", start+size).build(); + infos.addLink(new Link("next", uri)); + } + + } catch (EBaseException e) { + e.printStackTrace(); + throw new PKIException(e.getMessage()); + } + + return infos; + } + + @Override + public Response getActiveKeyInfo(String clientKeyID) { + + KeyInfoCollection infos = listKeyInfos( + clientKeyID, + "active", + null, + null, + null, + null + ); + + Collection<KeyInfo> list = infos.getEntries(); + Iterator<KeyInfo> iter = list.iterator(); + + while (iter.hasNext()) { + KeyInfo info = iter.next(); + if (info != null) { + // return the first one + return createOKResponse(info); + } + } + + throw new ResourceNotFoundException("Key not found."); + } + + public KeyInfo createKeyDataInfo(IKeyRecord rec) throws EBaseException { + KeyInfo ret = new KeyInfo(); + ret.setClientKeyID(rec.getClientId()); + ret.setStatus(rec.getKeyStatus()); + ret.setAlgorithm(rec.getAlgorithm()); + ret.setSize(rec.getKeySize()); + ret.setOwnerName(rec.getOwnerName()); + + Path keyPath = KeyResource.class.getAnnotation(Path.class); + BigInteger serial = rec.getSerialNumber(); + + UriBuilder keyBuilder = uriInfo.getBaseUriBuilder(); + keyBuilder.path(keyPath.value() + "/" + serial); + ret.setKeyURL(keyBuilder.build().toString()); + + return ret; + } + + private String createSearchFilter(String status, String clientKeyID) { + String filter = ""; + int matches = 0; + + if ((status == null) && (clientKeyID == null)) { + filter = "(serialno=*)"; + return filter; + } + + if (status != null) { + filter += "(status=" + LDAPUtil.escapeFilter(status) + ")"; + matches ++; + } + + if (clientKeyID != null) { + filter += "(clientID=" + LDAPUtil.escapeFilter(clientKeyID) + ")"; + matches ++; + } + + if (matches > 1) { + filter = "(&" + filter + ")"; + } + + return filter; + } + + public void auditRetrieveKey(String status, RequestId requestID, KeyId keyID, String reason) { + String msg = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_SECURITY_DATA_RETRIEVE_KEY, + servletRequest.getUserPrincipal().getName(), + status, + requestID != null ? requestID.toString(): "null", + keyID != null ? keyID.toString(): "null", + reason); + auditor.log(msg); + } + + /** + * Used to retrieve a key + * @param data + * @return + */ + private KeyData recoverKey(KeyRecoveryRequest data) { + // confirm request exists + RequestId reqId = data.getRequestId(); + + IRequest request = null; + try { + request = queue.findRequest(reqId); + } catch (EBaseException e) { + } + if (request == null) { + throw new HTTPGoneException("No request record."); + } + String type = request.getRequestType(); + RequestStatus status = request.getRequestStatus(); + if (!IRequest.KEYRECOVERY_REQUEST.equals(type) || + !status.equals(RequestStatus.APPROVED)) { + auditRetrieveKey(ILogger.FAILURE, reqId, null, "Unauthorized request."); + throw new UnauthorizedException("Unauthorized request."); + } + + String passphrase = data.getPassphrase(); + byte pkcs12[] = null; + try { + pkcs12 = service.doKeyRecovery(reqId.toString(), passphrase); + } catch (EBaseException e) { + } + if (pkcs12 == null) { + throw new HTTPGoneException("Key not recovered."); + } + String pkcs12base64encoded = Utils.base64encode(pkcs12); + + KeyData keyData = new KeyData(); + keyData.setP12Data(pkcs12base64encoded); + + try { + queue.processRequest(request); + queue.markAsServiced(request); + } catch (EBaseException e) { + } + + return keyData; + } + + @Override + public Response getKeyInfo(KeyId keyId) { + IKeyRecord rec = null; + try { + rec = repo.readKeyRecord(keyId.toBigInteger()); + KeyInfo info = createKeyDataInfo(rec); + + return createOKResponse(info); + } catch (EDBRecordNotFoundException e) { + throw new KeyNotFoundException(keyId); + } catch (Exception e) { + CMS.debug("Unable to retrieve key record: " + e); + e.printStackTrace(); + throw new PKIException(e.getMessage()); + } + } + + @Override + public Response modifyKeyStatus(KeyId keyId, String status) { + try { + + ModificationSet mods = new ModificationSet(); + mods.add(IKeyRecord.ATTR_STATUS, Modification.MOD_REPLACE, + status); + repo.modifyKeyRecord(keyId.toBigInteger(), mods); + return createNoContentResponse(); + } catch (EDBRecordNotFoundException e) { + throw new KeyNotFoundException(keyId); + } catch (Exception e) { + CMS.debug("Unable to retrieve key record: " + e); + e.printStackTrace(); + throw new PKIException(e.getMessage()); + } + } + + +} |