001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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.kuali.rice.kew.documentoperation.web;
017
018import java.sql.Connection;
019import java.sql.PreparedStatement;
020import java.sql.ResultSet;
021import java.sql.SQLException;
022import java.util.HashMap;
023import java.util.Map;
024
025import javax.crypto.Cipher;
026import javax.crypto.KeyGenerator;
027import javax.crypto.SecretKey;
028import javax.crypto.SecretKeyFactory;
029import javax.crypto.spec.DESKeySpec;
030import javax.servlet.http.HttpServletRequest;
031import javax.servlet.http.HttpServletResponse;
032import javax.sql.DataSource;
033
034import org.apache.commons.codec.binary.Base64;
035import org.apache.commons.lang.StringUtils;
036import org.apache.log4j.Logger;
037import org.apache.struts.action.ActionForm;
038import org.apache.struts.action.ActionForward;
039import org.apache.struts.action.ActionMapping;
040import org.kuali.rice.core.api.config.property.ConfigContext;
041import org.kuali.rice.kew.service.KEWServiceLocator;
042import org.kuali.rice.kew.web.KewKualiAction;
043import org.kuali.rice.kim.api.KimConstants;
044import org.kuali.rice.kim.api.services.KimApiServiceLocator;
045import org.kuali.rice.krad.exception.AuthorizationException;
046import org.kuali.rice.krad.util.GlobalVariables;
047import org.kuali.rice.krad.util.KRADConstants;
048import org.kuali.rice.krad.util.KRADUtils;
049import org.springframework.dao.DataAccessException;
050import org.springframework.jdbc.core.JdbcTemplate;
051import org.springframework.jdbc.core.PreparedStatementCallback;
052import org.springframework.jdbc.core.PreparedStatementCreator;
053
054public class DocumentContentOperationAction extends KewKualiAction {
055
056        private final static String ALGORITHM = "DES/ECB/PKCS5Padding";
057        private final static String CHARSET = "UTF-8";
058    private static Logger LOG = Logger.getLogger(DocumentContentOperationAction.class);
059
060    public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
061                return mapping.findForward("basic");
062        }
063
064        public ActionForward encryptContent(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
065                if(checkPermissions()) {
066                        DocumentContentOperationForm docContentOperationForm = (DocumentContentOperationForm)form;
067                        String formDocumentId = docContentOperationForm.getDocumentId();
068                        String[] documentIds = formDocumentId.split(",");
069                        String encryptionKey = docContentOperationForm.getKey();
070                        for(String documentId : documentIds) {
071                                String docContent = getDocumentContent(documentId);
072                                String encryptedDocContent = encrypt(encryptionKey, docContent);
073                                saveDocumentContent(documentId, encryptedDocContent);
074                        }
075                }
076                return mapping.findForward("basic");
077        }
078
079        public ActionForward decryptContent(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
080                if(checkPermissions()) {
081                        DocumentContentOperationForm docContentOperationForm = (DocumentContentOperationForm)form;
082                        String formDocumentId = docContentOperationForm.getDocumentId();
083                        String[] documentIds = formDocumentId.split(",");
084                        String encryptionKey = docContentOperationForm.getKey();
085                        for(String documentId : documentIds) {
086                                String docContent = getDocumentContent(documentId);
087                                String decryptedDocContent = decrypt(encryptionKey, docContent);
088                                saveDocumentContent(documentId, decryptedDocContent);
089                        }
090                }
091                return mapping.findForward("basic");
092        }
093
094        private boolean checkPermissions() {
095                String principalId = GlobalVariables.getUserSession().getPrincipalId();
096                Map<String, String> permissionDetails = KRADUtils.getNamespaceAndActionClass(this.getClass());
097
098        boolean canUseScreen = KimApiServiceLocator.getPermissionService().isAuthorizedByTemplate(principalId,
099                        KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.USE_SCREEN, permissionDetails,
100                                new HashMap<String, String>());
101            if(canUseScreen && !ConfigContext.getCurrentContextConfig().isProductionEnvironment()) {
102                    return true;
103            } else {
104                    throw new AuthorizationException(GlobalVariables.getUserSession().getPrincipalName(), "encrypt or decrypt content", this.getClass().getSimpleName());
105            }
106        }
107
108        private String getDocumentContent(final String documentId) {
109                final DataSource dataSource = KEWServiceLocator.getDataSource();
110                JdbcTemplate template = new JdbcTemplate(dataSource);
111                String docContent = template.execute(
112                                new PreparedStatementCreator() {
113                                        public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
114                                                String sql = "SELECT doc_cntnt_txt FROM krew_doc_hdr_cntnt_t WHERE doc_hdr_id = ?";
115                                                PreparedStatement statement = connection.prepareStatement(sql);
116                                                return statement;
117                                        }
118                                },
119                                new PreparedStatementCallback<String>() {
120                                        public String doInPreparedStatement(PreparedStatement statement) throws SQLException, DataAccessException {
121                                                String docContent = "";
122                                                statement.setString(1, documentId);
123                                                ResultSet rs = statement.executeQuery();
124                                                try {
125                                                        while(rs.next()) {
126                                                                docContent = rs.getString("doc_cntnt_txt");
127                                                        }
128                                                } finally {
129                                                        if(rs != null) {
130                                                                rs.close();
131                                                        }
132                                                }
133                                                return docContent;
134                                        }
135                                });
136                return docContent;
137        }
138
139        private void saveDocumentContent(final String documentId, final String docContent) {
140                if(StringUtils.isBlank(documentId) || StringUtils.isBlank(docContent)) {
141            LOG.info("The document Id or the doc content was blank");
142                        return;
143                }
144                final DataSource dataSource = KEWServiceLocator.getDataSource();
145                JdbcTemplate template = new JdbcTemplate(dataSource);
146                template.execute(
147                                new PreparedStatementCreator() {
148                                        public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
149                                                String sql = "UPDATE krew_doc_hdr_cntnt_t SET doc_cntnt_txt = ? WHERE doc_hdr_id = ?";
150                                                PreparedStatement statement = connection.prepareStatement(sql);
151                                                return statement;
152                                        }
153                                },
154                                new PreparedStatementCallback<String>() {
155                                        public String doInPreparedStatement(PreparedStatement statement) throws SQLException, DataAccessException {
156                                                statement.setString(1, docContent);
157                                                statement.setString(2, documentId);
158                                                ResultSet rs = statement.executeQuery();
159                                                if(rs != null) {
160                                                        rs.close();
161                                                }
162                                                return "";
163                                        }
164                                });
165        }
166
167        private SecretKey getSecretKey(String encryptionKey) throws Exception {
168                KeyGenerator keygen = KeyGenerator.getInstance("DES");
169                SecretKey desKey = keygen.generateKey();
170
171                // Create the cipher
172                Cipher cipher = Cipher.getInstance(ALGORITHM);
173                cipher.init((Cipher.UNWRAP_MODE), desKey);
174
175                byte[] bytes = Base64.decodeBase64(encryptionKey.getBytes());
176
177                SecretKeyFactory desFactory = SecretKeyFactory.getInstance("DES");
178
179                DESKeySpec keyspec = new DESKeySpec(bytes);
180                desKey = desFactory.generateSecret(keyspec);
181                // Create the cipher
182                cipher.init((Cipher.WRAP_MODE), desKey);
183                return desKey;
184        }
185
186        private String encrypt(String encryptionKey, String value) throws Exception {
187                if (StringUtils.isBlank(value)) {
188            LOG.info("The value was was blank, returning an empty string");
189            return "";
190                }
191
192                // Initialize the cipher for encryption
193                Cipher cipher = Cipher.getInstance(ALGORITHM);
194                cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(encryptionKey));
195
196                try {
197                        // Our cleartext
198                        byte[] cleartext = value.toString().getBytes(CHARSET);
199
200                        // Encrypt the cleartext
201                        byte[] ciphertext = cipher.doFinal(cleartext);
202
203                        return new String(Base64.encodeBase64(ciphertext), CHARSET);
204                } catch (Exception e) {
205                        throw new RuntimeException(e);
206                }
207        }
208
209        private String decrypt(String encryptionKey, String value) throws Exception {
210        if (StringUtils.isBlank(value)) {
211            LOG.info("The value was was blank, returning an empty string");
212            return "";
213        }
214                // Initialize the same cipher for decryption
215                Cipher cipher = Cipher.getInstance(ALGORITHM);
216                cipher.init(Cipher.DECRYPT_MODE, getSecretKey(encryptionKey));
217
218                // un-Base64 encode the encrypted data
219                byte[] encryptedData = Base64.decodeBase64(value.getBytes(CHARSET));
220
221                // Decrypt the ciphertext
222                byte[] cleartext1 = cipher.doFinal(encryptedData);
223                return new String(cleartext1, CHARSET);
224        }
225}