001/*
002 *  Copyright 2010 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.forms.data;
017
018import java.io.IOException;
019import java.io.InputStream;
020import java.sql.Connection;
021import java.sql.PreparedStatement;
022import java.sql.ResultSet;
023import java.sql.SQLException;
024
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.cocoon.ProcessingException;
028import org.apache.cocoon.reading.ServiceableReader;
029import org.apache.commons.lang.StringUtils;
030import org.apache.excalibur.source.SourceUtil;
031import org.xml.sax.SAXException;
032
033import org.ametys.core.datasource.ConnectionHelper;
034import org.ametys.core.datasource.dbtype.SQLDatabaseTypeExtensionPoint;
035import org.ametys.core.user.CurrentUserProvider;
036import org.ametys.core.user.UserIdentity;
037import org.ametys.plugins.forms.table.FormTableManager;
038import org.ametys.runtime.authentication.AccessDeniedException;
039import org.ametys.runtime.config.Config;
040import org.ametys.web.renderingcontext.RenderingContext;
041import org.ametys.web.renderingcontext.RenderingContextHandler;
042
043/**
044 * Reads a BLOB value of a form entry.
045 */
046public class FormEntryFileReader extends ServiceableReader
047{
048    private CurrentUserProvider _currentUserProvider;
049    
050    private SQLDatabaseTypeExtensionPoint _sqlDatabaseTypeExtensionPoint;
051
052    private RenderingContextHandler _renderingContextHandler;
053
054    private SQLDatabaseTypeExtensionPoint getSQLDatabaseTypeExtensionPoint()
055    {
056        if (_sqlDatabaseTypeExtensionPoint == null)
057        {
058            try
059            {
060                _sqlDatabaseTypeExtensionPoint = (SQLDatabaseTypeExtensionPoint) manager.lookup(SQLDatabaseTypeExtensionPoint.ROLE);
061            }
062            catch (ServiceException e)
063            {
064                throw new RuntimeException(e);
065            }
066        }
067        return _sqlDatabaseTypeExtensionPoint;
068    }
069    
070    @Override
071    public void service(ServiceManager smanager) throws ServiceException
072    {
073        super.service(smanager);
074        _renderingContextHandler = (RenderingContextHandler) smanager.lookup(RenderingContextHandler.ROLE);
075        _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
076    }
077    
078    @Override
079    public void generate() throws IOException, SAXException, ProcessingException
080    {
081        String siteName = parameters.getParameter("site", "");
082        String formId = parameters.getParameter("form-id", "");
083        int entryId = parameters.getParameterAsInteger("entry-id", Integer.MIN_VALUE);
084        String fieldId = parameters.getParameter("field-id", "");
085        
086        if (StringUtils.isEmpty(siteName) || StringUtils.isEmpty(formId)
087            || entryId == Integer.MIN_VALUE || StringUtils.isEmpty(fieldId))
088        {
089            throw new IllegalArgumentException("Site name, form id, entry id and field id must be provided.");
090        }
091        
092        String tableName = FormTableManager.TABLE_PREFIX + formId;
093        
094        Connection connection = null;
095        PreparedStatement stmt = null;
096        ResultSet rs = null;
097        
098        try
099        {
100            String dataSourceId = Config.getInstance().getValue(FormTableManager.FORMS_POOL_CONFIG_PARAM);
101            connection = ConnectionHelper.getConnection(dataSourceId);
102            
103            String dbType = ConnectionHelper.getDatabaseType(connection);
104            String sql = "SELECT " + getSQLDatabaseTypeExtensionPoint().languageEscapeTableName(dbType, fieldId) 
105                    + "," + FormTableManager.LOGIN_FIELD
106                    + "," + FormTableManager.POPULATION_ID_FIELD
107                    + " FROM " + getSQLDatabaseTypeExtensionPoint().languageEscapeTableName(dbType, tableName) 
108                    + " WHERE id = ?";
109            
110            stmt = connection.prepareStatement(sql);
111            
112            stmt.setInt(1, entryId);
113            
114            // Execute the query.
115            rs = stmt.executeQuery();
116            
117            // Extract the result.
118            if (rs.next())
119            {
120                String login = rs.getString(FormTableManager.LOGIN_FIELD);
121                String population = rs.getString(FormTableManager.POPULATION_ID_FIELD);
122                
123                _checkAccess(login, population);
124                
125                try (InputStream is = _sqlDatabaseTypeExtensionPoint.getBlob(dbType, rs, 1))
126                {
127                    if (is != null)
128                    {
129                        SourceUtil.copy(is, out);
130                    }
131                }
132            }
133        }
134        catch (SQLException e)
135        {
136            getLogger().error("Error reading a form entry blob." + tableName, e);
137            throw new ProcessingException("Error reading a form entry blob.", e);
138        }
139        finally
140        {
141            ConnectionHelper.cleanup(rs);
142            ConnectionHelper.cleanup(stmt);
143            ConnectionHelper.cleanup(connection);
144        }
145    }
146    
147    private void _checkAccess(String login, String population)
148    {
149        UserIdentity entryOwner = null;
150        if (StringUtils.isNotEmpty(login) && StringUtils.isNotEmpty(population))
151        {
152            entryOwner = new UserIdentity(login, population);
153        }
154        
155        RenderingContext context = _renderingContextHandler.getRenderingContext();
156        if (context == RenderingContext.FRONT)
157        {
158            // If request come from front, check user is the file owner
159            UserIdentity currentUser = _currentUserProvider.getUser();
160            if (entryOwner == null || !entryOwner.equals(currentUser))
161            {
162                throw new AccessDeniedException("User '" + currentUser + "' is not allowed to access to user entry data.");
163            }
164        }
165    }
166}