Prepared statements for DG services
[appc.git] / appc-config / appc-data-services / provider / src / main / java / org / onap / appc / data / services / db / CtxParameterizedResolver.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * ============LICENSE_END=========================================================
20  */
21
22
23 package org.onap.appc.data.services.db;
24
25 import java.sql.Connection;
26 import java.sql.PreparedStatement;
27 import java.sql.ResultSet;
28 import java.sql.ResultSetMetaData;
29 import java.sql.SQLException;
30 import java.util.ArrayList;
31
32 import javax.sql.rowset.CachedRowSet;
33
34 import org.apache.commons.lang3.StringUtils;
35 import org.onap.ccsdk.sli.core.dblib.DbLibService;
36 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
37
38 import com.att.eelf.configuration.EELFLogger;
39 import com.att.eelf.configuration.EELFManager;
40
41 public class CtxParameterizedResolver {
42
43     private static String CRYPT_KEY = "QtfJMKggVk";
44     private static final EELFLogger log = EELFManager.getInstance().getLogger(CtxParameterizedResolver.class);
45     
46     protected static String resolveCtxVars(String key, SvcLogicContext ctx, ArrayList<String> arguments) {
47         if (key == null) {
48             return (null);
49         }
50
51         if (key.startsWith("'") && key.endsWith("'")) {
52             key = key.substring(1, key.length() - 1);
53             log.debug("Stripped outer single quotes - key is now [" + key + "]");
54         }
55
56         String[] keyTerms = key.split("\\s+");
57
58         StringBuffer sqlBuffer = new StringBuffer();
59
60         for (int i = 0; i < keyTerms.length; i++) {
61             sqlBuffer.append(resolveTerm(keyTerms[i], ctx, arguments));
62             sqlBuffer.append(" ");
63         }
64
65         return (sqlBuffer.toString());
66     }
67
68     private static String resolveTerm(String term, SvcLogicContext ctx, ArrayList<String> arguments) {
69         if (term == null) {
70             return (null);
71         }
72
73         log.trace("resolveTerm: term is " + term);
74
75         if (term.startsWith("$") && (ctx != null)) {
76             // Resolve any index variables.
77             term = resolveCtxVariable(term.substring(1), ctx);
78             // Escape single quote
79             if (term != null) {
80                 term = term.replaceAll("'", "''");
81             }
82             //valueOf will store null values as a String "null"
83             arguments.add(String.valueOf(term));
84             return "?";
85         } else {
86             return (term);
87         }
88
89     }
90
91     private static String resolveCtxVariable(String ctxVarName, SvcLogicContext ctx) {
92
93         if (ctxVarName.indexOf('[') == -1) {
94             // Ctx variable contains no arrays
95             if ("CRYPT_KEY".equals(ctxVarName)) {
96                 // Handle crypt key as special case. If it's set as a context
97                 // variable, use it. Otherwise, use
98                 // configured crypt key.
99                 String cryptKey = ctx.getAttribute(ctxVarName);
100                 if ((cryptKey != null) && (cryptKey.length() > 0)) {
101                     return (cryptKey);
102                 } else {
103                     return (CRYPT_KEY);
104                 }
105             }
106             return (ctx.getAttribute(ctxVarName));
107         }
108
109         // Resolve any array references
110         StringBuffer sbuff = new StringBuffer();
111         String[] ctxVarParts = ctxVarName.split("\\[");
112         sbuff.append(ctxVarParts[0]);
113         for (int i = 1; i < ctxVarParts.length; i++) {
114             if (ctxVarParts[i].startsWith("$")) {
115                 int endBracketLoc = ctxVarParts[i].indexOf("]");
116                 if (endBracketLoc == -1) {
117                     // Missing end bracket ... give up parsing
118                     log.warn("Variable reference " + ctxVarName + " seems to be missing a ']'");
119                     return (ctx.getAttribute(ctxVarName));
120                 }
121
122                 String idxVarName = ctxVarParts[i].substring(1, endBracketLoc);
123                 String remainder = ctxVarParts[i].substring(endBracketLoc);
124
125                 sbuff.append("[");
126                 sbuff.append(ctx.getAttribute(idxVarName));
127                 sbuff.append(remainder);
128
129             } else {
130                 // Index is not a variable reference
131                 sbuff.append("[");
132                 sbuff.append(ctxVarParts[i]);
133             }
134         }
135
136         return (ctx.getAttribute(sbuff.toString()));
137     }
138         
139         protected static void saveCachedRowSetToCtx(CachedRowSet results, SvcLogicContext ctx, String prefix, DbLibService dblibSvc)
140                 throws SQLException {
141             if (ctx != null) {
142                 if ((prefix != null) && prefix.endsWith("[]")) {
143                     // Return an array.
144                     String pfx = prefix.substring(0, prefix.length() - 2);
145                     int idx = 0;
146                     do {
147                         ResultSetMetaData rsMeta = results.getMetaData();
148                         int numCols = rsMeta.getColumnCount();
149
150                         for (int i = 0; i < numCols; i++) {
151                             String colValue = null;
152                             String tableName = rsMeta.getTableName(i + 1);
153                             if (rsMeta.getColumnType(i + 1) == java.sql.Types.VARBINARY) {
154                                 colValue = decryptColumn(tableName, rsMeta.getColumnName(i + 1), results.getBytes(i + 1),
155                                         dblibSvc);
156                             } else {
157                                 colValue = results.getString(i + 1);
158                             }
159                             log.debug("Setting " + pfx + "[" + idx + "]."
160                                     + rsMeta.getColumnLabel(i + 1).replaceAll("_", "-") + " = " + colValue);
161                             ctx.setAttribute(pfx + "[" + idx + "]." + rsMeta.getColumnLabel(i + 1).replaceAll("_", "-"),
162                                     colValue);
163                         }
164                         idx++;
165                     } while (results.next());
166                     log.debug("Setting " + pfx + "_length = " + idx);
167                     ctx.setAttribute(pfx + "_length", "" + idx);
168                 } else {
169                     ResultSetMetaData rsMeta = results.getMetaData();
170                     int numCols = rsMeta.getColumnCount();
171
172                     for (int i = 0; i < numCols; i++) {
173                         String colValue = null;
174                         String tableName = rsMeta.getTableName(i + 1);
175                         if ("VARBINARY".equalsIgnoreCase(rsMeta.getColumnTypeName(i + 1))) {
176                             colValue = decryptColumn(tableName, rsMeta.getColumnName(i + 1), results.getBytes(i + 1),
177                                     dblibSvc);
178                         } else {
179                             colValue = results.getString(i + 1);
180                         }
181                         if (prefix != null) {
182                             log.debug("Setting " + prefix + "." + rsMeta.getColumnLabel(i + 1).replaceAll("_", "-") + " = "
183                                     + colValue);
184                             ctx.setAttribute(prefix + "." + rsMeta.getColumnLabel(i + 1).replaceAll("_", "-"), colValue);
185                         } else {
186                             log.debug("Setting " + rsMeta.getColumnLabel(i + 1).replaceAll("_", "-") + " = " + colValue);
187                             ctx.setAttribute(rsMeta.getColumnLabel(i + 1).replaceAll("_", "-"), colValue);
188                         }
189                     }
190                 }
191             }
192         }
193         
194         private static String decryptColumn(String tableName, String colName, byte[] colValue, DbLibService dblibSvc) {
195             String strValue = new String(colValue);
196
197             if (StringUtils.isAsciiPrintable(strValue)) {
198
199                 // If printable, not encrypted
200                 return (strValue);
201             } else {
202                 ResultSet results = null;
203                 try (Connection conn =  dblibSvc.getConnection();
204                    PreparedStatement stmt = conn.prepareStatement("SELECT CAST(AES_DECRYPT(?, ?) AS CHAR(50)) FROM DUAL")) {
205
206                     stmt.setBytes(1, colValue);
207                     stmt.setString(2, CRYPT_KEY);
208                     results = stmt.executeQuery();
209
210                     if ((results != null) && results.next()) {
211                         strValue = results.getString(1);
212                         log.debug("Decrypted value is " + strValue);
213                     } else {
214                         log.warn("Cannot decrypt " + tableName + "." + colName);
215                     }
216                 } catch (Exception e) {
217                     log.error("Caught exception trying to decrypt " + tableName + "." + colName, e);
218                 }finally {
219                     if (results != null) {
220                         try {
221                             results.close();
222                         } catch (SQLException se) {
223                             log.error("Caught exception trying to close ResultSet",se);
224                         }
225                     }
226                 }
227             }
228             return (strValue);
229         }
230 }