/** * Licensed Materials - Property of IBM * * IBM Cognos Products: CAMAAA * * (C) Copyright IBM Corp. 2005, 2016 * * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import com.cognos.CAM_AAA.authentication.IAccount; import com.cognos.CAM_AAA.authentication.INamespace; import com.cognos.CAM_AAA.authentication.IQueryOption; import com.cognos.CAM_AAA.authentication.ISearchFilter; import com.cognos.CAM_AAA.authentication.ISearchFilterConditionalExpression; import com.cognos.CAM_AAA.authentication.ISearchFilterFunctionCall; import com.cognos.CAM_AAA.authentication.ISearchFilterRelationExpression; import com.cognos.CAM_AAA.authentication.ISortProperty; import com.cognos.CAM_AAA.authentication.QueryResult; import com.cognos.CAM_AAA.authentication.UnrecoverableException; public class QueryUtil { private static void addSQLConditionFragment(final StringBuffer sqlCondition, final String columnName, final String likePattern) { sqlCondition.append(" " + columnName + " LIKE '" + likePattern + "' ESCAPE '!'"); } public static Account createAccount(final ConnectionManager connectionManager, final String userName, final String password) throws UnrecoverableException { final Object[][] data = QueryUtil.query(connectionManager.getConnection(), "SELECT USERID FROM USERS WHERE USERNAME = ? AND PASSWORD = ?", userName, password); final String userID = QueryUtil.getSingleStringResult(data); if (null != userID) { final String userSearchPath = "u:" + userID; return connectionManager.getAccountCache().findAccount(userSearchPath); } throw new UnrecoverableException("Invalid Credentials", "Could not authenticate with the provide credentials"); } public static String escapeSpecialChars(final String str) { final StringBuffer escapedString = new StringBuffer(str); final String bangApostrophe = "!'"; final String bangPercent = "!%"; for (int i = 0; i < escapedString.length();) { final char c = escapedString.charAt(i); switch (c) { case '\'': escapedString.insert(i, bangApostrophe); i += bangApostrophe.length() + 1; break; case '%': escapedString.insert(i, bangPercent); i += bangPercent.length() + 1; break; default: i++; break; } } return escapedString.toString(); } private static Object[] getDataRow(final ResultSet resultSet) throws SQLException { final ResultSetMetaData rsMetaData = resultSet.getMetaData(); final Object[] row = new Object[rsMetaData.getColumnCount()]; for (int i = 0; i < row.length; ++i) row[i] = resultSet.getObject(i + 1); return row; } public static Locale getLocale(final String localeID) { if (2 > localeID.length()) return Locale.ENGLISH; final String language = localeID.substring(0, 2); final int fullLocaleLength = 5; if (fullLocaleLength == localeID.length()) { final String country = localeID.substring(3, 5); return new Locale(language, country); } return new Locale(language); } private static Object[] getMetaDataRow(final ResultSet resultSet) throws SQLException { final ResultSetMetaData rsMetaData = resultSet.getMetaData(); final Object[] metaDataRow = new Object[rsMetaData.getColumnCount()]; for (int i = 0; i < metaDataRow.length; ++i) metaDataRow[i] = rsMetaData.getColumnName(i); return metaDataRow; } private static Object[] getSingleRowResult(final Object[][] data) { if (1 == data.length) return data[0]; return null; } private static String getSingleStringResult(final Object[][] data) { final Object[] row = QueryUtil.getSingleRowResult(data); if (null != row && 1 == row.length) return String.valueOf(row[0]); return null; } public static String getSqlCondition(final ISearchFilter theSearchFilter) { final String falseCondition = " 1 = 0 "; final String trueCondition = "1 = 1 "; final StringBuffer sqlCondition = new StringBuffer(); if (theSearchFilter != null) switch (theSearchFilter.getSearchFilterType()) { case ISearchFilter.ConditionalExpression: final ISearchFilterConditionalExpression item = (ISearchFilterConditionalExpression) theSearchFilter; final String operator = item.getOperator(); final ISearchFilter[] filters = item.getFilters(); if (filters.length > 0) { sqlCondition.append("( "); sqlCondition.append(QueryUtil.getSqlCondition(filters[0])); for (int i = 1; i < filters.length; i++) { sqlCondition.append(' '); sqlCondition.append(operator); sqlCondition.append(' '); sqlCondition.append(QueryUtil.getSqlCondition(filters[i])); } sqlCondition.append(" )"); } break; case ISearchFilter.FunctionCall: final ISearchFilterFunctionCall functionItem = (ISearchFilterFunctionCall) theSearchFilter; final String functionName = functionItem.getFunctionName(); if (functionName.equals(ISearchFilterFunctionCall.Contains)) { final String[] parameter = functionItem.getParameters(); final String propertyName = parameter[0]; final String value = parameter[1]; final String likePattern = "%" + QueryUtil.escapeSpecialChars(value) + "%"; if (propertyName.equals("@objectClass")) { if (-1 != "account".indexOf(value)) sqlCondition.append(" ISUSER = 1 "); else if (-1 != "group".indexOf(value)) sqlCondition.append(" ISGROUP = 1 "); else sqlCondition.append(falseCondition); } else if (propertyName.equals("@defaultName") || propertyName.equals("@name")) QueryUtil.addSQLConditionFragment(sqlCondition, "NAME", likePattern); else if (propertyName.equals("@userName")) QueryUtil.addSQLConditionFragment(sqlCondition, "USERNAME", likePattern); else sqlCondition.append(trueCondition); } else if (functionName.equals(ISearchFilterFunctionCall.StartsWith)) { final String[] parameter = functionItem.getParameters(); final String propertyName = parameter[0]; final String value = parameter[1]; final String likePattern = QueryUtil.escapeSpecialChars(value) + "%"; if (propertyName.equals("@objectClass")) { if ("account".startsWith(value)) sqlCondition.append(" ISUSER = 1 "); else if ("group".startsWith(value)) sqlCondition.append(" ( ISGROUP = 1 ) "); else // // Make sure this is a false statement // sqlCondition.append(falseCondition); } else if (propertyName.equals("@defaultName") || propertyName.equals("@name")) QueryUtil.addSQLConditionFragment(sqlCondition, "NAME", likePattern); else if (propertyName.equals("@userName")) QueryUtil.addSQLConditionFragment(sqlCondition, "USERNAME", likePattern); else // // We ignore the properties that are not // supported. // sqlCondition.append(trueCondition); } else if (functionName.equals(ISearchFilterFunctionCall.EndsWith)) { final String[] parameter = functionItem.getParameters(); final String propertyName = parameter[0]; final String value = parameter[1]; if (propertyName.equals("@objectClass")) { if ("account".endsWith(value)) sqlCondition.append(" ISUSER = 1 "); else if ("group".endsWith(value)) sqlCondition.append(" ( ISGROUP = 1 ) "); else sqlCondition.append(falseCondition); } else if (propertyName.equals("@defaultName") || propertyName.equals("@name")) QueryUtil.addSQLConditionFragment(sqlCondition, "NAME", "%" + QueryUtil.escapeSpecialChars(value)); else if (propertyName.equals("@userName")) QueryUtil.addSQLConditionFragment(sqlCondition, "USERNAME", "%" + QueryUtil.escapeSpecialChars(value)); else sqlCondition.append(trueCondition); } else sqlCondition.append(trueCondition); break; case ISearchFilter.RelationalExpression: final ISearchFilterRelationExpression relationalItem = (ISearchFilterRelationExpression) theSearchFilter; final String propertyName = relationalItem.getPropertyName(); final String constraint = relationalItem.getConstraint(); final String relationalOperator = relationalItem.getOperator(); if (propertyName.equals("@objectClass")) { if (constraint.equals("account")) { if (relationalOperator.equals(ISearchFilterRelationExpression.EqualTo)) sqlCondition.append(" ISUSER = 1 "); else if (relationalOperator.equals(ISearchFilterRelationExpression.NotEqual)) sqlCondition.append(" ISUSER = 0 "); else // // Make sure this is a false statement // sqlCondition.append(falseCondition); } else if (constraint.equals("group")) { if (relationalOperator.equals(ISearchFilterRelationExpression.EqualTo)) sqlCondition.append(" ( ISGROUP = 1 ) "); else if (relationalOperator.equals(ISearchFilterRelationExpression.NotEqual)) sqlCondition.append(" ( ISGROUP = 0 ) "); else sqlCondition.append(falseCondition); } else sqlCondition.append(falseCondition); } else if (propertyName.equals("@defaultName") || propertyName.equals("@name")) sqlCondition.append(" NAME " + relationalOperator + " '" + constraint + "'"); else if (propertyName.equals("@userName")) sqlCondition.append(" USERNAME " + relationalOperator + " '" + constraint + "'"); else sqlCondition.append(trueCondition); break; } return sqlCondition.toString(); } public static Object[][] query(final Connection connection, final String sql, final Object... parameters) throws UnrecoverableException { return QueryUtil.queryImpl(connection, sql, false, parameters); } private static Object[][] queryImpl(final Connection connection, final String sql, final boolean includeMetadata, final Object... parameters) throws UnrecoverableException { final List< Object[] > data = new ArrayList< Object[] >(); try (final PreparedStatement statement = connection.prepareStatement(sql)) { for (int i = 0; i < parameters.length; ++i) statement.setObject(i + 1, parameters[i]); try (final ResultSet resultSet = statement.executeQuery()) { if (includeMetadata) data.add(QueryUtil.getMetaDataRow(resultSet)); while (resultSet.next()) data.add(QueryUtil.getDataRow(resultSet)); } } catch (final SQLException ex) { throw new UnrecoverableException("SQL Exception", "An exception was caught while querying the authentication database."); } return data.toArray(new Object[0][]); } public static Object[][] queryWithMetaData(final Connection connection, final String sql, final Object... parameters) throws UnrecoverableException { return QueryUtil.queryImpl(connection, sql, true, parameters); } public static void searchQuery(final ConnectionManager connectionManager, final String theSqlCondition, final IQueryOption theQueryOption, final String[] theProperties, final ISortProperty[] theSortProperties, final QueryResult theResult, final INamespace theNamespace) throws SQLException, UnrecoverableException { final StringBuffer sqlStatement = new StringBuffer(); sqlStatement.append("SELECT ID, USERNAME, NAME, ISUSER, ISGROUP FROM OBJECTVIEW"); if (theSqlCondition.length() > 0) sqlStatement.append(" WHERE ").append(theSqlCondition); final long maxCount = theQueryOption.getMaxCount(); final long skipCount = theQueryOption.getSkipCount(); String theSortClause = new String(); if (theSortProperties != null) { for (int i = 0; i < theSortProperties.length; i++) { final ISortProperty property = theSortProperties[i]; if (property.getPropertyName().equals("name")) { if (theSortClause.length() > 0) theSortClause += ", "; theSortClause += "NAME"; if (property.getSortOrder() == ISortProperty.SortOrderAscending) theSortClause += " ASC"; else theSortClause += " DESC"; } } if (theSortClause.length() > 0) sqlStatement.append(" ORDER BY ").append(theSortClause); } final Object[][] data = QueryUtil.query(connectionManager.getConnection(), sqlStatement.toString()); if (0 < data.length) { long curSkip = 0, curMax = 0; final int isUserCol = 3; final int isGroupCol = 4; for (int i = 0; i < data.length; i++) { final Object[] row = data[i]; final boolean bIsUser = ((Integer) row[isUserCol]).intValue() == 1; final boolean bIsGroup = ((Integer) row[isGroupCol]).intValue() == 1; // We need to handle paging information if (bIsUser || bIsGroup) { if (curSkip++ < skipCount) // We need to skip skipCount // first objects continue; else if (curMax >= maxCount && maxCount > 0) // If we // already // have // maxCount // objects, // we can // stop // looking break; else // curMax < maxCount - we need to keep retrieving // entries curMax++; } else // If the entry is neither a user nor a role, we'll skip it continue; final String objectID = String.valueOf(row[0]); final String userName = (String) row[1]; final String objectName = (String) row[2]; if (bIsUser) { final String searchPath = "u:" + objectID; final Account account = connectionManager.getAccountCache().findAccount(searchPath); account.addName(Locale.getDefault(), objectName); account.setUserName(userName); // The following two custom properties used for testing // purposes account.addCustomProperty("newProp1", "value1"); account.addCustomProperty("newProp2", "value2"); theResult.addObject(account); } else if (bIsGroup) { final String searchPath = "g:" + objectID; final Group group = connectionManager.getGroupCache().findGroup(searchPath); group.addName(Locale.getDefault(), objectName); theResult.addObject(group); } } } } public static void updateMembership(final ConnectionManager connectionManager, final Visa theVisa) throws SQLException, UnrecoverableException { final IAccount account = theVisa.getAccount(); final String userID = account.getObjectID().substring(2); final String tenantID = getTenantId(account); final Object[][] data = QueryUtil .query(connectionManager.getConnection(), "SELECT GROUPID, GROUPNAME FROM GROUPS WHERE USERID = ? AND (TENANT = ? OR TENANT='')", userID, tenantID); for (int i = 0; i < data.length; ++i) { final Object[] row = data[i]; final String groupID = String.valueOf(row[0]); final String groupName = (String) row[1]; final Group group = connectionManager.getGroupCache().findGroup("g:" + groupID); group.addName(account.getContentLocale(), groupName); theVisa.addGroup(group); } } public static String getTenantId(IAccount account) { String value[] = account.getCustomPropertyValue(AccountCache.TENANTID_ACCOUNT_PROPERTY); return value != null ? value[0] : null; } }