JDBCSample.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /**
  2. * Licensed Materials - Property of IBM
  3. *
  4. * IBM Cognos Products: CAMAAA
  5. *
  6. * (C) Copyright IBM Corp. 2005, 2015
  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.Connection;
  14. import java.sql.SQLException;
  15. import java.util.Locale;
  16. import com.cognos.CAM_AAA.authentication.IBiBusHeader;
  17. import com.cognos.CAM_AAA.authentication.IBiBusHeader2;
  18. import com.cognos.CAM_AAA.authentication.INamespaceAuthenticationProvider2;
  19. import com.cognos.CAM_AAA.authentication.INamespaceConfiguration;
  20. import com.cognos.CAM_AAA.authentication.IQuery;
  21. import com.cognos.CAM_AAA.authentication.IQueryResult;
  22. import com.cognos.CAM_AAA.authentication.ISearchExpression;
  23. import com.cognos.CAM_AAA.authentication.ISearchFilter;
  24. import com.cognos.CAM_AAA.authentication.ISearchStep;
  25. import com.cognos.CAM_AAA.authentication.ISearchStep.SearchAxis;
  26. import com.cognos.CAM_AAA.authentication.IVisa;
  27. import com.cognos.CAM_AAA.authentication.QueryResult;
  28. import com.cognos.CAM_AAA.authentication.ReadOnlyDisplayObject;
  29. import com.cognos.CAM_AAA.authentication.SystemRecoverableException;
  30. import com.cognos.CAM_AAA.authentication.TextDisplayObject;
  31. import com.cognos.CAM_AAA.authentication.TextNoEchoDisplayObject;
  32. import com.cognos.CAM_AAA.authentication.UnrecoverableException;
  33. import com.cognos.CAM_AAA.authentication.UserRecoverableException;
  34. /**
  35. * A Namespace implementation that uses JDBC to connect to a database that contains users and groups.
  36. */
  37. public class JDBCSample extends Namespace implements INamespaceAuthenticationProvider2
  38. {
  39. /**
  40. * A utility class for handling username and password pairs.
  41. */
  42. static class Credential
  43. {
  44. private String password;
  45. private String username;
  46. public String getPassword()
  47. {
  48. return this.password;
  49. }
  50. public String getUsername()
  51. {
  52. return this.username;
  53. }
  54. public boolean isEmpty()
  55. {
  56. return null == this.getUsername() && null == this.getPassword();
  57. }
  58. public void setPassword(final String thePassword)
  59. {
  60. this.password = thePassword;
  61. }
  62. public void setUsername(final String theUsername)
  63. {
  64. this.username = theUsername;
  65. }
  66. }
  67. protected static Credential getCredentialValues(final IBiBusHeader authRequest)
  68. {
  69. final Credential credential = new Credential();
  70. final String[] usernames = authRequest.getCredentialValue("username");
  71. final String[] passwords = authRequest.getCredentialValue("password");
  72. if (null != usernames && 0 < usernames.length)
  73. credential.setUsername(usernames[0]);
  74. if (null != passwords && 0 < passwords.length)
  75. credential.setPassword(passwords[0]);
  76. return credential;
  77. }
  78. private static String getErrorDetails(final UnrecoverableException e)
  79. {
  80. final ByteArrayOutputStream out = new ByteArrayOutputStream();
  81. final PrintStream ps = new PrintStream(out);
  82. ps.println(e.getClass().getName() + " : ");
  83. final String[] messages = e.getMessages();
  84. for (int i = 0; i < messages.length; i++)
  85. ps.println(messages[i]);
  86. ps.close();
  87. return out.toString();
  88. }
  89. protected static Credential getFormFieldValues(final IBiBusHeader authRequest)
  90. {
  91. final Credential credential = new Credential();
  92. final String[] usernames = authRequest.getFormFieldValue("CAMUsername");
  93. final String[] passwords = authRequest.getFormFieldValue("CAMPassword");
  94. if (null != usernames && 0 < usernames.length)
  95. credential.setUsername(usernames[0]);
  96. if (null != passwords && 0 < passwords.length)
  97. credential.setPassword(passwords[0]);
  98. return credential;
  99. }
  100. protected static Credential getTrustedCredentialValues(final IBiBusHeader2 authRequest)
  101. {
  102. final Credential credential = new Credential();
  103. final String[] usernames = authRequest.getTrustedCredentialValue("username");
  104. final String[] passwords = authRequest.getTrustedCredentialValue("password");
  105. if (null != usernames && 0 < usernames.length)
  106. credential.setUsername(usernames[0]);
  107. if (null != passwords && 0 < passwords.length)
  108. credential.setPassword(passwords[0]);
  109. return credential;
  110. }
  111. protected static Credential getTrustedEnvironmentVaribleValue(final IBiBusHeader2 authRequest)
  112. {
  113. final Credential credential = new Credential();
  114. final String[] userNames;
  115. userNames = authRequest.getTrustedEnvVarValue("REMOTE_USER");
  116. if (userNames != null && userNames.length > 0)
  117. {
  118. credential.setUsername(userNames[0]);
  119. // To simplified the case, we set up the password the same as userName
  120. credential.setPassword(userNames[0]);
  121. }
  122. return credential;
  123. }
  124. private ConnectionManager connectionManager;
  125. public Connection getConnection()
  126. {
  127. return this.connectionManager.getConnection();
  128. }
  129. /*
  130. * @see com.cognos.CAM_AAA.provider.INamespace#init(com.cognos.CAM_AAA.provider .INamespaceConfiguration)
  131. */
  132. @Override
  133. public void init(final INamespaceConfiguration theNamespaceConfiguration) throws UnrecoverableException
  134. {
  135. super.init(theNamespaceConfiguration);
  136. this.addName(Locale.getDefault(), theNamespaceConfiguration.getDisplayName());
  137. try
  138. {
  139. this.connectionManager = connectionManager.get();
  140. this.connectionManager.init(theNamespaceConfiguration);
  141. }
  142. catch (final IOException e)
  143. {
  144. throw new UnrecoverableException("Configuration Error", "Provider initialization failure. Reason: " + e.toString());
  145. }
  146. catch (final ClassNotFoundException e)
  147. {
  148. throw new UnrecoverableException("Configuration Error", "Provider initialization failure. Reason: " + e.toString());
  149. }
  150. }
  151. /*
  152. * @see com.cognos.CAM_AAA.provider.INamespaceAuthenticationProvider#logoff(com .cognos.CAM_AAA.provider.IVisa,
  153. * com.cognos.CAM_AAA.provider.IBiBusHeader)
  154. */
  155. public void logoff(final IVisa theVisa, final IBiBusHeader theAuthRequest)
  156. {
  157. try
  158. {
  159. // We can safely assume that we'll get back the same Visa that we
  160. // issued.
  161. final JDBCVisa visa = (JDBCVisa) theVisa;
  162. visa.destroy();
  163. }
  164. catch (final UnrecoverableException e)
  165. {
  166. e.printStackTrace();
  167. }
  168. }
  169. /*
  170. * @see com.cognos.CAM_AAA.provider.INamespaceAuthenticationProvider2#logon(com .cognos.CAM_AAA.provider.IBiBusHeader2)
  171. */
  172. public IVisa logon(final IBiBusHeader2 theAuthRequest) throws UserRecoverableException, SystemRecoverableException,
  173. UnrecoverableException
  174. {
  175. JDBCVisa visa = null;
  176. // 1 - Look for trusted credentials
  177. Credential credential = JDBCSample.getTrustedCredentialValues(theAuthRequest);
  178. if (credential.isEmpty())
  179. credential = JDBCSample.getCredentialValues(theAuthRequest);
  180. if (credential.isEmpty())
  181. credential = JDBCSample.getFormFieldValues(theAuthRequest);
  182. // here, should be something for the single signon case
  183. if (credential.isEmpty() && this.connectionManager.singleSignOnEnabled())
  184. credential = JDBCSample.getTrustedEnvironmentVaribleValue(theAuthRequest);
  185. if (credential.isEmpty() && this.connectionManager.singleSignOnEnabled())
  186. {
  187. // null implies the provider has to start the dance so throw a SysRecov.
  188. // the SysRecov needs to have the name of the variable we look for in
  189. // the second parameter
  190. SystemRecoverableException e = new SystemRecoverableException("Challenge for REMOTE_USER", "REMOTE_USER");
  191. throw e;
  192. }
  193. if (credential.isEmpty())
  194. {
  195. // Assume this is the initial logon and pass null for errorDetails
  196. generateAndThrowExceptionForLogonPrompt(null);
  197. }
  198. try
  199. {
  200. //
  201. // Create a Visa for the new user.
  202. //
  203. visa = new JDBCVisa();
  204. visa.init(this, this.connectionManager, credential.getUsername(), credential.getPassword());
  205. }
  206. catch (final UnrecoverableException ex)
  207. {
  208. final String errorDetails = JDBCSample.getErrorDetails(ex);
  209. // Something went wrong, probably because the user's credentials
  210. // are invalid.
  211. generateAndThrowExceptionForLogonPrompt(errorDetails);
  212. }
  213. return visa;
  214. }
  215. /*
  216. * @see com.cognos.CAM_AAA.provider.INamespaceAuthenticationProvider#search(com .cognos.CAM_AAA.provider.IVisa,
  217. * com.cognos.CAM_AAA.provider.IQuery)
  218. */
  219. public IQueryResult search(final IVisa theVisa, final IQuery theQuery) throws UnrecoverableException
  220. {
  221. // We can safely assume that we'll get back the same Visa that we
  222. // issued.
  223. final JDBCVisa visa = (JDBCVisa) theVisa;
  224. final QueryResult result = new QueryResult();
  225. try
  226. {
  227. final ISearchExpression expression = theQuery.getSearchExpression();
  228. final String objectID = expression.getObjectID();
  229. final ISearchStep[] steps = expression.getSteps();
  230. // It doesn't make sense to have multiple steps for this provider
  231. // since the objects are not hierarchical.
  232. if (steps.length != 1)
  233. throw new UnrecoverableException("Internal Error",
  234. "Invalid search expression. Multiple steps is not supported for this namespace.");
  235. final StringBuffer sqlCondition = new StringBuffer();
  236. final int searchType = steps[0].getAxis();
  237. final ISearchFilter filter = steps[0].getPredicate();
  238. String tenantId = QueryUtil.getTenantId(visa.getAccount());
  239. switch (searchType)
  240. {
  241. case SearchAxis.Self:
  242. case SearchAxis.DescendentOrSelf:
  243. if (objectID == null)
  244. {
  245. if (filter == null || this.matchesFilter(filter))
  246. result.addObject(this);
  247. // Add current namespace
  248. if (searchType == SearchAxis.Self)
  249. return result;
  250. else
  251. sqlCondition.append(QueryUtil.getSqlCondition(filter));
  252. }
  253. else if (objectID.startsWith("u:") && objectID.equals(visa.getAccount().getObjectID()))
  254. {
  255. if (filter == null || this.matchesFilter(filter))
  256. result.addObject(visa.getAccount());
  257. // Add current user
  258. return result;
  259. }
  260. else if (objectID.startsWith("u:"))
  261. {
  262. final String sqlID = objectID.substring(2);
  263. sqlCondition.append(QueryUtil.getSqlCondition(filter));
  264. if (sqlCondition.length() > 0)
  265. sqlCondition.append(" AND ");
  266. sqlCondition.append("ID = " + sqlID + " AND ISUSER = 1");
  267. }
  268. else if (objectID.startsWith("g:"))
  269. {
  270. final String sqlID = objectID.substring(2);
  271. sqlCondition.append(QueryUtil.getSqlCondition(filter));
  272. if (sqlCondition.length() > 0)
  273. sqlCondition.append(" AND ");
  274. sqlCondition.append("ID = " + sqlID + " AND ISGROUP = 1");
  275. }
  276. break;
  277. default:
  278. sqlCondition.append(QueryUtil.getSqlCondition(filter));
  279. break;
  280. }
  281. sqlCondition.append(getTenantSql(tenantId));
  282. QueryUtil.searchQuery(this.connectionManager, sqlCondition.toString(), theQuery.getQueryOption(),
  283. theQuery.getProperties(), theQuery.getSortProperties(), result, this);
  284. }
  285. catch (final SQLException e)
  286. {
  287. e.printStackTrace();
  288. }
  289. catch (final UnrecoverableException e)
  290. {
  291. e.printStackTrace();
  292. }
  293. return result;
  294. }
  295. private static String getTenantSql(String tenantId)
  296. {
  297. return " AND (TENANT='' OR TENANT='" + tenantId + "'" + ")";
  298. }
  299. /*
  300. * Generate an exception with applicable display objects for the login prompt Note: If this is the initial logon, to avoid an
  301. * empty logon log, be sure to throw either: a) a UserRecoverableException with null errorDetails b) a
  302. * SystemRecoverableException
  303. */
  304. private void generateAndThrowExceptionForLogonPrompt(String errorDetails) throws UserRecoverableException
  305. {
  306. final UserRecoverableException e =
  307. new UserRecoverableException("Please type your credentials for authentication.", errorDetails);
  308. e.addDisplayObject(new ReadOnlyDisplayObject("Namespace:", "CAMNamespaceDisplayName", this.getName(Locale.getDefault())));
  309. e.addDisplayObject(new TextDisplayObject("User ID:", "CAMUsername"));
  310. e.addDisplayObject(new TextNoEchoDisplayObject("Password:", "CAMPassword"));
  311. throw e;
  312. }
  313. }