QueryUtil.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /**
  2. * Licensed Materials - Property of IBM
  3. *
  4. * IBM Cognos Products: CAMAAA
  5. *
  6. * (C) Copyright IBM Corp. 2005, 2016
  7. *
  8. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  9. */
  10. import java.sql.Connection;
  11. import java.sql.PreparedStatement;
  12. import java.sql.ResultSet;
  13. import java.sql.ResultSetMetaData;
  14. import java.sql.SQLException;
  15. import java.util.ArrayList;
  16. import java.util.List;
  17. import java.util.Locale;
  18. import com.cognos.CAM_AAA.authentication.IAccount;
  19. import com.cognos.CAM_AAA.authentication.INamespace;
  20. import com.cognos.CAM_AAA.authentication.IQueryOption;
  21. import com.cognos.CAM_AAA.authentication.ISearchFilter;
  22. import com.cognos.CAM_AAA.authentication.ISearchFilterConditionalExpression;
  23. import com.cognos.CAM_AAA.authentication.ISearchFilterFunctionCall;
  24. import com.cognos.CAM_AAA.authentication.ISearchFilterRelationExpression;
  25. import com.cognos.CAM_AAA.authentication.ISortProperty;
  26. import com.cognos.CAM_AAA.authentication.QueryResult;
  27. import com.cognos.CAM_AAA.authentication.UnrecoverableException;
  28. public class QueryUtil
  29. {
  30. private static void addSQLConditionFragment(final StringBuffer sqlCondition, final String columnName, final String likePattern)
  31. {
  32. sqlCondition.append(" " + columnName + " LIKE '" + likePattern + "' ESCAPE '!'");
  33. }
  34. public static Account createAccount(final ConnectionManager connectionManager, final String userName, final String password)
  35. throws UnrecoverableException
  36. {
  37. final Object[][] data =
  38. QueryUtil.query(connectionManager.getConnection(),
  39. "SELECT USERID FROM USERS WHERE USERNAME = ? AND PASSWORD = ?", userName, password);
  40. final String userID = QueryUtil.getSingleStringResult(data);
  41. if (null != userID)
  42. {
  43. final String userSearchPath = "u:" + userID;
  44. return connectionManager.getAccountCache().findAccount(userSearchPath);
  45. }
  46. throw new UnrecoverableException("Invalid Credentials", "Could not authenticate with the provide credentials");
  47. }
  48. public static String escapeSpecialChars(final String str)
  49. {
  50. final StringBuffer escapedString = new StringBuffer(str);
  51. final String bangApostrophe = "!'";
  52. final String bangPercent = "!%";
  53. for (int i = 0; i < escapedString.length();)
  54. {
  55. final char c = escapedString.charAt(i);
  56. switch (c)
  57. {
  58. case '\'':
  59. escapedString.insert(i, bangApostrophe);
  60. i += bangApostrophe.length() + 1;
  61. break;
  62. case '%':
  63. escapedString.insert(i, bangPercent);
  64. i += bangPercent.length() + 1;
  65. break;
  66. default:
  67. i++;
  68. break;
  69. }
  70. }
  71. return escapedString.toString();
  72. }
  73. private static Object[] getDataRow(final ResultSet resultSet) throws SQLException
  74. {
  75. final ResultSetMetaData rsMetaData = resultSet.getMetaData();
  76. final Object[] row = new Object[rsMetaData.getColumnCount()];
  77. for (int i = 0; i < row.length; ++i)
  78. row[i] = resultSet.getObject(i + 1);
  79. return row;
  80. }
  81. public static Locale getLocale(final String localeID)
  82. {
  83. if (2 > localeID.length())
  84. return Locale.ENGLISH;
  85. final String language = localeID.substring(0, 2);
  86. final int fullLocaleLength = 5;
  87. if (fullLocaleLength == localeID.length())
  88. {
  89. final String country = localeID.substring(3, 5);
  90. return new Locale(language, country);
  91. }
  92. return new Locale(language);
  93. }
  94. private static Object[] getMetaDataRow(final ResultSet resultSet) throws SQLException
  95. {
  96. final ResultSetMetaData rsMetaData = resultSet.getMetaData();
  97. final Object[] metaDataRow = new Object[rsMetaData.getColumnCount()];
  98. for (int i = 0; i < metaDataRow.length; ++i)
  99. metaDataRow[i] = rsMetaData.getColumnName(i);
  100. return metaDataRow;
  101. }
  102. private static Object[] getSingleRowResult(final Object[][] data)
  103. {
  104. if (1 == data.length)
  105. return data[0];
  106. return null;
  107. }
  108. private static String getSingleStringResult(final Object[][] data)
  109. {
  110. final Object[] row = QueryUtil.getSingleRowResult(data);
  111. if (null != row && 1 == row.length)
  112. return String.valueOf(row[0]);
  113. return null;
  114. }
  115. public static String getSqlCondition(final ISearchFilter theSearchFilter)
  116. {
  117. final String falseCondition = " 1 = 0 ";
  118. final String trueCondition = "1 = 1 ";
  119. final StringBuffer sqlCondition = new StringBuffer();
  120. if (theSearchFilter != null)
  121. switch (theSearchFilter.getSearchFilterType())
  122. {
  123. case ISearchFilter.ConditionalExpression:
  124. final ISearchFilterConditionalExpression item = (ISearchFilterConditionalExpression) theSearchFilter;
  125. final String operator = item.getOperator();
  126. final ISearchFilter[] filters = item.getFilters();
  127. if (filters.length > 0)
  128. {
  129. sqlCondition.append("( ");
  130. sqlCondition.append(QueryUtil.getSqlCondition(filters[0]));
  131. for (int i = 1; i < filters.length; i++)
  132. {
  133. sqlCondition.append(' ');
  134. sqlCondition.append(operator);
  135. sqlCondition.append(' ');
  136. sqlCondition.append(QueryUtil.getSqlCondition(filters[i]));
  137. }
  138. sqlCondition.append(" )");
  139. }
  140. break;
  141. case ISearchFilter.FunctionCall:
  142. final ISearchFilterFunctionCall functionItem = (ISearchFilterFunctionCall) theSearchFilter;
  143. final String functionName = functionItem.getFunctionName();
  144. if (functionName.equals(ISearchFilterFunctionCall.Contains))
  145. {
  146. final String[] parameter = functionItem.getParameters();
  147. final String propertyName = parameter[0];
  148. final String value = parameter[1];
  149. final String likePattern = "%" + QueryUtil.escapeSpecialChars(value) + "%";
  150. if (propertyName.equals("@objectClass"))
  151. {
  152. if (-1 != "account".indexOf(value))
  153. sqlCondition.append(" ISUSER = 1 ");
  154. else if (-1 != "group".indexOf(value))
  155. sqlCondition.append(" ISGROUP = 1 ");
  156. else
  157. sqlCondition.append(falseCondition);
  158. }
  159. else if (propertyName.equals("@defaultName") || propertyName.equals("@name"))
  160. QueryUtil.addSQLConditionFragment(sqlCondition, "NAME", likePattern);
  161. else if (propertyName.equals("@userName"))
  162. QueryUtil.addSQLConditionFragment(sqlCondition, "USERNAME", likePattern);
  163. else
  164. sqlCondition.append(trueCondition);
  165. }
  166. else if (functionName.equals(ISearchFilterFunctionCall.StartsWith))
  167. {
  168. final String[] parameter = functionItem.getParameters();
  169. final String propertyName = parameter[0];
  170. final String value = parameter[1];
  171. final String likePattern = QueryUtil.escapeSpecialChars(value) + "%";
  172. if (propertyName.equals("@objectClass"))
  173. {
  174. if ("account".startsWith(value))
  175. sqlCondition.append(" ISUSER = 1 ");
  176. else if ("group".startsWith(value))
  177. sqlCondition.append(" ( ISGROUP = 1 ) ");
  178. else
  179. //
  180. // Make sure this is a false statement
  181. //
  182. sqlCondition.append(falseCondition);
  183. }
  184. else if (propertyName.equals("@defaultName") || propertyName.equals("@name"))
  185. QueryUtil.addSQLConditionFragment(sqlCondition, "NAME", likePattern);
  186. else if (propertyName.equals("@userName"))
  187. QueryUtil.addSQLConditionFragment(sqlCondition, "USERNAME", likePattern);
  188. else
  189. //
  190. // We ignore the properties that are not
  191. // supported.
  192. //
  193. sqlCondition.append(trueCondition);
  194. }
  195. else if (functionName.equals(ISearchFilterFunctionCall.EndsWith))
  196. {
  197. final String[] parameter = functionItem.getParameters();
  198. final String propertyName = parameter[0];
  199. final String value = parameter[1];
  200. if (propertyName.equals("@objectClass"))
  201. {
  202. if ("account".endsWith(value))
  203. sqlCondition.append(" ISUSER = 1 ");
  204. else if ("group".endsWith(value))
  205. sqlCondition.append(" ( ISGROUP = 1 ) ");
  206. else
  207. sqlCondition.append(falseCondition);
  208. }
  209. else if (propertyName.equals("@defaultName") || propertyName.equals("@name"))
  210. QueryUtil.addSQLConditionFragment(sqlCondition, "NAME", "%" + QueryUtil.escapeSpecialChars(value));
  211. else if (propertyName.equals("@userName"))
  212. QueryUtil.addSQLConditionFragment(sqlCondition, "USERNAME", "%" + QueryUtil.escapeSpecialChars(value));
  213. else
  214. sqlCondition.append(trueCondition);
  215. }
  216. else
  217. sqlCondition.append(trueCondition);
  218. break;
  219. case ISearchFilter.RelationalExpression:
  220. final ISearchFilterRelationExpression relationalItem = (ISearchFilterRelationExpression) theSearchFilter;
  221. final String propertyName = relationalItem.getPropertyName();
  222. final String constraint = relationalItem.getConstraint();
  223. final String relationalOperator = relationalItem.getOperator();
  224. if (propertyName.equals("@objectClass"))
  225. {
  226. if (constraint.equals("account"))
  227. {
  228. if (relationalOperator.equals(ISearchFilterRelationExpression.EqualTo))
  229. sqlCondition.append(" ISUSER = 1 ");
  230. else if (relationalOperator.equals(ISearchFilterRelationExpression.NotEqual))
  231. sqlCondition.append(" ISUSER = 0 ");
  232. else
  233. //
  234. // Make sure this is a false statement
  235. //
  236. sqlCondition.append(falseCondition);
  237. }
  238. else if (constraint.equals("group"))
  239. {
  240. if (relationalOperator.equals(ISearchFilterRelationExpression.EqualTo))
  241. sqlCondition.append(" ( ISGROUP = 1 ) ");
  242. else if (relationalOperator.equals(ISearchFilterRelationExpression.NotEqual))
  243. sqlCondition.append(" ( ISGROUP = 0 ) ");
  244. else
  245. sqlCondition.append(falseCondition);
  246. }
  247. else
  248. sqlCondition.append(falseCondition);
  249. }
  250. else if (propertyName.equals("@defaultName") || propertyName.equals("@name"))
  251. sqlCondition.append(" NAME " + relationalOperator + " '" + constraint + "'");
  252. else if (propertyName.equals("@userName"))
  253. sqlCondition.append(" USERNAME " + relationalOperator + " '" + constraint + "'");
  254. else
  255. sqlCondition.append(trueCondition);
  256. break;
  257. }
  258. return sqlCondition.toString();
  259. }
  260. public static Object[][] query(final Connection connection, final String sql, final Object... parameters)
  261. throws UnrecoverableException
  262. {
  263. return QueryUtil.queryImpl(connection, sql, false, parameters);
  264. }
  265. private static Object[][] queryImpl(final Connection connection, final String sql, final boolean includeMetadata,
  266. final Object... parameters) throws UnrecoverableException
  267. {
  268. final List< Object[] > data = new ArrayList< Object[] >();
  269. try (final PreparedStatement statement = connection.prepareStatement(sql))
  270. {
  271. for (int i = 0; i < parameters.length; ++i)
  272. statement.setObject(i + 1, parameters[i]);
  273. try (final ResultSet resultSet = statement.executeQuery())
  274. {
  275. if (includeMetadata)
  276. data.add(QueryUtil.getMetaDataRow(resultSet));
  277. while (resultSet.next())
  278. data.add(QueryUtil.getDataRow(resultSet));
  279. }
  280. }
  281. catch (final SQLException ex)
  282. {
  283. throw new UnrecoverableException("SQL Exception", "An exception was caught while querying the authentication database.");
  284. }
  285. return data.toArray(new Object[0][]);
  286. }
  287. public static Object[][] queryWithMetaData(final Connection connection, final String sql, final Object... parameters)
  288. throws UnrecoverableException
  289. {
  290. return QueryUtil.queryImpl(connection, sql, true, parameters);
  291. }
  292. public static void searchQuery(final ConnectionManager connectionManager, final String theSqlCondition,
  293. final IQueryOption theQueryOption, final String[] theProperties, final ISortProperty[] theSortProperties,
  294. final QueryResult theResult, final INamespace theNamespace) throws SQLException, UnrecoverableException
  295. {
  296. final StringBuffer sqlStatement = new StringBuffer();
  297. sqlStatement.append("SELECT ID, USERNAME, NAME, ISUSER, ISGROUP FROM OBJECTVIEW");
  298. if (theSqlCondition.length() > 0)
  299. sqlStatement.append(" WHERE ").append(theSqlCondition);
  300. final long maxCount = theQueryOption.getMaxCount();
  301. final long skipCount = theQueryOption.getSkipCount();
  302. String theSortClause = new String();
  303. if (theSortProperties != null)
  304. {
  305. for (int i = 0; i < theSortProperties.length; i++)
  306. {
  307. final ISortProperty property = theSortProperties[i];
  308. if (property.getPropertyName().equals("name"))
  309. {
  310. if (theSortClause.length() > 0)
  311. theSortClause += ", ";
  312. theSortClause += "NAME";
  313. if (property.getSortOrder() == ISortProperty.SortOrderAscending)
  314. theSortClause += " ASC";
  315. else
  316. theSortClause += " DESC";
  317. }
  318. }
  319. if (theSortClause.length() > 0)
  320. sqlStatement.append(" ORDER BY ").append(theSortClause);
  321. }
  322. final Object[][] data = QueryUtil.query(connectionManager.getConnection(), sqlStatement.toString());
  323. if (0 < data.length)
  324. {
  325. long curSkip = 0, curMax = 0;
  326. final int isUserCol = 3;
  327. final int isGroupCol = 4;
  328. for (int i = 0; i < data.length; i++)
  329. {
  330. final Object[] row = data[i];
  331. final boolean bIsUser = ((Integer) row[isUserCol]).intValue() == 1;
  332. final boolean bIsGroup = ((Integer) row[isGroupCol]).intValue() == 1;
  333. // We need to handle paging information
  334. if (bIsUser || bIsGroup)
  335. {
  336. if (curSkip++ < skipCount) // We need to skip skipCount
  337. // first objects
  338. continue;
  339. else if (curMax >= maxCount && maxCount > 0) // If we
  340. // already
  341. // have
  342. // maxCount
  343. // objects,
  344. // we can
  345. // stop
  346. // looking
  347. break;
  348. else
  349. // curMax < maxCount - we need to keep retrieving
  350. // entries
  351. curMax++;
  352. }
  353. else
  354. // If the entry is neither a user nor a role, we'll skip it
  355. continue;
  356. final String objectID = String.valueOf(row[0]);
  357. final String userName = (String) row[1];
  358. final String objectName = (String) row[2];
  359. if (bIsUser)
  360. {
  361. final String searchPath = "u:" + objectID;
  362. final Account account = connectionManager.getAccountCache().findAccount(searchPath);
  363. account.addName(Locale.getDefault(), objectName);
  364. account.setUserName(userName);
  365. // The following two custom properties used for testing
  366. // purposes
  367. account.addCustomProperty("newProp1", "value1");
  368. account.addCustomProperty("newProp2", "value2");
  369. theResult.addObject(account);
  370. }
  371. else if (bIsGroup)
  372. {
  373. final String searchPath = "g:" + objectID;
  374. final Group group = connectionManager.getGroupCache().findGroup(searchPath);
  375. group.addName(Locale.getDefault(), objectName);
  376. theResult.addObject(group);
  377. }
  378. }
  379. }
  380. }
  381. public static void updateMembership(final ConnectionManager connectionManager, final Visa theVisa) throws SQLException,
  382. UnrecoverableException
  383. {
  384. final IAccount account = theVisa.getAccount();
  385. final String userID = account.getObjectID().substring(2);
  386. final String tenantID = getTenantId(account);
  387. final Object[][] data =
  388. QueryUtil
  389. .query(connectionManager.getConnection(), "SELECT GROUPID, GROUPNAME FROM GROUPS WHERE USERID = ? AND (TENANT = ? OR TENANT='')", userID, tenantID);
  390. for (int i = 0; i < data.length; ++i)
  391. {
  392. final Object[] row = data[i];
  393. final String groupID = String.valueOf(row[0]);
  394. final String groupName = (String) row[1];
  395. final Group group = connectionManager.getGroupCache().findGroup("g:" + groupID);
  396. group.addName(account.getContentLocale(), groupName);
  397. theVisa.addGroup(group);
  398. }
  399. }
  400. public static String getTenantId(IAccount account) {
  401. String value[] = account.getCustomPropertyValue(AccountCache.TENANTID_ACCOUNT_PROPERTY);
  402. return value != null ? value[0] : null;
  403. }
  404. }