Author: jawi
Date: Thu Nov 21 15:58:26 2013
New Revision: 1544231
URL: http://svn.apache.org/r1544231
Log:
ACE-436 - fixed possible resource leak:
- a possible resource leak could occur when handling package
delivery to an agent that uses content-ranges during the
agent update retrieval;
- restored the authorization functionality for this servlet,
as this was not yet/no longer implemented, but should be,
as this is a public endpoint;
- code formatting applied & compiler warnings removed.
Modified:
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AgentDeploymentServlet.java
Modified:
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AgentDeploymentServlet.java
URL:
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AgentDeploymentServlet.java?rev=1544231&r1=1544230&r2=1544231&view=diff
==============================================================================
---
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AgentDeploymentServlet.java
(original)
+++
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AgentDeploymentServlet.java
Thu Nov 21 15:58:26 2013
@@ -18,6 +18,9 @@
*/
package org.apache.ace.deployment.servlet;
+import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+
+import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -41,11 +44,11 @@ import javax.xml.xpath.XPathFactory;
import org.apache.ace.authentication.api.AuthenticationService;
import org.apache.ace.connectionfactory.ConnectionFactory;
-import org.apache.felix.dm.DependencyManager;
import org.osgi.framework.Version;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.User;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -58,27 +61,77 @@ public class AgentDeploymentServlet exte
/** URL to the OBR that is used for finding versions of the agent. */
private static final String KEY_OBR_URL = "obr.url";
+ private static final String XPATH_QUERY = "/repository/resource[@uri]";
+
public static final String VERSIONS = "versions";
public static final String BUNDLE_MIMETYPE = "application/octet-stream";
public static final String TEXT_MIMETYPE = "text/plain";
-
+
// injected by Dependency Manager
- private volatile DependencyManager m_dm;
private volatile LogService m_log;
private volatile AuthenticationService m_authService;
private volatile ConnectionFactory m_connectionFactory;
+ // See updated()
+ private boolean m_useAuth = false;
+ private URL m_obrURL;
- private volatile boolean m_useAuth = false;
- private static final String XPATH_QUERY = "/repository/resource[@uri]";
private final String m_repositoryXML = "repository.xml";
- private URL m_obrURL;
-
+
+ /**
+ * Gets the actual text from a named item contained in the given node map.
+ *
+ * @param map
+ * the node map to get the named item from;
+ * @param name
+ * the name of the item to get.
+ * @return the text of the named item, can be <code>null</code> in case
the named item does not exist, or has no
+ * text.
+ */
+ private static String getNamedItemText(NamedNodeMap map, String name) {
+ Node namedItem = map.getNamedItem(name);
+ if (namedItem == null) {
+ return null;
+ }
+ else {
+ return namedItem.getTextContent();
+ }
+ }
+
+ @Override
+ public void updated(Dictionary settings) throws ConfigurationException {
+ if (settings != null) {
+ String useAuthString = (String)
settings.get(KEY_USE_AUTHENTICATION);
+ if (useAuthString == null
+ || !("true".equalsIgnoreCase(useAuthString) ||
"false".equalsIgnoreCase(useAuthString))) {
+ throw new ConfigurationException(KEY_USE_AUTHENTICATION,
"Missing or invalid value!");
+ }
+ boolean useAuth = Boolean.parseBoolean(useAuthString);
+ m_useAuth = useAuth;
+
+ String obrURL = (String) settings.get(KEY_OBR_URL);
+ try {
+ URL url = new URL(obrURL);
+ m_obrURL = url;
+ }
+ catch (MalformedURLException e) {
+ throw new ConfigurationException(KEY_OBR_URL, "Invalid value,
not a URL.", e);
+ }
+ if (obrURL == null) {
+ throw new ConfigurationException(KEY_OBR_URL, "Missing " +
+ "value!");
+ }
+ }
+ else {
+ m_useAuth = false;
+ m_obrURL = null;
+ }
+ }
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
try {
String[] pathElements =
verifyAndGetPathElements(request.getPathInfo());
- String targetID = pathElements[1]; // in the future we might use
this for per target approval
+ // String targetID = pathElements[1]; // in the future we might
use this for per target approval
String agentID = pathElements[2];
int numberOfElements = pathElements.length;
if (numberOfElements == 4) {
@@ -93,55 +146,63 @@ public class AgentDeploymentServlet exte
e.handleAsHttpError(response);
}
}
-
- private String[] verifyAndGetPathElements(String path) throws
AceRestException {
- if (path == null) {
- throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST,
"Request URI is invalid, no path specified.");
- }
- String[] elements = path.split("/");
- int numberOfElements = elements.length;
- if ((numberOfElements < 4) || (numberOfElements > 5) ||
!VERSIONS.equals(elements[3])) {
- throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST,
"Request URI elements are invalid: " + path);
- }
- return elements;
+
+ protected URLConnection openConnection(URL url) throws IOException {
+ return m_connectionFactory.createConnection(url);
}
- private List<Version> getVersions(String agentID) throws AceRestException {
- try {
- return getVersionsFromOBR(m_obrURL, agentID);
- }
- catch (XPathExpressionException e) {
- throw new AceRestException(HttpServletResponse.SC_NOT_FOUND,
"Unknown agent (" + agentID + ")");
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
+ if (!authenticate(req)) {
+ // Authentication failed; don't proceed with the original
request...
+ resp.sendError(SC_UNAUTHORIZED);
}
- catch (IOException ioe) {
- m_log.log(LogService.LOG_WARNING, "Error getting available
versions.", ioe);
- throw new
AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error getting
available versions.");
+ else {
+ // Authentication successful, proceed with original request...
+ super.service(req, resp);
}
}
- private List<Version> getVersionsFromOBR(URL obrBaseUrl, String agentID)
throws XPathExpressionException, IOException {
- InputStream input = null;
- NodeList resources = getOBRNodeList(input);
- List<Version> obrList = new ArrayList<Version>();
- for (int nResource = 0; nResource < resources.getLength();
nResource++) {
- Node resource = resources.item(nResource);
- NamedNodeMap attr = resource.getAttributes();
-
- String uri = getNamedItemText(attr, "uri");
- if (uri == null || uri.equals("")) {
- m_log.log(LogService.LOG_ERROR, "Skipping resource without uri
from repository " + obrBaseUrl);
- continue;
+ /**
+ * Authenticates, if needed the user with the information from the given
request.
+ *
+ * @param request
+ * the request to obtain the credentials from, cannot be
<code>null</code>.
+ * @return <code>true</code> if the authentication was successful,
<code>false</code> otherwise.
+ */
+ private boolean authenticate(HttpServletRequest request) {
+ if (m_useAuth) {
+ User user = m_authService.authenticate(request);
+ if (user == null) {
+ m_log.log(LogService.LOG_INFO, "Authentication failure!");
}
+ return (user != null);
+ }
+ return true;
+ }
- String symbolicname = getNamedItemText(attr, "symbolicname");
- if (agentID.equals(symbolicname)) {
- Version version = new Version(getNamedItemText(attr,
"version"));
- obrList.add(version);
+ private void closeSilently(Closeable resource) {
+ try {
+ if (resource != null) {
+ resource.close();
}
}
- Collections.sort(obrList);
- return obrList;
+ catch (IOException e) {
+ m_log.log(LogService.LOG_WARNING, "Exception trying to close
stream after request. ", e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ private URL createOBRURL() throws MalformedURLException {
+ try {
+ return new URL(m_obrURL, m_repositoryXML);
+ }
+ catch (MalformedURLException e) {
+ m_log.log(LogService.LOG_ERROR, "Error retrieving repository.xml
from " + m_obrURL);
+ throw e;
+ }
}
+
private InputStream getAgentFromOBR(URL obrBaseUrl, String agentID,
Version version) throws XPathExpressionException, IOException {
InputStream input = null;
NodeList resources = getOBRNodeList(input);
@@ -203,80 +264,71 @@ public class AgentDeploymentServlet exte
return resources;
}
- private URL createOBRURL() throws MalformedURLException {
+ private List<Version> getVersions(String agentID) throws AceRestException {
try {
- return new URL(m_obrURL, m_repositoryXML);
- }
- catch (MalformedURLException e) {
- m_log.log(LogService.LOG_ERROR, "Error retrieving repository.xml
from " + m_obrURL);
- throw e;
+ return getVersionsFromOBR(m_obrURL, agentID);
}
- }
- protected URLConnection openConnection(URL url) throws IOException {
- return m_connectionFactory.createConnection(url);
- }
- /**
- * Gets the actual text from a named item contained in the given node map.
- *
- * @param map the node map to get the named item from;
- * @param name the name of the item to get.
- * @return the text of the named item, can be <code>null</code> in case
the named item does not exist, or has no text.
- */
- private static String getNamedItemText(NamedNodeMap map, String name) {
- Node namedItem = map.getNamedItem(name);
- if (namedItem == null) {
- return null;
+ catch (XPathExpressionException e) {
+ throw new AceRestException(HttpServletResponse.SC_NOT_FOUND,
"Unknown agent (" + agentID + ")");
}
- else {
- return namedItem.getTextContent();
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_WARNING, "Error getting available
versions.", ioe);
+ throw new
AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error getting
available versions.");
}
}
-
- private void handleVersionsRequest(List<Version> versions,
HttpServletResponse response) throws AceRestException {
- ServletOutputStream output = null;
- response.setContentType(TEXT_MIMETYPE);
- try {
- output = response.getOutputStream();
- for (Version version : versions) {
- output.print(version.toString());
- output.print("\n");
+ @SuppressWarnings("unchecked")
+ private List<Version> getVersionsFromOBR(URL obrBaseUrl, String agentID)
throws XPathExpressionException, IOException {
+ InputStream input = null;
+ NodeList resources = getOBRNodeList(input);
+ List<Version> obrList = new ArrayList<Version>();
+ for (int nResource = 0; nResource < resources.getLength();
nResource++) {
+ Node resource = resources.item(nResource);
+ NamedNodeMap attr = resource.getAttributes();
+
+ String uri = getNamedItemText(attr, "uri");
+ if (uri == null || uri.equals("")) {
+ m_log.log(LogService.LOG_ERROR, "Skipping resource without uri
from repository " + obrBaseUrl);
+ continue;
+ }
+
+ String symbolicname = getNamedItemText(attr, "symbolicname");
+ if (agentID.equals(symbolicname)) {
+ Version version = new Version(getNamedItemText(attr,
"version"));
+ obrList.add(version);
}
}
- catch (IOException e) {
- throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST,
"Request URI is invalid");
- }
- finally {
- tryClose(output);
- }
+ Collections.sort(obrList);
+ return obrList;
}
private void handlePackageDelivery(String agentID, Version version,
HttpServletRequest request, HttpServletResponse response) throws
AceRestException {
- ServletOutputStream output = null;
+ InputStream is = null;
+ OutputStream os = null;
try {
// Wrap response to add support for range requests
response = new ContentRangeResponseWrapper(request, response);
- InputStream inputStream = null;
try {
- inputStream = getAgentFromOBR(m_obrURL, agentID, version);
- if (inputStream == null) {
+ is = getAgentFromOBR(m_obrURL, agentID, version);
+ if (is == null) {
throw (AceRestException) new
AceRestException(HttpServletResponse.SC_NOT_FOUND, "Agent not found in OBR.");
}
}
catch (XPathExpressionException e) {
throw (AceRestException) new
AceRestException(HttpServletResponse.SC_NOT_FOUND, "Agent not found: error
parsing OBR").initCause(e);
}
+
response.setContentType(BUNDLE_MIMETYPE);
- output = response.getOutputStream();
+
+ os = response.getOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int bytes;
- while ((bytes = inputStream.read(buffer)) != -1) {
- output.write(buffer, 0, bytes);
+ while ((bytes = is.read(buffer)) != -1) {
+ os.write(buffer, 0, bytes);
}
- output.flush();
- inputStream.close();
+ os.flush();
}
catch (IllegalArgumentException e) {
throw (AceRestException) new
AceRestException(HttpServletResponse.SC_BAD_REQUEST, "Request URI is
invalid").initCause(e);
@@ -284,47 +336,40 @@ public class AgentDeploymentServlet exte
catch (IOException e) {
throw (AceRestException) new
AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not
deliver package").initCause(e);
}
+ finally {
+ closeSilently(is);
+ closeSilently(os);
+ }
}
- private void tryClose(OutputStream output) {
+ private void handleVersionsRequest(List<Version> versions,
HttpServletResponse response) throws AceRestException {
+ ServletOutputStream output = null;
+
+ response.setContentType(TEXT_MIMETYPE);
try {
- if (output != null) {
- output.close();
+ output = response.getOutputStream();
+ for (Version version : versions) {
+ output.print(version.toString());
+ output.print("\n");
}
}
catch (IOException e) {
- m_log.log(LogService.LOG_WARNING, "Exception trying to close
stream after request. ", e);
- throw new RuntimeException(e);
+ throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST,
"Request URI is invalid");
+ }
+ finally {
+ closeSilently(output);
}
}
- @Override
- public void updated(Dictionary settings) throws ConfigurationException {
- if (settings != null) {
- String useAuthString = (String)
settings.get(KEY_USE_AUTHENTICATION);
- if (useAuthString == null
- || !("true".equalsIgnoreCase(useAuthString) ||
"false".equalsIgnoreCase(useAuthString))) {
- throw new ConfigurationException(KEY_USE_AUTHENTICATION,
"Missing or invalid value!");
- }
- boolean useAuth = Boolean.parseBoolean(useAuthString);
- m_useAuth = useAuth;
-
- String obrURL = (String) settings.get(KEY_OBR_URL);
- try {
- URL url = new URL(obrURL);
- m_obrURL = url;
- }
- catch (MalformedURLException e) {
- throw new ConfigurationException(KEY_OBR_URL, "Invalid value,
not a URL.", e);
- }
- if (obrURL == null) {
- throw new ConfigurationException(KEY_OBR_URL, "Missing " +
- "value!");
- }
+ private String[] verifyAndGetPathElements(String path) throws
AceRestException {
+ if (path == null) {
+ throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST,
"Request URI is invalid, no path specified.");
}
- else {
- m_useAuth = false;
- m_obrURL = null;
+ String[] elements = path.split("/");
+ int numberOfElements = elements.length;
+ if ((numberOfElements < 4) || (numberOfElements > 5) ||
!VERSIONS.equals(elements[3])) {
+ throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST,
"Request URI elements are invalid: " + path);
}
+ return elements;
}
}