001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 //========================================================================
018 //Copyright 2007 CSC - Scientific Computing Ltd.
019 //========================================================================
020 package org.apache.activemq.util;
021
022
023 import java.io.File;
024 import java.io.FileOutputStream;
025 import java.io.IOException;
026 import java.net.HttpURLConnection;
027 import java.net.URL;
028
029 import javax.servlet.Filter;
030 import javax.servlet.FilterChain;
031 import javax.servlet.FilterConfig;
032 import javax.servlet.ServletException;
033 import javax.servlet.ServletRequest;
034 import javax.servlet.ServletResponse;
035 import javax.servlet.UnavailableException;
036 import javax.servlet.http.HttpServletRequest;
037 import javax.servlet.http.HttpServletResponse;
038
039 import org.slf4j.Logger;
040 import org.slf4j.LoggerFactory;
041
042
043 /**
044 * <p>
045 * Adds support for HTTP PUT, MOVE and DELETE methods. If init parameters
046 * read-permission-role and write-permission-role are defined then all requests
047 * are authorized using the defined roles. Also GET methods are authorized.
048 * </p>
049 *
050 * @author Aleksi Kallio
051 */
052 public class RestFilter implements Filter {
053 private static final Logger LOG = LoggerFactory.getLogger(RestFilter.class);
054
055 private static final String HTTP_HEADER_DESTINATION = "Destination";
056 private static final String HTTP_METHOD_MOVE = "MOVE";
057 private static final String HTTP_METHOD_PUT = "PUT";
058 private static final String HTTP_METHOD_GET = "GET";
059 private static final String HTTP_METHOD_DELETE = "DELETE";
060
061 private String readPermissionRole;
062 private String writePermissionRole;
063 private FilterConfig filterConfig;
064
065 public void init(FilterConfig filterConfig) throws UnavailableException {
066 this.filterConfig = filterConfig;
067 readPermissionRole = filterConfig.getInitParameter("read-permission-role");
068 writePermissionRole = filterConfig.getInitParameter("write-permission-role");
069 }
070
071 private File locateFile(HttpServletRequest request) {
072 return new File(filterConfig.getServletContext().getRealPath(request.getServletPath()), request.getPathInfo());
073 }
074
075 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
076 if (!(request instanceof HttpServletRequest && response instanceof HttpServletResponse)) {
077 if (LOG.isDebugEnabled()) {
078 LOG.debug("request not HTTP, can not understand: " + request.toString());
079 }
080 chain.doFilter(request, response);
081 return;
082 }
083
084 HttpServletRequest httpRequest = (HttpServletRequest)request;
085 HttpServletResponse httpResponse = (HttpServletResponse)response;
086
087 if (httpRequest.getMethod().equals(HTTP_METHOD_MOVE)) {
088 doMove(httpRequest, httpResponse);
089 } else if (httpRequest.getMethod().equals(HTTP_METHOD_PUT)) {
090 doPut(httpRequest, httpResponse);
091 } else if (httpRequest.getMethod().equals(HTTP_METHOD_GET)) {
092 if (checkGet(httpRequest, httpResponse)) {
093 chain.doFilter(httpRequest, httpResponse); // actual processing
094 // done elsewhere
095 }
096 } else if (httpRequest.getMethod().equals(HTTP_METHOD_DELETE)) {
097 doDelete(httpRequest, httpResponse);
098 } else {
099 chain.doFilter(httpRequest, httpResponse);
100 }
101 }
102
103 protected void doMove(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
104 if (LOG.isDebugEnabled()) {
105 LOG.debug("RESTful file access: MOVE request for " + request.getRequestURI());
106 }
107
108 if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) {
109 response.sendError(HttpURLConnection.HTTP_FORBIDDEN);
110 return;
111 }
112
113 File file = locateFile(request);
114 String destination = request.getHeader(HTTP_HEADER_DESTINATION);
115
116 if (destination == null) {
117 response.sendError(HttpURLConnection.HTTP_BAD_REQUEST, "Destination header not found");
118 return;
119 }
120
121 try {
122 URL destinationUrl = new URL(destination);
123 IOHelper.copyFile(file, new File(destinationUrl.getFile()));
124 IOHelper.deleteFile(file);
125 } catch (IOException e) {
126 response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // file
127 // could
128 // not
129 // be
130 // moved
131 return;
132 }
133
134 response.setStatus(HttpURLConnection.HTTP_NO_CONTENT); // we return no
135 // content
136 }
137
138 protected boolean checkGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
139 if (LOG.isDebugEnabled()) {
140 LOG.debug("RESTful file access: GET request for " + request.getRequestURI());
141 }
142
143 if (readPermissionRole != null && !request.isUserInRole(readPermissionRole)) {
144 response.sendError(HttpURLConnection.HTTP_FORBIDDEN);
145 return false;
146 } else {
147 return true;
148 }
149 }
150
151 protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
152 if (LOG.isDebugEnabled()) {
153 LOG.debug("RESTful file access: PUT request for " + request.getRequestURI());
154 }
155
156 if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) {
157 response.sendError(HttpURLConnection.HTTP_FORBIDDEN);
158 return;
159 }
160
161 File file = locateFile(request);
162
163 if (file.exists()) {
164 boolean success = file.delete(); // replace file if it exists
165 if (!success) {
166 response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // file
167 // existed
168 // and
169 // could
170 // not
171 // be
172 // deleted
173 return;
174 }
175 }
176
177 FileOutputStream out = new FileOutputStream(file);
178 try {
179 IOHelper.copyInputStream(request.getInputStream(), out);
180 } catch (IOException e) {
181 LOG.warn("Exception occured" , e);
182 throw e;
183 } finally {
184 out.close();
185 }
186
187 response.setStatus(HttpURLConnection.HTTP_NO_CONTENT); // we return no
188 // content
189 }
190
191 protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
192 if (LOG.isDebugEnabled()) {
193 LOG.debug("RESTful file access: DELETE request for " + request.getRequestURI());
194 }
195
196 if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) {
197 response.sendError(HttpURLConnection.HTTP_FORBIDDEN);
198 return;
199 }
200
201 File file = locateFile(request);
202
203 if (!file.exists()) {
204 response.sendError(HttpURLConnection.HTTP_NOT_FOUND); // file not
205 // found
206 return;
207 }
208
209 boolean success = IOHelper.deleteFile(file); // actual delete operation
210
211 if (success) {
212 response.setStatus(HttpURLConnection.HTTP_NO_CONTENT); // we return
213 // no
214 // content
215 } else {
216 response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // could
217 // not
218 // be
219 // deleted
220 // due
221 // to
222 // internal
223 // error
224 }
225 }
226
227 public void destroy() {
228 // nothing to destroy
229 }
230 }