From 0b39b68e4e72cbcf0f4d28488d54ce06117efa9c Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Thu, 1 Mar 2012 19:58:34 -0600 Subject: Added CMSException. The CMSException was added to simplify error handling in REST services. The exception may include an error message and some other attributes. When the server throws a CMSException (or its subclass), the exception will be marshalled into XML and unmarshalled by the client, then thrown again as a new exception which can be caught by the application. Ticket #100 --- base/common/src/CMakeLists.txt | 2 + .../src/com/netscape/certsrv/dbs/keydb/KeyId.java | 11 ++ .../com/netscape/certsrv/request/RequestId.java | 11 ++ .../admin/SystemCertificateResourceService.java | 7 +- .../netscape/cms/servlet/base/CMSException.java | 165 +++++++++++++++++++++ .../cms/servlet/base/CMSResourceService.java | 17 ++- .../cms/servlet/key/KeyResourceService.java | 5 - .../cms/servlet/key/KeysResourceService.java | 5 - .../servlet/request/KeyRequestResourceService.java | 25 ++-- .../request/KeyRequestsResourceService.java | 5 - .../servlet/request/RequestNotFoundException.java | 46 ++++++ .../cms/servlet/test/DRMErrorInterceptor.java | 43 ++++++ .../netscape/cms/servlet/test/DRMRestClient.java | 105 +++++++------ .../src/com/netscape/cms/servlet/test/DRMTest.java | 50 ++++--- 14 files changed, 391 insertions(+), 106 deletions(-) create mode 100644 base/common/src/com/netscape/cms/servlet/base/CMSException.java create mode 100644 base/common/src/com/netscape/cms/servlet/request/RequestNotFoundException.java create mode 100644 base/kra/functional/src/com/netscape/cms/servlet/test/DRMErrorInterceptor.java (limited to 'base') diff --git a/base/common/src/CMakeLists.txt b/base/common/src/CMakeLists.txt index 01ff33e47..ea9077f74 100644 --- a/base/common/src/CMakeLists.txt +++ b/base/common/src/CMakeLists.txt @@ -579,6 +579,7 @@ set(pki-cms_java_SRCS com/netscape/cms/servlet/base/IndexServlet.java com/netscape/cms/servlet/base/UserInfo.java com/netscape/cms/servlet/base/PortsServlet.java + com/netscape/cms/servlet/base/CMSException.java com/netscape/cms/servlet/base/CMSResourceService.java com/netscape/cms/servlet/base/CMSServlet.java com/netscape/cms/servlet/base/CMSStartServlet.java @@ -664,6 +665,7 @@ set(pki-cms_java_SRCS com/netscape/cms/servlet/request/IReqParser.java com/netscape/cms/servlet/request/ReqParser.java com/netscape/cms/servlet/request/QueryReq.java + com/netscape/cms/servlet/request/RequestNotFoundException.java com/netscape/cms/servlet/request/SearchReqs.java com/netscape/cms/servlet/request/ProcessCertReq.java com/netscape/cms/servlet/request/CertReqParser.java diff --git a/base/common/src/com/netscape/certsrv/dbs/keydb/KeyId.java b/base/common/src/com/netscape/certsrv/dbs/keydb/KeyId.java index f998bf97a..b8bb1870b 100644 --- a/base/common/src/com/netscape/certsrv/dbs/keydb/KeyId.java +++ b/base/common/src/com/netscape/certsrv/dbs/keydb/KeyId.java @@ -95,6 +95,17 @@ public class KeyId { return value.toString(); } + /** + * Converts the KeyId into its hex string representation. The string + * form can be stored in a database (such as the LDAP directory) + * + * @return + * a string containing the hex (hex 16) value for the identifier. + */ + public String toHexString() { + return "0x"+value.toString(16); + } + @Override public int hashCode() { final int prime = 31; diff --git a/base/common/src/com/netscape/certsrv/request/RequestId.java b/base/common/src/com/netscape/certsrv/request/RequestId.java index da61f2bc0..b643fa30d 100644 --- a/base/common/src/com/netscape/certsrv/request/RequestId.java +++ b/base/common/src/com/netscape/certsrv/request/RequestId.java @@ -94,6 +94,17 @@ public class RequestId { return value.toString(); } + /** + * Converts the RequestId into its hex string representation. The string + * form can be stored in a database (such as the LDAP directory) + * + * @return + * a string containing the hex (base 16) value for the identifier. + */ + public String toHexString() { + return "0x"+value.toString(16); + } + @Override public int hashCode() { final int prime = 31; diff --git a/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResourceService.java b/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResourceService.java index 48f410c73..4dccb141f 100644 --- a/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResourceService.java +++ b/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResourceService.java @@ -21,8 +21,6 @@ package com.netscape.cms.servlet.admin; import java.security.cert.CertificateEncodingException; import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; import com.netscape.certsrv.apps.CMS; @@ -39,9 +37,6 @@ import com.netscape.cms.servlet.cert.model.CertificateData; */ public class SystemCertificateResourceService extends CMSResourceService implements SystemCertificateResource { - @Context - Request request; - /** * Used to retrieve the transport certificate */ @@ -74,7 +69,7 @@ public class SystemCertificateResourceService extends CMSResourceService impleme e.printStackTrace(); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } - return sendConditionalGetResponse(DEFAULT_LONG_CACHE_LIFETIME, cert, request); + return sendConditionalGetResponse(DEFAULT_LONG_CACHE_LIFETIME, cert); } } diff --git a/base/common/src/com/netscape/cms/servlet/base/CMSException.java b/base/common/src/com/netscape/cms/servlet/base/CMSException.java new file mode 100644 index 000000000..eda5566ac --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/base/CMSException.java @@ -0,0 +1,165 @@ +package com.netscape.cms.servlet.base; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlValue; +import javax.xml.bind.annotation.adapters.XmlAdapter; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +public class CMSException extends RuntimeException { + + private static final long serialVersionUID = 6000910362260369923L; + + public int code; + + public CMSException(String message) { + super(message); + code = Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); + } + + public CMSException(int code, String message) { + super(message); + this.code = code; + } + + public CMSException(Response.Status status, String message) { + super(message); + code = status.getStatusCode(); + } + + public CMSException(String message, Throwable cause) { + super(message, cause); + code = Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); + } + + public CMSException(int code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + public CMSException(Response.Status status, String message, Throwable cause) { + super(message, cause); + code = status.getStatusCode(); + } + + public CMSException(Data data) { + super(data.message); + code = data.code; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public Data getData() { + Data data = new Data(); + data.className = getClass().getName(); + data.code = code; + data.message = getMessage(); + return data; + } + + @XmlRootElement(name="CMSException") + public static class Data { + + @XmlElement(name="ClassName") + public String className; + + @XmlElement(name="Code") + public int code; + + @XmlElement(name="Message") + public String message; + + @XmlElement(name="Attributes") + @XmlJavaTypeAdapter(MapAdapter.class) + public Map attributes = new LinkedHashMap(); + + public String getAttribute(String name) { + return attributes.get(name); + } + + public void setAttribute(String name, String value) { + attributes.put(name, value); + } + } + + public static class MapAdapter extends XmlAdapter> { + + public AttributeList marshal(Map map) { + AttributeList list = new AttributeList(); + for (Map.Entry entry : map.entrySet()) { + Attribute attribute = new Attribute(); + attribute.name = entry.getKey(); + attribute.value = entry.getValue(); + list.attributes.add(attribute); + } + return list; + } + + public Map unmarshal(AttributeList list) { + Map map = new LinkedHashMap(); + for (Attribute attribute : list.attributes) { + map.put(attribute.name, attribute.value); + } + return map; + } + } + + public static class AttributeList { + @XmlElement(name="Attribute") + public List attributes = new ArrayList(); + } + + public static class Attribute { + + @XmlAttribute + public String name; + + @XmlValue + public String value; + } + + @Provider + public static class Mapper implements ExceptionMapper { + + public Response toResponse(CMSException exception) { + // convert CMSException into HTTP response with XML content + return Response + .status(exception.getCode()) + .entity(exception.getData()) + .type(MediaType.TEXT_XML) + .build(); + } + } + + public static void main(String args[]) throws Exception { + Data data = new Data(); + data.className = CMSException.class.getName(); + data.code = Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); + data.message = "An error has occured"; + data.setAttribute("attr1", "value1"); + data.setAttribute("attr2", "value2"); + + JAXBContext context = JAXBContext.newInstance(Data.class); + Marshaller marshaller = context.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.marshal(data, System.out); + } +} diff --git a/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java b/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java index acddba559..24c3cd74d 100644 --- a/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java +++ b/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java @@ -20,9 +20,11 @@ package com.netscape.cms.servlet.base; import java.security.cert.CertificateEncodingException; import javax.ws.rs.core.CacheControl; +import javax.ws.rs.core.Context; import javax.ws.rs.core.EntityTag; import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.Response.ResponseBuilder; import com.netscape.certsrv.apps.CMS; @@ -35,13 +37,24 @@ import com.netscape.cms.servlet.cert.model.CertificateData; * */ public class CMSResourceService { + public static final String HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----"; public static final String TRAILER = "-----END NEW CERTIFICATE REQUEST-----"; // caching parameters - protected static final int DEFAULT_LONG_CACHE_LIFETIME = 1000; + public static final int DEFAULT_LONG_CACHE_LIFETIME = 1000; + + @Context + protected UriInfo uriInfo; + + @Context + protected Request request; + + public Response createOKResponse(Object object) { + return Response.ok(object).build(); + } - protected Response sendConditionalGetResponse(int ctime, Object object, Request request) { + public Response sendConditionalGetResponse(int ctime, Object object) { CacheControl cc = new CacheControl(); cc.setMaxAge(ctime); EntityTag tag = new EntityTag(Integer.toString(object.hashCode())); diff --git a/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java b/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java index 79e6ccfdb..88f2f8a82 100644 --- a/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java +++ b/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java @@ -20,10 +20,8 @@ package com.netscape.cms.servlet.key; import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; import com.netscape.cms.servlet.base.CMSResourceService; import com.netscape.cms.servlet.key.model.KeyDAO; @@ -43,9 +41,6 @@ import com.netscape.certsrv.dbs.keydb.KeyId; */ public class KeyResourceService extends CMSResourceService implements KeyResource{ - @Context - UriInfo uriInfo; - /** * Used to retrieve a key * @param data diff --git a/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java b/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java index a7876a6c6..d525d5a77 100644 --- a/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java +++ b/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java @@ -21,9 +21,7 @@ package com.netscape.cms.servlet.key; import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; @@ -38,9 +36,6 @@ import com.netscape.cmsutil.ldap.LDAPUtil; */ public class KeysResourceService extends CMSResourceService implements KeysResource { - @Context - UriInfo uriInfo; - /** * Used to generate list of key infos based on the search parameters */ diff --git a/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java b/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java index 43e58bbdc..b9ba206c1 100644 --- a/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java +++ b/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java @@ -19,27 +19,24 @@ package com.netscape.cms.servlet.request; import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; + import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.request.RequestId; +import com.netscape.cms.servlet.base.CMSException; import com.netscape.cms.servlet.base.CMSResourceService; import com.netscape.cms.servlet.request.model.ArchivalRequestData; import com.netscape.cms.servlet.request.model.KeyRequestDAO; import com.netscape.cms.servlet.request.model.KeyRequestInfo; import com.netscape.cms.servlet.request.model.RecoveryRequestData; - + /** * @author alee - * + * */ public class KeyRequestResourceService extends CMSResourceService implements KeyRequestResource { - @Context - UriInfo uriInfo; - /** * Used to retrieve key request info for a specific request */ @@ -52,15 +49,15 @@ public class KeyRequestResourceService extends CMSResourceService implements Key } catch (EBaseException e) { // log error e.printStackTrace(); - throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + throw new CMSException(e.getMessage(), e); } if (info == null) { // request does not exist - throw new WebApplicationException(Response.Status.NOT_FOUND); + throw new RequestNotFoundException(id); } return info; } - + // Archiving - used to test integration with a browser public KeyRequestInfo archiveKey(MultivaluedMap form) { ArchivalRequestData data = new ArchivalRequestData(form); @@ -88,7 +85,7 @@ public class KeyRequestResourceService extends CMSResourceService implements Key } return info; } - + //Recovery - used to test integration with a browser public KeyRequestInfo recoverKey(MultivaluedMap form) { RecoveryRequestData data = new RecoveryRequestData(form); @@ -117,7 +114,7 @@ public class KeyRequestResourceService extends CMSResourceService implements Key } return info; } - + public void approveRequest(RequestId id) { if (id == null) { throw new WebApplicationException(Response.Status.BAD_REQUEST); @@ -132,7 +129,7 @@ public class KeyRequestResourceService extends CMSResourceService implements Key throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } } - + public void rejectRequest(RequestId id) { if (id == null) { throw new WebApplicationException(Response.Status.BAD_REQUEST); @@ -147,7 +144,7 @@ public class KeyRequestResourceService extends CMSResourceService implements Key throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } } - + public void cancelRequest(RequestId id) { if (id == null) { throw new WebApplicationException(Response.Status.BAD_REQUEST); diff --git a/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResourceService.java b/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResourceService.java index 11898ef7a..82b1efa07 100644 --- a/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResourceService.java +++ b/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResourceService.java @@ -19,9 +19,7 @@ package com.netscape.cms.servlet.request; import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; @@ -37,9 +35,6 @@ import com.netscape.cmsutil.ldap.LDAPUtil; */ public class KeyRequestsResourceService extends CMSResourceService implements KeyRequestsResource{ - @Context - UriInfo uriInfo; - /** * Used to generate list of key requests based on the search parameters */ diff --git a/base/common/src/com/netscape/cms/servlet/request/RequestNotFoundException.java b/base/common/src/com/netscape/cms/servlet/request/RequestNotFoundException.java new file mode 100644 index 000000000..5d6b5563b --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/request/RequestNotFoundException.java @@ -0,0 +1,46 @@ +package com.netscape.cms.servlet.request; + +import javax.ws.rs.core.Response; + +import com.netscape.certsrv.request.RequestId; +import com.netscape.cms.servlet.base.CMSException; + +public class RequestNotFoundException extends CMSException { + + private static final long serialVersionUID = -4784839378360933483L; + + public RequestId requestId; + + public RequestNotFoundException(RequestId requestId) { + this(requestId, "Request ID "+requestId.toHexString()+" not found"); + } + + public RequestNotFoundException(RequestId requestId, String message) { + super(Response.Status.NOT_FOUND, message); + this.requestId = requestId; + } + + public RequestNotFoundException(RequestId requestId, String message, Throwable cause) { + super(Response.Status.NOT_FOUND, message, cause); + this.requestId = requestId; + } + + public RequestNotFoundException(Data data) { + super(data); + requestId = new RequestId(data.getAttribute("requestId")); + } + + public Data getData() { + Data data = super.getData(); + data.setAttribute("requestId", requestId.toString()); + return data; + } + + public RequestId getRequestId() { + return requestId; + } + + public void setRequestId(RequestId requestId) { + this.requestId = requestId; + } +} diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMErrorInterceptor.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMErrorInterceptor.java new file mode 100644 index 000000000..7572acef5 --- /dev/null +++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMErrorInterceptor.java @@ -0,0 +1,43 @@ +package com.netscape.cms.servlet.test; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; + +import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.client.core.ClientErrorInterceptor; + +import com.netscape.cms.servlet.base.CMSException; + +public class DRMErrorInterceptor implements ClientErrorInterceptor { + + public void handle(ClientResponse response) { + + // handle HTTP code 4xx and 5xx + int code = response.getResponseStatus().getStatusCode(); + if (code < 400) return; + + MultivaluedMap headers = response.getHeaders(); + String contentType = headers.getFirst("Content-Type"); + + // handle XML content only + if (!contentType.startsWith(MediaType.TEXT_XML)) return; + + CMSException exception; + + try { + // Requires RESTEasy 2.3.2 + // https://issues.jboss.org/browse/RESTEASY-652 + CMSException.Data data = response.getEntity(CMSException.Data.class); + + Class clazz = Class.forName(data.className); + exception = (CMSException) clazz.getConstructor(CMSException.Data.class).newInstance(data); + + } catch (Exception e) { + e.printStackTrace(); + return; + } + + throw exception; + } + +} diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java index 651873b20..14b2aa3dc 100644 --- a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java +++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java @@ -2,9 +2,9 @@ package com.netscape.cms.servlet.test; import java.io.IOException; import java.net.InetAddress; -import java.net.MalformedURLException; import java.net.Socket; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.Collection; import java.util.Enumeration; @@ -18,9 +18,14 @@ import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; import org.jboss.resteasy.client.ClientExecutor; import org.jboss.resteasy.client.ClientResponse; import org.jboss.resteasy.client.ProxyFactory; +import org.jboss.resteasy.client.core.executors.ApacheHttpClientExecutor; +import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.mozilla.jss.ssl.SSLCertificateApprovalCallback; +import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback; +import org.mozilla.jss.ssl.SSLSocket; + import com.netscape.certsrv.dbs.keydb.KeyId; import com.netscape.certsrv.request.RequestId; -import org.jboss.resteasy.client.core.executors.ApacheHttpClientExecutor; import com.netscape.cms.servlet.admin.SystemCertificateResource; import com.netscape.cms.servlet.cert.model.CertificateData; import com.netscape.cms.servlet.key.KeyResource; @@ -36,10 +41,6 @@ import com.netscape.cms.servlet.request.model.KeyRequestInfos; import com.netscape.cms.servlet.request.model.RecoveryRequestData; import com.netscape.cmsutil.util.Utils; -import org.mozilla.jss.ssl.SSLCertificateApprovalCallback; -import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback; -import org.mozilla.jss.ssl.SSLSocket; - public class DRMRestClient { // Callback to approve or deny returned SSL server certs @@ -47,7 +48,7 @@ public class DRMRestClient { // ToDO: Look into taking this JSS http client code and move it into // its own class to be used by possible future clients. private class ServerCertApprovalCB implements SSLCertificateApprovalCallback { - + public boolean approve(org.mozilla.jss.crypto.X509Certificate servercert, SSLCertificateApprovalCallback.ValidityStatus status) { @@ -81,7 +82,7 @@ public class DRMRestClient { reason == SSLCertificateApprovalCallback.ValidityStatus.BAD_CERT_DOMAIN) { //Allow these two since we haven't necessarily installed the CA cert for trust - // and we are choosing "localhost" as the host for this client. + // and we are choosing "localhost" as the host for this client. return true; @@ -93,91 +94,95 @@ public class DRMRestClient { return false; } } - + private class JSSProtocolSocketFactory implements ProtocolSocketFactory { @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { - + SSLSocket sock = createJSSSocket(host,port, null, 0, null); - return (Socket) sock; + return sock; } @Override public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException { - + SSLSocket sock = createJSSSocket(host,port, clientHost, clientPort, null); - return (Socket) sock; + return sock; } @Override public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException { - + SSLSocket sock = createJSSSocket(host, port, localAddress, localPort, null); - return (Socket) sock; + return sock; } } - private SSLSocket createJSSSocket(String host, int port, InetAddress localAddress, + private SSLSocket createJSSSocket(String host, int port, InetAddress localAddress, int localPort, SSLClientCertificateSelectionCallback clientCertSelectionCallback) throws IOException, UnknownHostException, ConnectTimeoutException { - + SSLSocket sock = new SSLSocket(InetAddress.getByName(host), port, localAddress, localPort, new ServerCertApprovalCB(), null); - + if(sock != null && clientCertNickname != null) { sock.setClientCertNickname(clientCertNickname); } - + return sock; - + } private KeyResource keyClient; private KeysResource keysClient; private KeyRequestsResource keyRequestsClient; private KeyRequestResource keyRequestClient; private SystemCertificateResource systemCertClient; - + private String clientCertNickname = null; - - public DRMRestClient(String baseUri, String clientCertNick) throws MalformedURLException { - + + public DRMRestClient(String baseUri, String clientCertNick) throws URISyntaxException { + // For SSL we are assuming the caller has already intialized JSS and has // a valid CryptoManager and CryptoToken // optional clientCertNickname is provided for use if required. - - - URL url = new URL(baseUri); - - String protocol = url.getProtocol(); - int port = url.getPort(); - + + + URI uri = new URI(baseUri); + + String protocol = uri.getScheme(); + int port = uri.getPort(); + clientCertNickname = null; if(protocol != null && protocol.equals("https")) { if (clientCertNick != null) { clientCertNickname = clientCertNick; - } - - Protocol.registerProtocol("https", + } + + Protocol.registerProtocol("https", new Protocol(protocol, new JSSProtocolSocketFactory(), port)); } - + HttpClient httpclient = new HttpClient(); ClientExecutor executor = new ApacheHttpClientExecutor(httpclient); - systemCertClient = ProxyFactory.create(SystemCertificateResource.class, baseUri, executor); - keyRequestsClient = ProxyFactory.create(KeyRequestsResource.class, baseUri, executor); - keyRequestClient = ProxyFactory.create(KeyRequestResource.class, baseUri, executor); - keysClient = ProxyFactory.create(KeysResource.class, baseUri, executor); - keyClient = ProxyFactory.create(KeyResource.class, baseUri, executor); + ResteasyProviderFactory providerFactory = ResteasyProviderFactory.getInstance(); + providerFactory.addClientErrorInterceptor(new DRMErrorInterceptor()); + + systemCertClient = ProxyFactory.create(SystemCertificateResource.class, uri, executor, providerFactory); + keyRequestsClient = ProxyFactory.create(KeyRequestsResource.class, uri, executor, providerFactory); + keyRequestClient = ProxyFactory.create(KeyRequestResource.class, uri, executor, providerFactory); + keysClient = ProxyFactory.create(KeysResource.class, uri, executor, providerFactory); + keyClient = ProxyFactory.create(KeyResource.class, uri, executor, providerFactory); + keyClient = ProxyFactory.create(KeyResource.class, uri, executor, providerFactory); } - + public String getTransportCert() { @SuppressWarnings("unchecked") ClientResponse response = (ClientResponse) systemCertClient.getTransportCert(); @@ -185,7 +190,7 @@ public class DRMRestClient { String transportCert = certData.getB64(); return transportCert; } - + public Collection listRequests(String requestState, String requestType) { KeyRequestInfos infos = keyRequestsClient.listRequests( requestState, requestType, null, new RequestId(0), 100, 100, 10 @@ -193,7 +198,7 @@ public class DRMRestClient { Collection list = infos.getRequests(); return list; } - + public KeyRequestInfo archiveSecurityData(byte[] encoded, String clientId, String dataType) { // create archival request ArchivalRequestData data = new ArchivalRequestData(); @@ -205,7 +210,7 @@ public class DRMRestClient { KeyRequestInfo info = keyRequestClient.archiveKey(data); return info; } - + public KeyDataInfo getKeyData(String clientId, String status) { KeyDataInfos infos = keysClient.listKeys(clientId, status, 100, 10); Collection list = infos.getKeyInfos(); @@ -220,7 +225,7 @@ public class DRMRestClient { } return null; } - + public KeyRequestInfo requestRecovery(KeyId keyId, byte[] rpwd, byte[] rkey, byte[] nonceData) { // create recovery request RecoveryRequestData data = new RecoveryRequestData(); @@ -239,11 +244,11 @@ public class DRMRestClient { KeyRequestInfo info = keyRequestClient.recoverKey(data); return info; } - + public void approveRecovery(RequestId recoveryId) { keyRequestClient.approveRequest(recoveryId); } - + public KeyData retrieveKey(KeyId keyId, RequestId requestId, byte[] rpwd, byte[] rkey, byte[] nonceData) { // create recovery request RecoveryRequestData data = new RecoveryRequestData(); @@ -263,4 +268,8 @@ public class DRMRestClient { KeyData key = keyClient.retrieveKey(data); return key; } + + public KeyRequestInfo getRequest(RequestId id) { + return keyRequestClient.getRequestInfo(id); + } } diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java index 8d83247b8..5323777bd 100644 --- a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java +++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java @@ -17,12 +17,17 @@ // --- END COPYRIGHT BLOCK --- package com.netscape.cms.servlet.test; -import java.net.MalformedURLException; import java.util.Calendar; import java.util.Collection; import java.util.Iterator; import java.util.Random; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; import org.mozilla.jss.CryptoManager; import org.mozilla.jss.crypto.AlreadyInitializedException; import org.mozilla.jss.crypto.CryptoToken; @@ -32,19 +37,13 @@ import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.SymmetricKey; import org.mozilla.jss.util.Password; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.cli.PosixParser; - import com.netscape.certsrv.dbs.keydb.KeyId; import com.netscape.certsrv.request.RequestId; import com.netscape.cms.servlet.base.CMSResourceService; import com.netscape.cms.servlet.key.model.KeyData; import com.netscape.cms.servlet.key.model.KeyDataInfo; import com.netscape.cms.servlet.request.KeyRequestResource; +import com.netscape.cms.servlet.request.RequestNotFoundException; import com.netscape.cms.servlet.request.model.KeyRequestInfo; import com.netscape.cmsutil.crypto.CryptoUtil; import com.netscape.cmsutil.util.Utils; @@ -102,18 +101,18 @@ public class DRMTest { if (cmd.hasOption("d")) { db_dir = cmd.getOptionValue("d"); } - + if (cmd.hasOption("s")) { if(cmd.getOptionValue("s") != null && cmd.getOptionValue("s").equals("true")) { protocol = "https"; } } - + if (cmd.hasOption("c")) { String nick = cmd.getOptionValue("c"); - + if (nick != null && protocol.equals("https")) { - clientCertNickname = nick; + clientCertNickname = nick; } } @@ -123,7 +122,7 @@ public class DRMTest { } // used for crypto operations - byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; + byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; IVParameterSpec ivps = null; IVParameterSpec ivps_server = null; @@ -168,7 +167,7 @@ public class DRMTest { try { CryptoManager.initialize(db_dir); } catch (AlreadyInitializedException e) { - // it is ok if it is already initialized + // it is ok if it is already initialized } catch (Exception e) { log("INITIALIZATION ERROR: " + e.toString()); System.exit(1); @@ -192,15 +191,14 @@ public class DRMTest { } // Set base URI and get client - - + + String baseUri = protocol + "://" + host + ":" + port + "/kra/pki"; DRMRestClient client; try { client = new DRMRestClient(baseUri, clientCertNickname); - } catch (MalformedURLException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); return; } @@ -294,7 +292,7 @@ public class DRMTest { ivps_server = new IVParameterSpec(Utils.base64decode(keyData.getNonceData())); try { - recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server, + recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server, Utils.base64decode(wrappedRecoveredKey), recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD); } catch (Exception e) { @@ -406,7 +404,7 @@ public class DRMTest { wrappedRecoveredKey = keyData.getWrappedPrivateData(); ivps_server = new IVParameterSpec( Utils.base64decode(keyData.getNonceData())); try { - recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server, + recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server, Utils.base64decode(wrappedRecoveredKey), recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD); recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8"); @@ -476,6 +474,16 @@ public class DRMTest { } else { log("Success: recovered and archived passphrases do match!"); } + + // Test 23: Get non-existent request + RequestId requestId = new RequestId("0xabcdef"); + log("Getting non-existent request: " + requestId.toHexString()); + try { + client.getRequest(requestId); + log("Error: getting non-existent request does not throw an exception"); + } catch (RequestNotFoundException e) { + log("Success: getting non-existent request throws an exception: "+e.getMessage()+" ("+e.getRequestId().toHexString()+")"); + } } private static void log(String string) { -- cgit