diff options
Diffstat (limited to 'base/common/src/com/netscape/cms/servlet/request')
10 files changed, 931 insertions, 116 deletions
diff --git a/base/common/src/com/netscape/cms/servlet/request/CertRequestResource.java b/base/common/src/com/netscape/cms/servlet/request/CertRequestResource.java index 5dc97650d..7bb23dbd5 100644 --- a/base/common/src/com/netscape/cms/servlet/request/CertRequestResource.java +++ b/base/common/src/com/netscape/cms/servlet/request/CertRequestResource.java @@ -27,7 +27,9 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import com.netscape.certsrv.request.RequestId; +import com.netscape.cms.servlet.request.model.AgentEnrollmentRequestData; import com.netscape.cms.servlet.request.model.CertRequestInfo; +import com.netscape.cms.servlet.request.model.CertRequestInfos; import com.netscape.cms.servlet.request.model.EnrollmentRequestData; @Path("/certrequest") @@ -41,29 +43,56 @@ public interface CertRequestResource { @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) public CertRequestInfo getRequestInfo(@PathParam("id") RequestId id); + @GET + @Path("{id}/agentView") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) + public AgentEnrollmentRequestData reviewRequest(@PathParam("id") RequestId id); + // Enrollment - used to test integration with a browser @POST @Path("enroll") @Produces({ MediaType.TEXT_XML }) @Consumes({ MediaType.APPLICATION_FORM_URLENCODED }) - public CertRequestInfo enrollCert(MultivaluedMap<String, String> form); + public CertRequestInfos enrollCert(MultivaluedMap<String, String> form); @POST @Path("enroll") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) - public CertRequestInfo enrollCert(EnrollmentRequestData data); + public CertRequestInfos enrollCert(EnrollmentRequestData data); @POST - @Path("approve/{id}") - public void approveRequest(@PathParam("id") RequestId id); + @Path("{id}/approve") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public void approveRequest(@PathParam("id") RequestId id, AgentEnrollmentRequestData data); @POST - @Path("reject/{id}") - public void rejectRequest(@PathParam("id") RequestId id); + @Path("{id}/reject") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public void rejectRequest(@PathParam("id") RequestId id, AgentEnrollmentRequestData data); @POST - @Path("cancel/{id}") - public void cancelRequest(@PathParam("id") RequestId id); + @Path("{id}/cancel") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public void cancelRequest(@PathParam("id") RequestId id, AgentEnrollmentRequestData data); + + @POST + @Path("{id}/update") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public void updateRequest(@PathParam("id") RequestId id, AgentEnrollmentRequestData data); + @POST + @Path("{id}/validate") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public void validateRequest(@PathParam("id") RequestId id, AgentEnrollmentRequestData data); + + @POST + @Path("{id}/unassign") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public void unassignRequest(@PathParam("id") RequestId id, AgentEnrollmentRequestData data); + + @POST + @Path("{id}/assign") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public void assignRequest(@PathParam("id") RequestId id, AgentEnrollmentRequestData data); } diff --git a/base/common/src/com/netscape/cms/servlet/request/CertRequestResourceService.java b/base/common/src/com/netscape/cms/servlet/request/CertRequestResourceService.java index 40f57a7a7..b31d9961d 100644 --- a/base/common/src/com/netscape/cms/servlet/request/CertRequestResourceService.java +++ b/base/common/src/com/netscape/cms/servlet/request/CertRequestResourceService.java @@ -18,15 +18,27 @@ package com.netscape.cms.servlet.request; +import javax.ws.rs.PathParam; import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.EAuthException; +import com.netscape.certsrv.authorization.EAuthzException; +import com.netscape.certsrv.base.BadRequestDataException; import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.profile.EDeferException; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.property.EPropertyException; import com.netscape.certsrv.request.RequestId; import com.netscape.cms.servlet.base.BadRequestException; import com.netscape.cms.servlet.base.CMSException; import com.netscape.cms.servlet.base.CMSResourceService; +import com.netscape.cms.servlet.request.model.AgentEnrollmentRequestData; import com.netscape.cms.servlet.request.model.CertRequestDAO; import com.netscape.cms.servlet.request.model.CertRequestInfo; +import com.netscape.cms.servlet.request.model.CertRequestInfos; import com.netscape.cms.servlet.request.model.EnrollmentRequestData; /** @@ -60,51 +72,119 @@ public class CertRequestResourceService extends CMSResourceService implements Ce } // Enrollment - used to test integration with a browser - public CertRequestInfo enrollCert(MultivaluedMap<String, String> form) { + public CertRequestInfos enrollCert(MultivaluedMap<String, String> form) { EnrollmentRequestData data = new EnrollmentRequestData(form); return enrollCert(data); } - public CertRequestInfo enrollCert(EnrollmentRequestData data) { - + public CertRequestInfos enrollCert(EnrollmentRequestData data) { + CertRequestInfos infos; if (data == null) { throw new BadRequestException("Bad data input into CertRequestResourceService.enrollCert!"); } CertRequestDAO dao = new CertRequestDAO(); try { - dao.submitRequest(data, uriInfo); + infos = dao.submitRequest(data, servletRequest, uriInfo, getLocale()); + } catch (EAuthException e) { + CMS.debug("enrollCert: authentication failed: " + e); + throw new CMSException(Response.Status.UNAUTHORIZED, e.toString()); + } catch (EAuthzException e) { + CMS.debug("enrollCert: authorization failed: " + e); + throw new CMSException(Response.Status.UNAUTHORIZED, e.toString()); + } catch (BadRequestDataException e) { + CMS.debug("enrollCert: bad request data: " + e); + throw new CMSException(Response.Status.BAD_REQUEST, e.toString()); } catch (EBaseException e) { - throw new CMSException("Problem enrolling cert in CertRequestResource.enrollCert!"); + throw new CMSException(e.toString()); } - //TODO implement - throw new CMSException("CertRequestResourceService.enrollCert not implemented!"); + return infos; } - public void approveRequest(RequestId id) { - if (id == null) { - throw new BadRequestException("Bad data input in CertRequestResourceService.approveRequest!"); - } - //TODO implement - throw new CMSException("Problem approving request in CertRequestResource.approveRequest!"); + public void approveRequest(RequestId id, AgentEnrollmentRequestData data) { + changeRequestState(id, data, "approve"); } - public void rejectRequest(RequestId id) { - if (id == null) { - throw new BadRequestException("Bad data input into CertRequestResourceService.rejectRequest!"); - } - //TODO implement + public void rejectRequest(RequestId id, AgentEnrollmentRequestData data) { + changeRequestState(id, data, "reject"); + } - throw new CMSException("Problem rejecting request in CertRequestResource.rejectRequest!"); + public void cancelRequest(RequestId id, AgentEnrollmentRequestData data) { + changeRequestState(id, data, "cancel"); + } + public void updateRequest(RequestId id, AgentEnrollmentRequestData data) { + changeRequestState(id, data, "update"); } - public void cancelRequest(RequestId id) { + public void validateRequest(RequestId id, AgentEnrollmentRequestData data) { + changeRequestState(id, data, "validate"); + } + + public void unassignRequest(RequestId id, AgentEnrollmentRequestData data) { + changeRequestState(id, data, "unassign"); + } + + public void assignRequest(RequestId id, AgentEnrollmentRequestData data) { + changeRequestState(id, data, "assign"); + } + + public void changeRequestState(RequestId id, AgentEnrollmentRequestData data, String op) { if (id == null) { - throw new BadRequestException("Bad data input in CertRequestResourceService.cancelRequest!"); + throw new BadRequestException("Bad data input in CertRequestResourceService. op:" + op); + } + + CertRequestDAO dao = new CertRequestDAO(); + try { + dao.changeRequestState(id, servletRequest, data, getLocale(), op); + } catch (ERejectException e) { + CMS.debug("changeRequestState: execution rejected " + e); + throw new CMSException(Response.Status.BAD_REQUEST, + CMS.getUserMessage(getLocale(), "CMS_PROFILE_REJECTED", e.toString())); + } catch (EDeferException e) { + CMS.debug("changeRequestState: execution defered " + e); + // TODO do we throw an exception here? + throw new CMSException(Response.Status.BAD_REQUEST, + CMS.getUserMessage(getLocale(), "CMS_PROFILE_DEFERRED", e.toString())); + } catch (BadRequestDataException e) { + CMS.debug("changeRequestState: bad request data: " + e); + throw new CMSException(Response.Status.BAD_REQUEST, e.toString()); + } catch (EPropertyException e) { + CMS.debug("changeRequestState: execution error " + e); + throw new CMSException(CMS.getUserMessage(getLocale(), + "CMS_PROFILE_PROPERTY_ERROR", e.toString())); + } catch (EProfileException e) { + CMS.debug("ProfileProcessServlet: execution error " + e); + throw new CMSException(CMS.getUserMessage(getLocale(), "CMS_INTERNAL_ERROR")); + } catch (EBaseException e) { + e.printStackTrace(); + throw new CMSException("Problem approving request in CertRequestResource.assignRequest!"); + } catch (RequestNotFoundException e) { + throw new CMSException(Response.Status.BAD_REQUEST, + CMS.getUserMessage(getLocale(), "CMS_REQUEST_NOT_FOUND", id.toString())); } - //TODO implement - throw new CMSException("Problem cancelling request in CertRequestResource.cancelRequest!"); } + + public AgentEnrollmentRequestData reviewRequest(@PathParam("id") RequestId id) { + // auth and authz + AgentEnrollmentRequestData info; + + CertRequestDAO dao = new CertRequestDAO(); + try { + info = dao.reviewRequest(servletRequest, id, uriInfo, getLocale()); + } catch (EBaseException e) { + // log error + e.printStackTrace(); + throw new CMSException("Error getting Cert request info!"); + } + + if (info == null) { + // request does not exist + throw new RequestNotFoundException(id); + } + + return info; + } + } diff --git a/base/common/src/com/netscape/cms/servlet/request/model/AgentEnrollmentRequestData.java b/base/common/src/com/netscape/cms/servlet/request/model/AgentEnrollmentRequestData.java new file mode 100644 index 000000000..fb0874353 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/request/model/AgentEnrollmentRequestData.java @@ -0,0 +1,252 @@ +//--- 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.request.model; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestIdAdapter; +import com.netscape.cms.servlet.profile.model.PolicyDefault; +import com.netscape.cms.servlet.profile.model.ProfileAttribute; +import com.netscape.cms.servlet.profile.model.ProfilePolicy; +import com.netscape.cms.servlet.profile.model.ProfilePolicySet; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class AgentEnrollmentRequestData extends EnrollmentRequestData { + + @XmlElement(name="ProfilePolicySet") + protected List<ProfilePolicySet> policySets = new ArrayList<ProfilePolicySet>(); + + protected String nonce; + + @XmlElement + @XmlJavaTypeAdapter(RequestIdAdapter.class) + protected RequestId requestId; + + protected String requestType; + + protected String requestStatus; + + protected String requestOwner; + + protected String requestCreationTime; + + protected String requestModificationTime; + + protected String requestNotes; + + protected String profileApprovedBy; + + protected String profileSetId; + + protected String profileIsVisible; + + protected String profileName; + + protected String profileDescription; + + protected String profileRemoteHost; + + protected String profileRemoteAddr; + + public String getNonce() { + return nonce; + } + + public void setNonce(String nonce) { + this.nonce = nonce; + } + + public RequestId getRequestId() { + return requestId; + } + + public void setRequestId(RequestId requestId) { + this.requestId = requestId; + } + + public String getRequestType() { + return requestType; + } + + public void setRequestType(String requestType) { + this.requestType = requestType; + } + + public String getRequestStatus() { + return requestStatus; + } + + public void setRequestStatus(String requestStatus) { + this.requestStatus = requestStatus; + } + + public String getRequestOwner() { + return requestOwner; + } + + public void setRequestOwner(String requestOwner) { + this.requestOwner = requestOwner; + } + + public String getRequestCreationTime() { + return requestCreationTime; + } + + public void setRequestCreationTime(String requestCreationTime) { + this.requestCreationTime = requestCreationTime; + } + + public String getRequestModificationTime() { + return requestModificationTime; + } + + public void setRequestModificationTime(String requestModificationTime) { + this.requestModificationTime = requestModificationTime; + } + + public String getRequestNotes() { + return requestNotes; + } + + public void setRequestNotes(String requestNotes) { + this.requestNotes = requestNotes; + } + + public String getProfileApprovedBy() { + return profileApprovedBy; + } + + public void setProfileApprovedBy(String profileApprovedBy) { + this.profileApprovedBy = profileApprovedBy; + } + + public String getProfileSetId() { + return profileSetId; + } + + public void setProfileSetId(String profileSetId) { + this.profileSetId = profileSetId; + } + + public String getProfileIsVisible() { + return profileIsVisible; + } + + public void setProfileIsVisible(String profileIsVisible) { + this.profileIsVisible = profileIsVisible; + } + + public String getProfileName() { + return profileName; + } + + public void setProfileName(String profileName) { + this.profileName = profileName; + } + + public String getProfileDescription() { + return profileDescription; + } + + public void setProfileDescription(String profileDescription) { + this.profileDescription = profileDescription; + } + + public String getProfileRemoteHost() { + return profileRemoteHost; + } + + public void setProfileRemoteHost(String profileRemoteHost) { + this.profileRemoteHost = profileRemoteHost; + } + + public String getProfileRemoteAddr() { + return profileRemoteAddr; + } + + public void setProfileRemoteAddr(String profileRemoteAddr) { + this.profileRemoteAddr = profileRemoteAddr; + } + + public String toString() { + try { + JAXBContext context = JAXBContext.newInstance(AgentEnrollmentRequestData.class); + Marshaller marshaller = context.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + marshaller.marshal(this, stream); + return stream.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public List<ProfilePolicySet> getPolicySets() { + return policySets; + } + + public void setPolicySets(List<ProfilePolicySet> policySets) { + this.policySets = policySets; + } + + public void addProfilePolicySet(ProfilePolicySet policySet) { + policySets.add(policySet); + } + + public void removeProfilePolicySet(ProfilePolicySet policySet) { + policySets.remove(policySet); + } + + @Override + public HashMap<String,String> toParams() { + HashMap<String,String> ret = super.toParams(); + + if (requestId != null) ret.put("requestId", requestId.toString()); + if (requestNotes != null) ret.put("requestNotes", requestNotes); + if (nonce != null) ret.put("nonces", nonce); + if (requestType != null) ret.put("requestType", requestType); + + for (ProfilePolicySet policySet: policySets) { + for (ProfilePolicy policy: policySet.getPolicies()) { + PolicyDefault def = policy.getDef(); + List<ProfileAttribute> attrs = def.getAttributes(); + for (ProfileAttribute attr: attrs) { + ret.put(attr.getName(), attr.getValue()); + } + } + } + return ret; + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/request/model/AgentEnrollmentRequestDataFactory.java b/base/common/src/com/netscape/cms/servlet/request/model/AgentEnrollmentRequestDataFactory.java new file mode 100644 index 000000000..fff1a59df --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/request/model/AgentEnrollmentRequestDataFactory.java @@ -0,0 +1,174 @@ +//--- 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.request.model; + +import java.util.Enumeration; +import java.util.Locale; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.UriInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.Nonces; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.profile.IProfileInput; +import com.netscape.certsrv.profile.IProfilePolicy; +import com.netscape.certsrv.property.EPropertyException; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.processors.Processor; +import com.netscape.cms.servlet.profile.model.PolicyConstraint; +import com.netscape.cms.servlet.profile.model.PolicyConstraintFactory; +import com.netscape.cms.servlet.profile.model.PolicyDefault; +import com.netscape.cms.servlet.profile.model.PolicyDefaultFactory; +import com.netscape.cms.servlet.profile.model.ProfileInput; +import com.netscape.cms.servlet.profile.model.ProfileInputFactory; +import com.netscape.cms.servlet.profile.model.ProfilePolicy; +import com.netscape.cms.servlet.profile.model.ProfilePolicySet; + +public class AgentEnrollmentRequestDataFactory { + + public static AgentEnrollmentRequestData create(IRequest request, IProfile profile, UriInfo uriInfo, Locale locale) throws EBaseException { + AgentEnrollmentRequestData ret = new AgentEnrollmentRequestData(); + + if (request.getRequestType().equals("renewal")) { + ret.setIsRenewal(true); + } else { + ret.setIsRenewal(false); + } + + ret.setRequestId(request.getRequestId()); + ret.setRequestType(request.getRequestType()); + ret.setRequestStatus(request.getRequestStatus().toString()); + if (request.getRequestOwner() == null) { + ret.setRequestOwner(""); + } else { + ret.setRequestOwner(request.getRequestOwner()); + } + ret.setRequestCreationTime(request.getCreationTime().toString()); + ret.setRequestModificationTime(request.getModificationTime().toString()); + + ret.setProfileId(profile.getId()); + ret.setProfileApprovedBy(request.getExtDataInString("profileApprovedBy")); + ret.setProfileSetId(request.getExtDataInString("profileSetId")); + if (profile.isVisible()) { + ret.setProfileIsVisible("true"); + } else { + ret.setProfileIsVisible("false"); + } + + ret.setProfileName(profile.getName(locale)); + ret.setProfileDescription(profile.getDescription(locale)); + ret.setProfileRemoteHost(request.getExtDataInString("profileRemoteHost")); + ret.setProfileRemoteAddr(request.getExtDataInString("profileRemoteAddr")); + if (request.getExtDataInString("requestNotes") == null) { + ret.setRequestNotes(""); + } else { + ret.setRequestNotes(request.getExtDataInString("requestNotes")); + } + + // populate profile inputs + Enumeration<String> inputIds = profile.getProfileInputIds(); + while (inputIds.hasMoreElements()) { + IProfileInput input = profile.getProfileInput(inputIds.nextElement()); + ProfileInput addInput = ProfileInputFactory.create(input, request, locale); + ret.addInput(addInput); + } + + String profileSetId = request.getExtDataInString("profileSetId"); + CMS.debug("createAgentCertRequestInfo: profileSetId=" + profileSetId); + Enumeration<String> policyIds = (profileSetId != null && profileSetId.length() > 0) ? + profile.getProfilePolicyIds(profileSetId) : null; + ProfilePolicySet dataPolicySet = new ProfilePolicySet(); + + if (policyIds != null) { + while (policyIds.hasMoreElements()) { + String id = policyIds.nextElement(); + CMS.debug("policyId:" + id); + IProfilePolicy policy = profile.getProfilePolicy(profileSetId, id); + ProfilePolicy dataPolicy = new ProfilePolicy(); + + //populate defaults + IPolicyDefault def = policy.getDefault(); + PolicyDefault dataDef = PolicyDefaultFactory.create(request, locale, def); + dataPolicy.setDef(dataDef); + + //populate constraints + PolicyConstraint dataCons = PolicyConstraintFactory.create(locale, policy.getConstraint()); + dataPolicy.setConstraint(dataCons); + + dataPolicySet.addPolicy(dataPolicy); + } + } + + + ret.addProfilePolicySet(dataPolicySet); + + // TODO populate profile outputs + return ret; + } + + public static AgentEnrollmentRequestData create(CMSRequest cmsReq, IProfile profile, Nonces nonces, Locale locale) + throws EPropertyException, EProfileException { + HttpServletRequest req = cmsReq.getHttpReq(); + IRequest ireq = cmsReq.getIRequest(); + IArgBlock params = cmsReq.getHttpParams(); + + AgentEnrollmentRequestData ret = new AgentEnrollmentRequestData(); + ret.setProfileId(profile.getId()); + ret.setRequestNotes(req.getParameter("requestNotes")); + ret.setRequestId(ireq.getRequestId()); + + if (nonces != null) { + ret.setNonce(req.getParameter(Processor.ARG_REQUEST_NONCE)); + } + + // populate profile policy values + String profileSetId = ireq.getExtDataInString("profileSetId"); + Enumeration<String> policyIds = (profileSetId != null && profileSetId.length() > 0) ? + profile.getProfilePolicyIds(profileSetId) : null; + ProfilePolicySet dataPolicySet = new ProfilePolicySet(); + + if (policyIds != null) { + while (policyIds.hasMoreElements()) { + String id = policyIds.nextElement(); + CMS.debug("policyId:" + id); + IProfilePolicy policy = profile.getProfilePolicy(profileSetId, id); + com.netscape.cms.servlet.profile.model.ProfilePolicy dataPolicy = + new com.netscape.cms.servlet.profile.model.ProfilePolicy(); + + //populate defaults + IPolicyDefault def = policy.getDefault(); + PolicyDefault dataDef = PolicyDefaultFactory.create(params, locale, def); + dataPolicy.setDef(dataDef); + + dataPolicySet.addPolicy(dataPolicy); + CMS.debug(dataPolicy.toString()); + } + } + + ret.addProfilePolicySet(dataPolicySet); + + return ret; + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/request/model/CMSRequestInfo.java b/base/common/src/com/netscape/cms/servlet/request/model/CMSRequestInfo.java index b86b39fbd..07a02cd1c 100644 --- a/base/common/src/com/netscape/cms/servlet/request/model/CMSRequestInfo.java +++ b/base/common/src/com/netscape/cms/servlet/request/model/CMSRequestInfo.java @@ -1,3 +1,20 @@ +//--- 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.request.model; import javax.xml.bind.annotation.XmlAccessType; diff --git a/base/common/src/com/netscape/cms/servlet/request/model/CertRequestDAO.java b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestDAO.java index 1d7f8aeae..da1c78661 100644 --- a/base/common/src/com/netscape/cms/servlet/request/model/CertRequestDAO.java +++ b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestDAO.java @@ -17,27 +17,31 @@ // --- END COPYRIGHT BLOCK --- package com.netscape.cms.servlet.request.model; -import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Locale; +import java.util.Random; -import javax.ws.rs.Path; -import javax.ws.rs.core.UriBuilder; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.UriInfo; -import netscape.security.x509.X509CertImpl; - import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.ca.ICertificateAuthority; -import com.netscape.certsrv.profile.IEnrollProfile; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.profile.IProfileSubsystem; 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.cert.CertResource; -import com.netscape.cms.servlet.request.CertRequestResource; +import com.netscape.cms.servlet.cert.EnrollmentProcessor; +import com.netscape.cms.servlet.cert.RenewalProcessor; +import com.netscape.cms.servlet.cert.RequestProcessor; +import com.netscape.cms.servlet.processors.Processor; +import com.netscape.cms.servlet.request.RequestNotFoundException; /** * @author alee @@ -46,16 +50,22 @@ import com.netscape.cms.servlet.request.CertRequestResource; public class CertRequestDAO extends CMSRequestDAO { private IRequestQueue queue; private ICertificateAuthority ca; + IProfileSubsystem ps; + private Nonces nonces = null; + private Random random = null; public static final String ATTR_SERIALNO = "serialNumber"; - private static final String REQ_COMPLETE = "complete"; + public static final String REQ_COMPLETE = "complete"; public CertRequestDAO() { - super("ca"); ca = (ICertificateAuthority) CMS.getSubsystem("ca"); queue = ca.getRequestQueue(); - + if (ca.noncesEnabled()) { + random = new Random(); + nonces = ca.getNonces(); + } + ps = (IProfileSubsystem) CMS.getSubsystem(IProfileSubsystem.ID); } /** @@ -122,86 +132,87 @@ public class CertRequestDAO extends CMSRequestDAO { } /** - * Submits an enrollment request and processes it. + * Gets info for a specific request * - * @param data - * @return info for the request submitted. + * @param id + * @return info for specific request * @throws EBaseException */ - public CertRequestInfo submitRequest(EnrollmentRequestData data, UriInfo uriInfo) throws EBaseException { - - //TODO perform actual profile request. - - throw new EBaseException("Not implemented."); - } - - public void approveRequest(RequestId id) throws EBaseException { - IRequest request = queue.findRequest(id); - request.setRequestStatus(RequestStatus.APPROVED); - queue.updateRequest(request); - } - - public void rejectRequest(RequestId id) throws EBaseException { + public AgentEnrollmentRequestData reviewRequest(HttpServletRequest servletRequest, RequestId id, + UriInfo uriInfo, Locale locale) throws EBaseException { IRequest request = queue.findRequest(id); - request.setRequestStatus(RequestStatus.CANCELED); - queue.updateRequest(request); - } + if (request == null) { + return null; + } + String profileId = request.getExtDataInString("profileId"); + IProfile profile = ps.getProfile(profileId); - public void cancelRequest(RequestId id) throws EBaseException { - IRequest request = queue.findRequest(id); - request.setRequestStatus(RequestStatus.REJECTED); - queue.updateRequest(request); + AgentEnrollmentRequestData info = AgentEnrollmentRequestDataFactory.create(request, profile, uriInfo, locale); + if (ca.noncesEnabled()) { + addNonce(info, servletRequest); + } + return info; } - private CertRequestInfo createCertRequestInfo(IRequest request, UriInfo uriInfo) { - CertRequestInfo ret = new CertRequestInfo(); - String requestType = request.getRequestType(); - String requestStatus = request.getRequestStatus().toString(); - - ret.setRequestType(requestType); - ret.setRequestStatus(requestStatus); - - ret.setCertRequestType(request.getExtDataInString("cert_request_type")); - - Path certRequestPath = CertRequestResource.class.getAnnotation(Path.class); - RequestId rid = request.getRequestId(); - - UriBuilder reqBuilder = uriInfo.getBaseUriBuilder(); - reqBuilder.path(certRequestPath.value() + "/" + rid); - ret.setRequestURL(reqBuilder.build().toString()); - - //Get Cert info if issued. - - String serialNoStr = null; - - if ((requestType != null) && (requestStatus != null)) { - if (requestStatus.equals(REQ_COMPLETE)) { - X509CertImpl impl[] = new X509CertImpl[1]; - impl[0] = request.getExtDataInCert(IEnrollProfile.REQUEST_ISSUED_CERT); - - BigInteger serialNo; - if (impl[0] != null) { - serialNo = impl[0].getSerialNumber(); - serialNoStr = serialNo.toString(); - } + private void addNonce(AgentEnrollmentRequestData info, HttpServletRequest servletRequest) throws EBaseException { + if (nonces != null) { + long n = random.nextLong(); + long m = nonces.addNonce(n, Processor.getSSLClientCertificate(servletRequest)); + if ((n + m) != 0) { + info.setNonce(Long.toString(m)); } + } + } + /** + * Submits an enrollment request and processes it. + * + * @param data + * @return info for the request submitted. + * @throws EBaseException + * @throws ServletException + */ + public CertRequestInfos submitRequest(EnrollmentRequestData data, HttpServletRequest request, UriInfo uriInfo, + Locale locale) throws EBaseException { + HashMap<String, Object> results = null; + if (data.getIsRenewal()) { + RenewalProcessor processor = new RenewalProcessor("caProfileSubmit", locale); + results = processor.processRenewal(data, request); + } else { + EnrollmentProcessor processor = new EnrollmentProcessor("caProfileSubmit", locale); + results = processor.processEnrollment(data, request); } - if (serialNoStr != null && !serialNoStr.equals("")) { - Path certPath = CertResource.class.getAnnotation(Path.class); - UriBuilder certBuilder = uriInfo.getBaseUriBuilder(); - certBuilder.path(certPath.value() + "/" + serialNoStr); - ret.setCertURL(certBuilder.build().toString()); + CertRequestInfos ret = new CertRequestInfos(); + ArrayList<CertRequestInfo> infos = new ArrayList<CertRequestInfo>(); + IRequest reqs[] = (IRequest[]) results.get(Processor.ARG_REQUESTS); + for (IRequest req : reqs) { + CertRequestInfo info = CertRequestInfoFactory.create(req, uriInfo); + infos.add(info); } + // TODO - what happens if the errorCode is internal error ? + ret.setRequests(infos); + ret.setLinks(null); return ret; } + public void changeRequestState(RequestId id, HttpServletRequest request, AgentEnrollmentRequestData data, + Locale locale, String op) throws EBaseException { + IRequest ireq = queue.findRequest(id); + if (ireq == null) { + throw new RequestNotFoundException(id); + } + + RequestProcessor processor = new RequestProcessor("caProfileProcess", locale); + processor.processRequest(request, data, ireq, op); + } + + @Override public CertRequestInfo createCMSRequestInfo(IRequest request, UriInfo uriInfo) { - return createCertRequestInfo(request, uriInfo); + return CertRequestInfoFactory.create(request, uriInfo); } } diff --git a/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfo.java b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfo.java index 25083126d..20c298136 100644 --- a/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfo.java +++ b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfo.java @@ -74,6 +74,7 @@ public class CertRequestInfo extends CMSRequestInfo { */ public CertId getCertId() { + if (certURL == null) return null; String id = certURL.substring(certURL.lastIndexOf("/") + 1); return new CertId(id); } diff --git a/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfoFactory.java b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfoFactory.java new file mode 100644 index 000000000..7045f3366 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfoFactory.java @@ -0,0 +1,81 @@ +//--- 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.request.model; + +import java.math.BigInteger; + +import javax.ws.rs.Path; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.core.UriInfo; + +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.profile.IEnrollProfile; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.RequestId; +import com.netscape.cms.servlet.cert.CertResource; +import com.netscape.cms.servlet.request.CertRequestResource; + +public class CertRequestInfoFactory { + + public static final String REQ_COMPLETE = "complete"; + + public static CertRequestInfo create(IRequest request, UriInfo uriInfo) { + CertRequestInfo ret = new CertRequestInfo(); + String requestType = request.getRequestType(); + String requestStatus = request.getRequestStatus().toString(); + + ret.setRequestType(requestType); + ret.setRequestStatus(requestStatus); + + ret.setCertRequestType(request.getExtDataInString("cert_request_type")); + + Path certRequestPath = CertRequestResource.class.getAnnotation(Path.class); + RequestId rid = request.getRequestId(); + + UriBuilder reqBuilder = uriInfo.getBaseUriBuilder(); + reqBuilder.path(certRequestPath.value() + "/" + rid); + ret.setRequestURL(reqBuilder.build().toString()); + + //Get cert info if issued. + String serialNoStr = null; + + if ((requestType != null) && (requestStatus != null)) { + if (requestStatus.equals(REQ_COMPLETE)) { + X509CertImpl impl[] = new X509CertImpl[1]; + impl[0] = request.getExtDataInCert(IEnrollProfile.REQUEST_ISSUED_CERT); + + BigInteger serialNo; + if (impl[0] != null) { + serialNo = impl[0].getSerialNumber(); + serialNoStr = serialNo.toString(); + } + } + + } + + if (serialNoStr != null && !serialNoStr.equals("")) { + Path certPath = CertResource.class.getAnnotation(Path.class); + UriBuilder certBuilder = uriInfo.getBaseUriBuilder(); + certBuilder.path(certPath.value() + "/" + serialNoStr); + ret.setCertURL(certBuilder.build().toString()); + } + return ret; + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestData.java b/base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestData.java index f2979ebce..caff0261d 100644 --- a/base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestData.java +++ b/base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestData.java @@ -24,8 +24,10 @@ package com.netscape.cms.servlet.request.model; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import javax.ws.rs.core.MultivaluedMap; import javax.xml.bind.JAXBContext; @@ -38,6 +40,7 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import com.netscape.cms.servlet.profile.model.ProfileInput; +import com.netscape.cms.servlet.profile.model.ProfileOutput; /** * @author jmagne @@ -50,6 +53,7 @@ public class EnrollmentRequestData { private static final String PROFILE_ID = "profileId"; private static final String RENEWAL = "renewal"; + private static final String SERIAL_NUM = "serial_num"; @XmlElement protected String profileId; @@ -57,18 +61,30 @@ public class EnrollmentRequestData { @XmlElement protected boolean isRenewal; + @XmlElement + protected String serialNum; // used for one type of renewal + + @XmlElement + protected String remoteHost; + + @XmlElement + protected String remoteAddr; + @XmlElement(name = "Input") protected List<ProfileInput> inputs = new ArrayList<ProfileInput>(); + @XmlElement(name = "Output") + protected List<ProfileOutput> outputs = new ArrayList<ProfileOutput>(); + public EnrollmentRequestData() { + // required for jaxb } public EnrollmentRequestData(MultivaluedMap<String, String> form) { profileId = form.getFirst(PROFILE_ID); String renewalStr = form.getFirst(RENEWAL); - + serialNum = form.getFirst(SERIAL_NUM); isRenewal = new Boolean(renewalStr); - } /** @@ -94,7 +110,22 @@ public class EnrollmentRequestData { return isRenewal; } - public ProfileInput addInput(String name) { + public void addInput(ProfileInput input) { + ProfileInput curInput = getInput(input.getInputId()); + if (curInput != null) { + getInputs().remove(curInput); + } + getInputs().add(input); + } + + public void deleteInput(ProfileInput input) { + ProfileInput curInput = getInput(input.getInputId()); + if (curInput != null) { + getInputs().remove(curInput); + } + } + + public ProfileInput createInput(String name) { ProfileInput oldInput = getInput(name); @@ -104,7 +135,7 @@ public class EnrollmentRequestData { ProfileInput newInput = new ProfileInput(); newInput.setInputId(name); - inputs.add(newInput); + getInputs().add(newInput); return newInput; } @@ -113,14 +144,11 @@ public class EnrollmentRequestData { ProfileInput input = null; - Iterator<ProfileInput> it = inputs.iterator(); + Iterator<ProfileInput> it = getInputs().iterator(); ProfileInput curInput = null; - while (it.hasNext()) - - { + while (it.hasNext()) { curInput = it.next(); - if (curInput != null && curInput.getInputId().equals(name)) break; } @@ -128,6 +156,35 @@ public class EnrollmentRequestData { return input; } + public void addOutput(ProfileOutput output) { + ProfileOutput curOutput = getOutput(output.getOutputId()); + if (curOutput != null) { + getOutputs().remove(curOutput); + } + getOutputs().add(output); + } + + public void deleteOutput(ProfileOutput output) { + ProfileOutput curOutput = getOutput(output.getOutputId()); + if (curOutput != null) { + getInputs().remove(curOutput); + } + } + + public ProfileOutput getOutput(String name) { + ProfileOutput output = null; + ProfileOutput curOutput = null; + + Iterator<ProfileOutput> it = getOutputs().iterator(); + while (it.hasNext()) { + curOutput = it.next(); + if (curOutput != null && curOutput.getOutputId().equals(name)) + break; + } + + return output; + } + /** * @param renewal the renewal to set */ @@ -135,6 +192,24 @@ public class EnrollmentRequestData { this.isRenewal = isRenewal; } + public HashMap<String, String> toParams() { + HashMap<String, String> ret = new HashMap<String, String>(); + ret.put("isRenewal", Boolean.valueOf(isRenewal).toString()); + if (profileId != null) ret.put(PROFILE_ID, profileId); + if (serialNum != null) ret.put(SERIAL_NUM, serialNum); + if (remoteHost != null) ret.put("remoteHost", remoteHost); + if (remoteAddr != null) ret.put("remoteAddr", remoteAddr); + + for (ProfileInput input: inputs) { + Map<String, String> attrs = input.getAttributes(); + for (Map.Entry<String, String> entry: attrs.entrySet()) { + ret.put(entry.getKey(), entry.getValue()); + } + } + + return ret; + } + public static void main(String args[]) throws Exception { EnrollmentRequestData data = new EnrollmentRequestData(); data.setProfileId("caUserCert"); @@ -142,13 +217,13 @@ public class EnrollmentRequestData { //Simulate a "caUserCert" Profile enrollment - ProfileInput certReq = data.addInput("KeyGenInput"); + ProfileInput certReq = data.createInput("KeyGenInput"); certReq.setInputAttr("cert_request_type", "crmf"); certReq.setInputAttr( "cert_request", "MIIBozCCAZ8wggEFAgQBMQp8MIHHgAECpQ4wDDEKMAgGA1UEAxMBeKaBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2NgaPHp0jiohcP4M+ufrJOZEqH8GV+liu5JLbT8nWpkfhC+8EUBqT6g+n3qroSxIcNVGNdcsBEqs1utvpItzyslAbpdyat3WwQep1dWMzo6RHrPDuIoxNA0Yka1n3qEX4U//08cLQtUv2bYglYgN/hOCNQemLV6vZWAv0n7zelkCAwEAAakQMA4GA1UdDwEB/wQEAwIF4DAzMBUGCSsGAQUFBwUBAQwIcmVnVG9rZW4wGgYJKwYBBQUHBQECDA1hdXRoZW50aWNhdG9yoYGTMA0GCSqGSIb3DQEBBQUAA4GBAJ1VOQcaSEhdHa94s8kifVbSZ2WZeYE5//qxL6wVlEst20vq4ybj13CetnbN3+WT49Zkwp7Fg+6lALKgSk47suTg3EbbQDm+8yOrC0nc/q4PTRoHl0alMmUxIhirYc1t3xoCMqJewmjX1bNP8lpVIZAYFZo4eZCpZaiSkM5BeHhz"); - ProfileInput subjectName = data.addInput("SubjectNameInput"); + ProfileInput subjectName = data.createInput("SubjectNameInput"); subjectName.setInputAttr("sn_uid", "jmagne"); subjectName.setInputAttr("sn_e", "jmagne@redhat.com"); subjectName.setInputAttr("sn_c", "US"); @@ -159,7 +234,7 @@ public class EnrollmentRequestData { subjectName.setInputAttr("sn_cn", "Common"); subjectName.setInputAttr("sn_o", "RedHat"); - ProfileInput submitter = data.addInput("SubmitterInfoInput"); + ProfileInput submitter = data.createInput("SubmitterInfoInput"); submitter.setInputAttr("requestor_name", "admin"); submitter.setInputAttr("requestor_email", "admin@redhat.com"); submitter.setInputAttr("requestor_phone", "650-555-5555"); @@ -199,4 +274,48 @@ public class EnrollmentRequestData { } } + public String getSerialNum() { + return serialNum; + } + + public void setSerialNum(String serialNum) { + this.serialNum = serialNum; + } + + public List<ProfileInput> getInputs() { + return inputs; + } + + public void setInputs(List<ProfileInput> inputs) { + this.inputs = inputs; + } + + public String getRemoteAddr() { + return remoteAddr; + } + + public void setRemoteAddr(String remoteAddr) { + this.remoteAddr = remoteAddr; + } + + public String getRemoteHost() { + return remoteHost; + } + + public void setRemoteHost(String remoteHost) { + this.remoteHost = remoteHost; + } + + public List<ProfileOutput> getOutputs() { + return outputs; + } + + public void setOutputs(List<ProfileOutput> outputs) { + this.outputs = outputs; + } + + public void setRenewal(boolean isRenewal) { + this.isRenewal = isRenewal; + } + } diff --git a/base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestDataFactory.java b/base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestDataFactory.java new file mode 100644 index 000000000..3a09b7608 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestDataFactory.java @@ -0,0 +1,51 @@ +//--- 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.request.model; + +import java.util.Enumeration; +import java.util.Locale; + +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.profile.IProfileInput; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.profile.model.ProfileInput; +import com.netscape.cms.servlet.profile.model.ProfileInputFactory; + +public class EnrollmentRequestDataFactory { + + public static EnrollmentRequestData create(CMSRequest cmsReq, IProfile profile, Locale locale) + throws EProfileException { + IArgBlock params = cmsReq.getHttpParams(); + + EnrollmentRequestData ret = new EnrollmentRequestData(); + ret.setProfileId(profile.getId()); + + // populate profile inputs + Enumeration<String> inputIds = profile.getProfileInputIds(); + while (inputIds.hasMoreElements()) { + IProfileInput input = profile.getProfileInput(inputIds.nextElement()); + ProfileInput addInput = ProfileInputFactory.create(input, params, locale); + ret.addInput(addInput); + } + + return ret; + } + +} |