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}