diff options
7 files changed, 506 insertions, 47 deletions
diff --git a/pki/base/common/src/com/netscape/cms/servlet/base/model/Link.java b/pki/base/common/src/com/netscape/cms/servlet/base/model/Link.java new file mode 100644 index 000000000..7fd850a22 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/servlet/base/model/Link.java @@ -0,0 +1,88 @@ +// --- 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 com.netscape.cms.servlet.base.model; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * @author alee + * + */ +@XmlRootElement(name = "Link") +public class Link { + protected String relationship; + protected String href; + protected String type; + + public Link() { + // required for jaxb + } + + public Link(String relationship, String href, String type) { + this.relationship = relationship; + this.href = href; + this.type = type; + } + + /** + * @return the relationship + */ + @XmlAttribute(name = "rel") + public String getRelationship() { + return relationship; + } + + /** + * @param relationship the relationship to set + */ + public void setRelationship(String relationship) { + this.relationship = relationship; + } + + /** + * @return the href + */ + @XmlAttribute + public String getHref() { + return href; + } + + /** + * @param href the href to set + */ + public void setHref(String href) { + this.href = href; + } + + /** + * @return the type + */ + @XmlAttribute + public String getType() { + return type; + } + + /** + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + } + +} diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java b/pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java index 98f12ae5a..4cf5db3f4 100644 --- a/pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java +++ b/pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java @@ -20,21 +20,22 @@ */ package com.netscape.cms.servlet.key; +import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; -import java.util.List; - +import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; import com.netscape.cms.servlet.base.CMSResource; import com.netscape.cms.servlet.key.model.KeyDAO; -import com.netscape.cms.servlet.key.model.KeyDataInfo; +import com.netscape.cms.servlet.key.model.KeyDataInfos; /** * @author alee @@ -43,6 +44,9 @@ import com.netscape.cms.servlet.key.model.KeyDataInfo; @Path("/keys") public class KeysResource extends CMSResource { + private static final String DEFAULT_MAXTIME = "10"; + private static final String DEFAULT_MAXRESULTS = "100"; + @Context UriInfo uriInfo; @@ -51,20 +55,51 @@ public class KeysResource extends CMSResource { */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) - public List<KeyDataInfo> listKeys() { + public KeyDataInfos listKeys(@QueryParam("clientID") String clientID, + @QueryParam("status") String status, + @DefaultValue(DEFAULT_MAXRESULTS) @QueryParam("maxResults") int maxResults, + @DefaultValue(DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime) { // auth and authz - // parse search parameters from uriInfo and create search filter - // String clientID = uriInfo.getQueryParameters().getFirst(CLIENT_ID); - String filter = "objectClass=keyRecord"; + + // get ldap filter + String filter = createSearchFilter(status, clientID); + CMS.debug("listKeys: filter is " + filter); + KeyDAO dao = new KeyDAO(); - List<KeyDataInfo> info; + KeyDataInfos infos; try { - info = dao.listKeys(filter, uriInfo); + infos = dao.listKeys(filter, maxResults, maxTime, uriInfo); } catch (EBaseException e) { e.printStackTrace(); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } - return info; + return infos; + } + + private String createSearchFilter(String status, String clientID) { + String filter = ""; + int matches = 0; + + if ((status == null) && (clientID == null)) { + filter = "(serialno=*)"; + return filter; + } + + if (status != null) { + filter += "(status=" + status + ")"; + matches ++; + } + + if (clientID != null) { + filter += "(clientID=" + clientID + ")"; + matches ++; + } + + if (matches > 1) { + filter = "(&" + filter + ")"; + } + + return filter; } } diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDAO.java b/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDAO.java index b7a2d8ed1..5fd17a333 100644 --- a/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDAO.java +++ b/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDAO.java @@ -38,8 +38,6 @@ import com.netscape.cms.servlet.request.model.RecoveryRequestData; public class KeyDAO { private IKeyRepository repo; - private int maxSize = 100; - private int maxTime = 20; public KeyDAO() { IKeyRecoveryAuthority kra = null; @@ -47,25 +45,37 @@ public class KeyDAO { repo = kra.getKeyRepository(); } /** - * This will find the keys in the database matching the specified search parameters - * Needs input validation and probably paging, maybe using the vlv functions - * @throws EBaseException + * Returns list of keys meeting specified search filter. + * Currently, vlv searches are not used for keys. + * + * @param filter + * @param maxResults + * @param maxTime + * @param uriInfo + * @return + * @throws EBaseException */ - public List<KeyDataInfo> listKeys(String filter, UriInfo uriInfo) throws EBaseException { - List <KeyDataInfo> list = new ArrayList<KeyDataInfo>(); + public KeyDataInfos listKeys(String filter, int maxResults, int maxTime, UriInfo uriInfo) + throws EBaseException { + List <KeyDataInfo> list = new ArrayList<KeyDataInfo>(); Enumeration<IKeyRecord> e = null; - e = repo.searchKeys(filter, maxSize, maxTime); - + e = repo.searchKeys(filter, maxResults, maxTime); if (e == null) { throw new EBaseException("search results are null"); } while (e.hasMoreElements()) { IKeyRecord rec = e.nextElement(); - list.add(createKeyDataInfo(rec, uriInfo)); + if (rec != null) { + list.add(createKeyDataInfo(rec, uriInfo)); + } } - return list; + + KeyDataInfos ret = new KeyDataInfos(); + ret.setKeyInfos(list); + + return ret; } public KeyData getKey(String keyId, RecoveryRequestData data) throws EBaseException { diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDataInfos.java b/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDataInfos.java new file mode 100644 index 000000000..b01184708 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDataInfos.java @@ -0,0 +1,87 @@ +// --- 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) 2012 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.servlet.key.model; + +import java.util.Collection; +import java.util.List; + +import javax.xml.bind.annotation.XmlElementRef; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlTransient; + +import com.netscape.cms.servlet.base.model.Link; + +@XmlRootElement(name = "SecurityDataInfos") +public class KeyDataInfos { + + protected Collection<KeyDataInfo> keyInfos; + protected List<Link> links; + + /** + * @return the keyInfos + */ + @XmlElementRef + public Collection<KeyDataInfo> getKeyInfos() { + return keyInfos; + } + /** + * @param keyInfos the keyInfos to set + */ + public void setKeyInfos(Collection<KeyDataInfo> keyInfos) { + this.keyInfos = keyInfos; + } + /** + * @return the links + */ + @XmlElementRef + public List<Link> getLinks() { + return links; + } + /** + * @param links the links to set + */ + public void setLinks(List<Link> links) { + this.links = links; + } + + @XmlTransient + public String getNext() { + if (links == null) { + return null; + } + for (Link link : links) { + if ("next".equals(link.getRelationship())) { + return link.getHref(); + } + } + return null; + } + + @XmlTransient + public String getPrevious() { + if (links == null) { + return null; + } + for (Link link : links) { + if ("previous".equals(link.getRelationship())) { + return link.getHref(); + } + } + return null; + } +} diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java index 3624b1bd6..ce53053d4 100644 --- a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java +++ b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java @@ -18,11 +18,11 @@ package com.netscape.cms.servlet.request; -import java.util.List; - +import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -33,7 +33,7 @@ import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; import com.netscape.cms.servlet.base.CMSResource; import com.netscape.cms.servlet.request.model.KeyRequestDAO; -import com.netscape.cms.servlet.request.model.KeyRequestInfo; +import com.netscape.cms.servlet.request.model.KeyRequestInfos; /** * @author alee @@ -41,7 +41,12 @@ import com.netscape.cms.servlet.request.model.KeyRequestInfo; */ @Path("/keyrequests") public class KeyRequestsResource extends CMSResource { - + + private static final int DEFAULT_START = 0; + private static final String DEFAULT_PAGESIZE = "20"; + private static final String DEFAULT_MAXRESULTS = "100"; + private static final String DEFAULT_MAXTIME = "10"; + @Context UriInfo uriInfo; @@ -50,24 +55,75 @@ public class KeyRequestsResource extends CMSResource { */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) - public List<KeyRequestInfo> listRequests() { + public KeyRequestInfos listRequests(@QueryParam("requestState") String requestState, + @QueryParam("requestType") String requestType, + @QueryParam("clientID") String clientID, + @QueryParam("start") String start_s, + @DefaultValue(DEFAULT_PAGESIZE) @QueryParam("pageSize") int pageSize, + @DefaultValue(DEFAULT_MAXRESULTS) @QueryParam("maxResults") int maxResults, + @DefaultValue(DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime) { // auth and authz - // parse search parameters from uriInfo and create search filter - // String clientID = uriInfo.getQueryParameters().getFirst(CLIENT_ID); - String filter = "requestState=complete"; + + // get ldap filter + String filter = createSearchFilter(requestState, requestType, clientID); + CMS.debug("listRequests: filter is " + filter); + + + // get start marker + int start = DEFAULT_START; + if (start_s != null) { + try { + if (start_s.trim().startsWith("0x")) { + start = Integer.parseInt(start_s.trim().substring(2), 16); + } else { + start = Integer.parseInt(start_s.trim()); + } + } catch (NumberFormatException e) { + CMS.debug("listRequests: NumberformatException: Invalid value for start " + start_s); + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + } + KeyRequestDAO reqDAO = new KeyRequestDAO(); - List<KeyRequestInfo> requests; + KeyRequestInfos requests; try { - CMS.debug("alee: getting requests"); - requests = reqDAO.listRequests(filter, uriInfo); - CMS.debug("alee: got request"); + requests = reqDAO.listRequests(filter, start, pageSize, maxResults, maxTime, uriInfo); } catch (EBaseException e) { - // log error + CMS.debug("listRequests: error in obtaining request results" + e); e.printStackTrace(); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } - CMS.debug("going into return"); return requests; } + + private String createSearchFilter(String requestState, String requestType, String clientID) { + String filter = ""; + int matches = 0; + + if ((requestState == null) && (requestType == null) && (clientID == null)) { + filter = "(requeststate=*)"; + return filter; + } + + if (requestState != null) { + filter += "(requeststate=" + requestState + ")"; + matches ++; + } + + if (requestType != null) { + filter += "(requesttype=" + requestType + ")"; + matches ++; + } + if (clientID != null) { + filter += "(clientID=" + clientID + ")"; + matches ++; + } + + if (matches > 1) { + filter = "(&" + filter + ")"; + } + + return filter; + } } diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestDAO.java b/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestDAO.java index b15e17c6d..16da23d8b 100644 --- a/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestDAO.java +++ b/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestDAO.java @@ -17,9 +17,11 @@ // --- END COPYRIGHT BLOCK --- package com.netscape.cms.servlet.request.model; +import java.net.URI; import java.util.ArrayList; import java.util.List; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; @@ -29,8 +31,10 @@ import com.netscape.certsrv.kra.IKeyRecoveryAuthority; import com.netscape.certsrv.request.IRequest; import com.netscape.certsrv.request.IRequestList; import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.IRequestVirtualList; import com.netscape.certsrv.request.RequestId; import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.base.model.Link; /** * @author alee @@ -39,6 +43,19 @@ import com.netscape.certsrv.request.RequestStatus; public class KeyRequestDAO { private IRequestQueue queue; + private String[] vlvFilters = { + "(requeststate=*)", "(requesttype=enrollment)", + "(requesttype=recovery)", "(requeststate=canceled)", + "(&(requeststate=canceled)(requesttype=enrollment))", + "(&(requeststate=canceled)(requesttype=recovery))", + "(requeststate=rejected)", + "(&(requeststate=rejected)(requesttype=enrollment))", + "(&(requeststate=rejected)(requesttype=recovery))", + "(requeststate=complete)", + "(&(requeststate=complete)(requesttype=enrollment))", + "(&(requeststate=complete)(requesttype=recovery))" + }; + public KeyRequestDAO() { IKeyRecoveryAuthority kra = null; kra = ( IKeyRecoveryAuthority ) CMS.getSubsystem( "kra" ); @@ -46,20 +63,88 @@ public class KeyRequestDAO { } /** - * This will find the requests in the database matching the specified search parameters - * Needs input validation and probably paging, maybe using the vlv functions - * @throws EBaseException + * Finds list of requests matching the specified search filter. + * + * If the filter corresponds to a VLV search, then that search is executed and the pageSize + * and start parameters are used. Otherwise, the maxResults and maxTime parameters are + * used in the regularly indexed search. + * + * @param filter - ldap search filter + * @param start - start position for VLV search + * @param pageSize - page size for VLV search + * @param maxResults - max results to be returned in normal search + * @param maxTime - max time for normal search + * @param uriInfo - uri context of request + * @return collection of key request info + * @throws EBaseException */ - public List<KeyRequestInfo> listRequests(String filter, UriInfo uriInfo) throws EBaseException { - List <KeyRequestInfo> list = new ArrayList<KeyRequestInfo>(); - IRequestList requests = queue.listRequestsByFilter(filter); - while (requests.hasMoreElements()) { - RequestId rid = (RequestId) requests.nextElement(); - IRequest request; - request = queue.findRequest(rid); - list.add(createKeyRequestInfo(request, uriInfo)); + public KeyRequestInfos listRequests(String filter, int start, int pageSize, int maxResults, int maxTime, + UriInfo uriInfo) throws EBaseException { + List <KeyRequestInfo> list = new ArrayList<KeyRequestInfo>(); + List <Link> links = new ArrayList<Link>(); + int totalSize = 0; + int current = 0; + + if (isVLVSearch(filter)) { + RequestId id = new RequestId(Integer.toString(start)); + IRequestVirtualList vlvlist = queue.getPagedRequestsByFilter(id, false, filter, + pageSize +1 , "requestId"); + totalSize = vlvlist.getSize(); + current = vlvlist.getCurrentIndex(); + + int numRecords = (totalSize > (current + pageSize)) ? pageSize : + totalSize - current; + + for (int i=0; i < numRecords; i++) { + IRequest request = vlvlist.getElementAt(i); + list.add(createKeyRequestInfo(request, uriInfo)); + } + } else { + // The non-vlv requests are indexed, but are not paginated. + // We should think about whether they should be, or if we need to + // limit the number of results returned. + IRequestList requests = queue.listRequestsByFilter(filter, maxResults, maxTime); + while (requests.hasMoreElements()) { + RequestId rid = (RequestId) requests.nextElement(); + IRequest request = queue.findRequest(rid); + if (request != null) { + list.add(createKeyRequestInfo(request, uriInfo)); + } + } + } + + // builder for vlv links + MultivaluedMap<String, String> params = uriInfo.getQueryParameters(); + UriBuilder builder = uriInfo.getAbsolutePathBuilder(); + if (params.containsKey("requestState")) { + builder.queryParam("requestState", params.getFirst("requestState")); + } + if (params.containsKey("requestType")) { + builder.queryParam("requestType", params.getFirst("requestType")); + } + builder.queryParam("start", "{start}"); + builder.queryParam("pageSize", "{pageSize}"); + + // next link + if (totalSize > current + pageSize) { + int next = current + pageSize + 1; + URI nextUri = builder.clone().build(next,pageSize); + Link nextLink = new Link("next", nextUri.toString(), "application/xml"); + links.add(nextLink); } - return list; + + // previous link + if (current >0) { + int previous = current - pageSize; + URI previousUri = builder.clone().build(previous,pageSize); + Link previousLink = new Link("previous", previousUri.toString(), "application/xml"); + links.add(previousLink); + } + + KeyRequestInfos ret = new KeyRequestInfos(); + ret.setRequests(list); + ret.setLinks(links); + return ret; } /** @@ -135,4 +220,13 @@ public class KeyRequestDAO { return ret; } + + private boolean isVLVSearch(String filter) { + for (int i=0; i < vlvFilters.length; i++) { + if (vlvFilters[i].equalsIgnoreCase(filter)) { + return true; + } + } + return false; + } } diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestInfos.java b/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestInfos.java new file mode 100644 index 000000000..dc1b6a5e4 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestInfos.java @@ -0,0 +1,89 @@ +// --- 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 com.netscape.cms.servlet.request.model; + +import java.util.Collection; +import java.util.List; + +import javax.xml.bind.annotation.XmlElementRef; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlTransient; + +import com.netscape.cms.servlet.base.model.Link; + +@XmlRootElement(name = "SecurityDataRequestInfos") +public class KeyRequestInfos { + protected Collection<KeyRequestInfo> requests; + protected List<Link> links; + + /** + * @return the requests + */ + @XmlElementRef + public Collection<KeyRequestInfo> getRequests() { + return requests; + } + + /** + * @param requests the requests to set + */ + public void setRequests(Collection<KeyRequestInfo> requests) { + this.requests = requests; + } + + /** + * @return the links + */ + @XmlElementRef + public List<Link> getLinks() { + return links; + } + + /** + * @param links the links to set + */ + public void setLinks(List<Link> links) { + this.links = links; + } + + @XmlTransient + public String getNext() { + if (links == null) { + return null; + } + for (Link link : links) { + if ("next".equals(link.getRelationship())) { + return link.getHref(); + } + } + return null; + } + + @XmlTransient + public String getPrevious() { + if (links == null) { + return null; + } + for (Link link : links) { + if ("previous".equals(link.getRelationship())) { + return link.getHref(); + } + } + return null; + } +} |