source: trunk/grails-app/controllers/nl/tno/metagenomics/files/FileController.groovy @ 22

Last change on this file since 22 was 22, checked in by robert@…, 9 years ago

Implemented authorization checks on file downloads

File size: 6.1 KB
RevLine 
[2]1/**
2 * FileController
3 *
4 * Handles file uploads and downloads
5 *
6 * @author      Robert Horlings
7 * @since       20100601
8 * @package     dbnp.studycapturing
9 *
10 * Revision information:
11 * $Rev: 1182 $
12 * $Author: robert@isdat.nl $
13 * $Date: 2010-11-22 17:27:23 +0100 (Mon, 22 Nov 2010) $
14 */
15package nl.tno.metagenomics.files
16
[22]17import nl.tno.metagenomics.*;
18
[2]19import org.codehaus.groovy.grails.commons.ConfigurationHolder
20import grails.converters.*
21import org.apache.commons.io.IOUtils;
22
23class FileController {
24
25        def fileService;
26
27        /**
28         * Returns the file that is asked for from the temporary upload directory
29         * or a 404 error if the file doesn't exist
30         */
31        def get = {
[22]32                // Remove all old files from the upload directory, so the user
33                // can't retrieve any old file that were left behind
34                fileService.cleanDirectory();
35               
[2]36                retrieveFile( params, fileService.getUploadDir() );
37        }
38
39        /**
40         * Deletes the file that is asked for from the temporary upload directory
41         * or a 404 error if the file doesn't exist
42         */
43        def delete = {
44                File directory = fileService.getUploadDir()
45                String filename = checkFile( params, directory );
46               
[22]47                response.contentType = "text/plain"
48               
[2]49                try {
50                        fileService.delete( filename, directory );
51                        render ''
52                } catch( Exception e ) {
53                        response.status = 500;
54                        render e.getMessage();
55                }
56        }
57
58        /**
59         * Returns the file that is asked for from the temporary upload directory
60         * or a 404 error if the file doesn't exist
61         */
62        def getPermanent  = {
[22]63                if( checkPermissions( params, fileService.absolutePath( ConfigurationHolder.config.metagenomics.fileDir ) ) ) {
64                        retrieveFile( params, fileService.absolutePath( ConfigurationHolder.config.metagenomics.fileDir ) );
65                } else {
66                        render 'No access';
67                }
[2]68        }
[22]69       
70        /**
71         * Checks whether the user is allowed to access this file. He is only allowed to
72         * if he has access to the study this file belongs to.
73         *
74         * The file could be pointed to in several locations:
75         *   - SequenceData.sequenceFile
76         *   - SequenceData.qualityFile
77         *   - Run.parameterFile
78         *   
79         * If the file is not mentioned in any of these locations, it should not be returned by this system and
80         * a 404 error is given. If the user doesn't have access to the file, a 403 is given.
81         *
82         * @param params        HTTP request parameters
83         * @param directory     File object representing the directory to search in
84         */
85        private boolean checkPermissions( params, directory ) {
86                String filename = checkFile( params, directory );
87               
88                if( !filename )
89                        return;
90               
91                // Search for the file in the sequenceData file fields
92                def sd = SequenceData.findBySequenceFileOrQualityFile( filename, filename );
93                if( sd ) {
94                        if( sd.sample?.sample?.study?.canRead( session.user ) ) {
95                                return true;
96                        } else {
97                                response.setStatus( 403, "Not authorized to access this file" );
98                                return false;
99                        }
100                }
101               
102                // Search for the file in run file fields. If the file is found in that spot
103                // it is freely accessible by any logged in user
104                def run = Run.findByParameterFile( filename );
105                if( run ) {
106                        if( session.user ) {
107                                return true;
108                        } else {
109                                response.setStatus( 403, "Not authorized to access this file" );
110                                return false;
111                        }
112                }
113               
114                // Otherwise, the file should not be accessed this way
115                response.setStatus( 404, "File not found" );
116                return false;
117        }
[2]118
119        private void retrieveFile( params, directory ) {
120                String filename = checkFile( params, directory );
121                def file = fileService.get( filename, directory );
122
123                //response.setContentType("application/octet-stream")
124                //response.setContentType( "image/jpeg" );
125
126                // Return the file
127                response.setHeader "Content-disposition", "attachment; filename=${filename}"
128                response.outputStream << file.newInputStream()
129                response.outputStream.flush()
130        }
131
132        private String checkFile( params, directory ) {
133                def fileExists;
134
135                // Filename is not url decoded for some reason
136                def coder = new org.apache.commons.codec.net.URLCodec()
137                def filename = coder.decode(params.id)
138
139                if( !filename ) {
[22]140                        response.contentType = "text/plain"
[2]141                        response.status = 404;
142                        render( "File not found" );
143                        return;
144                }
145
146                // Security check to prevent accessing files in other directories
147                if( filename.contains( '..' ) ) {
[22]148                        response.contentType = "text/plain"
[2]149                        response.status = 500;
150                        render "Invalid filename given";
151                        return;
152                }
153
154                try {
155                        fileExists = fileService.fileExists( filename, directory )
156                } catch( FileNotFoundException e ) {
157                        fileExists = false;
158                }
159                if( !filename || !fileExists ) {
[22]160                        response.contentType = "text/plain"
[2]161                        response.status = 404;
162                        render( "File not found" );
163                        return;
164                }
165               
166                return filename;
167        }
168
169        /**
170         * Uploads a file and returns the filename under which the file is saved
171         */
172        def upload = {
173                // If an old file exists, delete it
174                if( params.get( 'oldFile' ) ) {
175                        fileService.delete( params.get( 'oldFile' ) );
176                }
177
178                render moveUploadedFile( fileService. getUploadDir() ) as JSON
179        }
180
181        protected def moveUploadedFile(File absolutePath ) {
182                PrintWriter writer = null;
183                InputStream is = null;
184                FileOutputStream fos = null;
185
186                try {
187                        writer = response.getWriter();
188                } catch (IOException ex) {
189                        log(OctetStreamReader.class.getName() + "has thrown an exception: " + ex.getMessage());
190                }
191
192                String filename = request.getHeader("X-File-Name");
193
194                // URL decode the filename
195                def coder = new org.apache.commons.codec.net.URLCodec()
196                filename = coder.decode(filename)
197
198                String newFilename = fileService.getUniqueFilename( filename, absolutePath );
199                try {
200                        is = request.getInputStream();
201                        fos = new FileOutputStream(new File(absolutePath, newFilename));
202                        IOUtils.copy(is, fos);
203                        response.setStatus(response.SC_OK);
204                        return [ 'success': true, 'filename': newFilename ]
205                } catch (FileNotFoundException ex) {
206                        response.setStatus(response.SC_INTERNAL_SERVER_ERROR);
207                        log(OctetStreamReader.class.getName() + "has thrown an exception: " + ex.getMessage());
208
209                        return [ 'success': false ]
210                } catch (IOException ex) {
211                        response.setStatus(response.SC_INTERNAL_SERVER_ERROR);
212                        log(OctetStreamReader.class.getName() + "has thrown an exception: " + ex.getMessage());
213
214                        return [ 'success': false ]
215                } finally {
216                        try {
217                                fos.close();
218                                is.close();
219                        } catch (IOException ignored) {
220                        }
221                }
222        }
223
224
225}
Note: See TracBrowser for help on using the repository browser.