RestorableJDBCSample.java 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /**
  2. * Licensed Materials - Property of IBM
  3. *
  4. * IBM Cognos Products: CAMAAA
  5. *
  6. * (C) Copyright IBM Corp. 2012
  7. *
  8. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  9. */
  10. import java.io.ByteArrayOutputStream;
  11. import java.io.IOException;
  12. import java.io.PrintStream;
  13. import java.sql.SQLException;
  14. import java.util.Locale;
  15. import com.cognos.CAM_AAA.authentication.IBiBusHeader;
  16. import com.cognos.CAM_AAA.authentication.IBiBusHeader2;
  17. import com.cognos.CAM_AAA.authentication.INamespaceAuthenticationProvider2;
  18. import com.cognos.CAM_AAA.authentication.INamespaceConfiguration;
  19. import com.cognos.CAM_AAA.authentication.IQuery;
  20. import com.cognos.CAM_AAA.authentication.IQueryResult;
  21. import com.cognos.CAM_AAA.authentication.ISearchExpression;
  22. import com.cognos.CAM_AAA.authentication.ISearchFilter;
  23. import com.cognos.CAM_AAA.authentication.ISearchStep;
  24. import com.cognos.CAM_AAA.authentication.ISearchStep.SearchAxis;
  25. import com.cognos.CAM_AAA.authentication.IVisa;
  26. import com.cognos.CAM_AAA.authentication.QueryResult;
  27. import com.cognos.CAM_AAA.authentication.ReadOnlyDisplayObject;
  28. import com.cognos.CAM_AAA.authentication.SystemRecoverableException;
  29. import com.cognos.CAM_AAA.authentication.TextDisplayObject;
  30. import com.cognos.CAM_AAA.authentication.TextNoEchoDisplayObject;
  31. import com.cognos.CAM_AAA.authentication.UnrecoverableException;
  32. import com.cognos.CAM_AAA.authentication.UserRecoverableException;
  33. /**
  34. * This is a modified version of the JDBCSample that demonstrates how to implement a custom namespace that can
  35. * handle failover of the user session.
  36. *
  37. * Note that IBM Cognos must be properly configured to support authentication failover for this to work.
  38. *
  39. * @See {@link JDBCSample}
  40. *
  41. */
  42. public class RestorableJDBCSample extends Namespace implements INamespaceAuthenticationProvider2
  43. {
  44. /**
  45. * The logon method is virtually identical to {@link JDBCSample#logon(IBiBusHeader2)
  46. *
  47. * The main difference is that now we need to use a RestorableJDBCVisa instead of a JDBCVisa.
  48. * @see INamespaceAuthenticationProvider2#logon(IBiBusHeader2)
  49. */
  50. public IVisa logon(IBiBusHeader2 theAuthRequest) throws UserRecoverableException, SystemRecoverableException,
  51. UnrecoverableException
  52. {
  53. RestorableJDBCVisa visa = null;
  54. ConnectionManager mgr = ConnectionManager.get();
  55. // 1 - Look for trusted credentials
  56. JDBCSample.Credential credential = JDBCSample.getTrustedCredentialValues(theAuthRequest);
  57. if (credential.isEmpty())
  58. credential = JDBCSample.getCredentialValues(theAuthRequest);
  59. if (credential.isEmpty())
  60. credential = JDBCSample.getFormFieldValues(theAuthRequest);
  61. // here, should be something for the single signon case
  62. if (credential.isEmpty() && mgr.singleSignOnEnabled())
  63. credential = JDBCSample.getTrustedEnvironmentVaribleValue(theAuthRequest);
  64. if (credential.isEmpty() && mgr.singleSignOnEnabled())
  65. {
  66. // null implies the provider has to start the dance so throw a SysRecov.
  67. // the SysRecov needs to have the name of the variable we look for in
  68. // the second parameter
  69. SystemRecoverableException e = new SystemRecoverableException("Challenge for REMOTE_USER", "REMOTE_USER");
  70. throw e;
  71. }
  72. if (credential.isEmpty())
  73. {
  74. // Assume this is the initial logon and pass null for errorDetails
  75. generateAndThrowExceptionForLogonPrompt(null);
  76. }
  77. try
  78. {
  79. //
  80. // Create a Visa for the new user. Unlike the JDBCVisa, we will not pas a reference to
  81. // the ConnectionManager. Instead, the Visa will use a static accessor to get the singleton
  82. // reference to the ConnectionManager
  83. //
  84. visa = new RestorableJDBCVisa();
  85. visa.init(credential.getUsername(), credential.getPassword());
  86. }
  87. catch (final UnrecoverableException ex)
  88. {
  89. final String errorDetails = RestorableJDBCSample.getErrorDetails(ex);
  90. // Something went wrong, probably because the user's credentials
  91. // are invalid.
  92. generateAndThrowExceptionForLogonPrompt(errorDetails);
  93. }
  94. return visa;
  95. }
  96. /**
  97. * This method is implemented the same as in {@link JDBCSample#logoff(IVisa, IBiBusHeader)
  98. *
  99. * @see INamespaceAuthenticationProvider2#logoff(IVisa, IBiBusHeader)
  100. */
  101. public void logoff(IVisa theVisa, IBiBusHeader theBiBusHeader)
  102. {
  103. try
  104. {
  105. // We can safely assume that we'll get back the same Visa that we
  106. // issued.
  107. final RestorableJDBCVisa visa = (RestorableJDBCVisa) theVisa;
  108. visa.destroy();
  109. }
  110. catch (UnrecoverableException e)
  111. {
  112. e.printStackTrace();
  113. }
  114. }
  115. /**
  116. * The search method only has minor modifications from {@link JDBCSample#search(IVisa, IQuery), as we no longer
  117. * need to hold a reference to the ConnectionManager and we are using a RestorableJDBCVIsa
  118. *
  119. * @see com.cognos.CAM_AAA.authentication.INamespaceAuthenticationProviderBase#search(com.cognos.CAM_AAA.authentication.IVisa, com.cognos.CAM_AAA.authentication.IQuery)
  120. */
  121. public IQueryResult search(IVisa theVisa, IQuery theQuery) throws UnrecoverableException
  122. {
  123. // We can safely assume that we'll get back the same Visa that we
  124. // issued.
  125. final RestorableJDBCVisa visa = (RestorableJDBCVisa) theVisa;
  126. final QueryResult result = new QueryResult();
  127. try
  128. {
  129. final ISearchExpression expression = theQuery.getSearchExpression();
  130. final String objectID = expression.getObjectID();
  131. final ISearchStep[] steps = expression.getSteps();
  132. // It doesn't make sense to have multiple steps for this provider
  133. // since the objects are not hierarchical.
  134. if (steps.length != 1)
  135. throw new UnrecoverableException("Internal Error",
  136. "Invalid search expression. Multiple steps is not supported for this namespace.");
  137. final StringBuffer sqlCondition = new StringBuffer();
  138. final int searchType = steps[0].getAxis();
  139. final ISearchFilter filter = steps[0].getPredicate();
  140. String tenantId = QueryUtil.getTenantId(visa.getAccount());
  141. switch (searchType)
  142. {
  143. case SearchAxis.Self:
  144. case SearchAxis.DescendentOrSelf:
  145. if (objectID == null)
  146. {
  147. if (filter == null || this.matchesFilter(filter))
  148. result.addObject(this);
  149. // Add current namespace
  150. if (searchType == SearchAxis.Self)
  151. return result;
  152. else
  153. sqlCondition.append(QueryUtil.getSqlCondition(filter));
  154. }
  155. else if (objectID.startsWith("u:") && objectID.equals(visa.getAccount().getObjectID()))
  156. {
  157. if (filter == null || this.matchesFilter(filter))
  158. result.addObject(visa.getAccount());
  159. // Add current user
  160. return result;
  161. }
  162. else if (objectID.startsWith("u:"))
  163. {
  164. final String sqlID = objectID.substring(2);
  165. sqlCondition.append(QueryUtil.getSqlCondition(filter));
  166. if (sqlCondition.length() > 0)
  167. sqlCondition.append(" AND ");
  168. sqlCondition.append("ID = " + sqlID + " AND ISUSER = 1");
  169. }
  170. else if (objectID.startsWith("g:"))
  171. {
  172. final String sqlID = objectID.substring(2);
  173. sqlCondition.append(QueryUtil.getSqlCondition(filter));
  174. if (sqlCondition.length() > 0)
  175. sqlCondition.append(" AND ");
  176. sqlCondition.append("ID = " + sqlID + " AND ISGROUP = 1");
  177. }
  178. break;
  179. default:
  180. sqlCondition.append(QueryUtil.getSqlCondition(filter));
  181. break;
  182. }
  183. sqlCondition.append(getTenantSql(tenantId));
  184. QueryUtil.searchQuery(ConnectionManager.get(), sqlCondition.toString(), theQuery.getQueryOption(),
  185. theQuery.getProperties(), theQuery.getSortProperties(), result, this);
  186. }
  187. catch (final SQLException e)
  188. {
  189. e.printStackTrace();
  190. }
  191. catch (final UnrecoverableException e)
  192. {
  193. e.printStackTrace();
  194. }
  195. return result;
  196. }
  197. /**
  198. * This method requires only minor modifications from {@link JDBCSample#init(INamespaceConfiguration)}, due to the fact
  199. * that the {@link ConnectionManager} is now a singleton
  200. *
  201. * @see Namespace#init(com.cognos.CAM_AAA.authentication.INamespaceConfiguration)
  202. */
  203. @Override
  204. public void init(INamespaceConfiguration theNamespaceConfiguration) throws UnrecoverableException
  205. {
  206. try
  207. {
  208. super.init(theNamespaceConfiguration);
  209. addName(theNamespaceConfiguration.getServerLocale(), theNamespaceConfiguration.getDisplayName());
  210. ConnectionManager.get().init(theNamespaceConfiguration);
  211. }
  212. catch (final IOException e)
  213. {
  214. throw new UnrecoverableException("Configuration Error", "Provider initialization failure. Reason: " + e.toString());
  215. }
  216. catch (final ClassNotFoundException e)
  217. {
  218. throw new UnrecoverableException("Configuration Error", "Provider initialization failure. Reason: " + e.toString());
  219. }
  220. }
  221. //
  222. // The following methods require no modification compared to their implementations in JDBCSample.
  223. //
  224. private static String getErrorDetails(final UnrecoverableException e)
  225. {
  226. final ByteArrayOutputStream out = new ByteArrayOutputStream();
  227. final PrintStream ps = new PrintStream(out);
  228. ps.println(e.getClass().getName() + " : ");
  229. final String[] messages = e.getMessages();
  230. for (int i = 0; i < messages.length; i++)
  231. ps.println(messages[i]);
  232. ps.println();
  233. e.printStackTrace(ps);
  234. ps.close();
  235. return out.toString();
  236. }
  237. private static String getTenantSql(String tenantId)
  238. {
  239. return " AND (TENANT='' OR TENANT='" + tenantId + "'" + ")";
  240. }
  241. /*
  242. * Generate an exception with applicable display objects for the login prompt Note: If this is the initial logon, to avoid an
  243. * empty logon log, be sure to throw either: a) a UserRecoverableException with null errorDetails b) a
  244. * SystemRecoverableException
  245. */
  246. private void generateAndThrowExceptionForLogonPrompt(String errorDetails) throws UserRecoverableException
  247. {
  248. final UserRecoverableException e =
  249. new UserRecoverableException("Please type your credentials for authentication.", errorDetails);
  250. e.addDisplayObject(new ReadOnlyDisplayObject("Namespace:", "CAMNamespaceDisplayName", this.getName(Locale.getDefault())));
  251. e.addDisplayObject(new TextDisplayObject("User ID:", "CAMUsername"));
  252. e.addDisplayObject(new TextNoEchoDisplayObject("Password:", "CAMPassword"));
  253. throw e;
  254. }
  255. }