PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/projects/jtopen-7.8/src/com/ibm/as400/util/servlet/AuthenticationServlet.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 481 lines | 220 code | 85 blank | 176 comment | 34 complexity | 3db1089cb96687d44539c5fa9c270518 MD5 | raw file
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // JTOpen (IBM Toolbox for Java - OSS version)
  4. //
  5. // Filename: AuthenticationServlet.java
  6. //
  7. // The source code contained herein is licensed under the IBM Public License
  8. // Version 1.0, which has been approved by the Open Source Initiative.
  9. // Copyright (C) 1997-2000 International Business Machines Corporation and
  10. // others. All rights reserved.
  11. //
  12. ///////////////////////////////////////////////////////////////////////////////
  13. package com.ibm.as400.util.servlet;
  14. import java.util.Hashtable;
  15. import java.util.Properties;
  16. import java.net.InetAddress;
  17. import java.net.UnknownHostException;
  18. import java.io.IOException;
  19. import sun.misc.BASE64Decoder;
  20. import javax.servlet.*;
  21. import javax.servlet.http.*;
  22. import com.ibm.as400.access.Log; //$A2C
  23. import com.ibm.as400.access.Trace;
  24. /**
  25. * AuthenticationServlet is an HttpServlet implementation that performs basic authentication for servlets.
  26. * Subclasses should override the validateAuthority() method to perform the authentication. The bypassValidation()
  27. * method can be overridden to authenticate only certain requests and the postValidation() method can be overridden
  28. * for additional processing of the request after authenticating.
  29. **/
  30. public class AuthenticationServlet extends HttpServlet
  31. {
  32. static final long serialVersionUID = 3761917964251765027L;
  33. /**
  34. * The realm used for this servlet instance.
  35. **/
  36. private String realm_ = "localhost";
  37. /**
  38. * The actual name the user will see. This may be the same as realm in some cases. A realm of
  39. * "localhost" may be meaningless to the user, while a realmDisplayName of "mysystem" may be more
  40. * meaningful.
  41. **/
  42. private String realmDisplayName_;
  43. /**
  44. * Hashtable used to keep session data.
  45. **/
  46. private Hashtable sessionTable_ = new Hashtable();
  47. /**
  48. * The log to use for logging traces and errors. //$A2C
  49. **/
  50. private Log log_; //$A2C
  51. // Handles loading the appropriate resource bundle
  52. private static ResourceBundleLoader_s loader_; //$A1A
  53. /**
  54. * Constructs a default AuthenticationServlet object.
  55. **/
  56. public AuthenticationServlet()
  57. {
  58. super();
  59. }
  60. /**
  61. * Constructs an AuthenticationServlet object with the specified <i>user</i>, <i>password</i>, and <i>realm</i>.
  62. *
  63. * @param user The user ID to use.
  64. * @param password The password for this user ID.
  65. * @param realm The realm, which refers to the system name.
  66. **/
  67. public AuthenticationServlet(String user, String password, String realm)
  68. {
  69. super();
  70. setUser(user);
  71. setPassword(password);
  72. setRealm(realm);
  73. }
  74. /**
  75. * Method to check to see if authentication should be performed. The default implementation returns false.
  76. * Subclasses that wish to implement authentication based on the URL can override this method, interrogate
  77. * the request object and determine if authentication should be performed.
  78. *
  79. * @param req The HttpServletRequest object for this request.
  80. * @return true if authentication should not be performed.
  81. */
  82. public boolean bypassAuthentication(HttpServletRequest req)
  83. {
  84. return false;
  85. }
  86. /**
  87. * Get the log object used for tracing and error logging.
  88. *
  89. * @return The Log object to use for this servlet.
  90. */
  91. public Log getLog()
  92. {
  93. return log_;
  94. }
  95. /**
  96. * Retrieve the user that was used for the authentication.
  97. *
  98. * @return The authenticated user ID.
  99. */
  100. public String getUser()
  101. {
  102. Thread currentThread = Thread.currentThread();
  103. String threadId = currentThread.getName();
  104. Properties p = (Properties)sessionTable_.get(threadId);
  105. return p.getProperty("uid");
  106. }
  107. /**
  108. * Retrieve the realm that was used for the authentication. For the IBM i system, the realm is the
  109. * system name.
  110. *
  111. * @return The realm.
  112. */
  113. public String getRealm()
  114. {
  115. return realm_;
  116. }
  117. /**
  118. * Retrieve the Hashtable used to keep session data
  119. *
  120. * @return The session data.
  121. */
  122. Hashtable getSessionData()
  123. {
  124. return sessionTable_;
  125. }
  126. /**
  127. * Servlet initialization. The realm is initialized at this point to localhost. It can be overridden
  128. * by the setRealm() method.
  129. *
  130. * @param config The servlet configuration.
  131. * @exception ServletException A ServletException is thrown if a problem with the servlet occurs.
  132. */
  133. public void init(ServletConfig config)
  134. throws ServletException
  135. {
  136. log_ = new ServletEventLog(config);
  137. super.init(config);
  138. setRealm("localhost"); // @A7C
  139. }
  140. /**
  141. * Log a message to the event log.
  142. *
  143. * @param msg The message to log.
  144. */
  145. public void log(String msg)
  146. {
  147. if (log_ != null)
  148. log_.log(msg);
  149. }
  150. /**
  151. * Log an exception and message to the event log.
  152. *
  153. * @param e The exception to log.
  154. * @param msg The message to log.
  155. */
  156. public void log(Exception e, String msg)
  157. {
  158. if (log_ != null)
  159. log_.log(msg, e);
  160. }
  161. /**
  162. * Send the authentication response to the client.
  163. *
  164. * @param resp The HttpServletResponse object to use.
  165. * @param realmDisplayName The realm name to be displayed by the client.
  166. * @exception IOException An IOException is thrown if a communications error occurs.
  167. */
  168. private void sendAuthenticationResponse(HttpServletResponse resp, String realmDisplayName)
  169. throws IOException
  170. {
  171. log(loader_.substitute(loader_.getText("PROP_DESC_CHALLENGE"), new String[] {realmDisplayName_})); //$A1C
  172. resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  173. resp.setHeader("Www-authenticate", "Basic realm=\"" + realmDisplayName_ + "\"");
  174. resp.setContentType("text/html");
  175. }
  176. /**
  177. * Set the log object used for tracing and error logging.
  178. *
  179. * @param log The Log.
  180. */
  181. public void setLog(Log log) //$A2C
  182. {
  183. if (log == null)
  184. throw new NullPointerException("log");
  185. log_ = log; //$A2C
  186. }
  187. /**
  188. * Set the password. This method can be used to set the password to a default password after bypassing
  189. * authentication.
  190. *
  191. * @param password The password to use.
  192. */
  193. public void setPassword(String password)
  194. {
  195. if (password == null)
  196. throw new NullPointerException("password");
  197. Thread currentThread = Thread.currentThread();
  198. String threadId = currentThread.getName();
  199. Properties p = (Properties)sessionTable_.get(threadId);
  200. if (p == null)
  201. p = new Properties();
  202. p.put("pw", password);
  203. }
  204. /**
  205. * Override the default service() method for HttpServlet. Subclasses should not override this method unless
  206. * necessary. If a subclass overrides this method, it should call super.service() or authentication would
  207. * not occur for the servlet.
  208. *
  209. * @param req The HTTP servlet request.
  210. * @param resp The HTTP servlet response.
  211. * @exception ServletException A ServletException is thrown if a problem with the servlet occurs.
  212. * @exception IOException An IOException is thrown if a communications error occurs.
  213. **/
  214. public void service(HttpServletRequest req, HttpServletResponse resp)
  215. throws ServletException, IOException
  216. {
  217. log(loader_.substitute(loader_.getText("PROP_DESC_SERVICE"), new String[] {req.getRemoteHost(), req.getRemoteAddr()})); //$A1C
  218. // check to see if we should authenticate. Call bypassAuthentication() method, which can be overridden
  219. // by subclasses to see if authentication should be performed. Default implementation is to authenticate
  220. // all requests. Subclasses can override the method and interrogate the request object to determine
  221. // if authentication is needed.
  222. if (!bypassAuthentication(req))
  223. {
  224. // see if the header contained realm user ID and password
  225. String uidpw = req.getHeader("Authorization");
  226. if (uidpw != null)
  227. {
  228. int index = uidpw.indexOf(" ");
  229. uidpw = uidpw.substring(index+1);
  230. // now decode from base64
  231. BASE64Decoder decoder = new BASE64Decoder();
  232. byte[] buffer = decoder.decodeBuffer(uidpw);
  233. String s = new String(buffer);
  234. index = s.indexOf(":");
  235. String uid, pw; // $A8C
  236. // If a character causes the ':' and password which follows to be omitted from the // $A8A
  237. // authoriztion header, then we need to ensure the password is set to an empty // $A8A
  238. // string, which will allow the validateAuthority method to gracefully handle // $A8A
  239. // an invalid uid/pwd string instead of generating exceptions. // $A8A
  240. if (index == -1) // $A8A
  241. {
  242. uid = s; // $A8C
  243. pw = ""; // $A8C
  244. Trace.log(Trace.INFORMATION, "Missing ':' (colon) in authorization header."); // $A8A
  245. } // $A8A
  246. else // $A8A
  247. {
  248. uid = s.substring(0, index);
  249. pw = s.substring(index+1);
  250. }
  251. try
  252. {
  253. log(loader_.substitute(loader_.getText("PROP_DESC_AUTHENTICATING"), new String[] {realm_, uid})); //$A1C
  254. // $A5A
  255. // The return from validateAuthority will tell if the caller wants to continue validation.
  256. // When the caller overrides validateAuthority() they can then return false, which will
  257. // allow them to display there own HTML error message/page in the browser instead of
  258. // getting the default browser message (Error: 503... etc) when an exception occurs.
  259. if (!validateAuthority(realm_, uid, pw)) //$A5C
  260. return; //$A5A
  261. Thread currentThread = Thread.currentThread();
  262. String threadId = currentThread.getName();
  263. Properties p = new Properties();
  264. p.put("realm", realm_);
  265. p.put("uid", uid);
  266. p.put("pwd", pw);
  267. sessionTable_.put(threadId, p);
  268. log( loader_.substitute( loader_.getText( "PROP_DESC_AUTHENTICATED"), new String[ ] {realm_, uid})); //$A1C
  269. //$A5A
  270. // The return from postValidation will tell if the caller wants to continue validation.
  271. // When the caller overrides postValidation() they can then return false, which will
  272. // allow them to display there own HTML error message/page in the browser instead of
  273. // getting the default browser message (Error: 503... etc) when an exception occurs.
  274. if (!postValidation(req, resp)) //$A5C
  275. return; //$A5A
  276. super.service(req, resp);
  277. sessionTable_.remove(threadId);
  278. }
  279. catch (SecurityException se)
  280. {
  281. log(loader_.substitute(loader_.getText("PROP_DESC_AUTHENTICATEFAILED"), new String[] {uid, se.getMessage()})); //$A1C $A6C
  282. if (Trace.isTraceOn()) //$A6A
  283. Trace.log(Trace.ERROR, se); //$A6A
  284. sendAuthenticationResponse(resp, realmDisplayName_);
  285. }
  286. catch (Exception e)
  287. {
  288. log(loader_.substitute(loader_.getText("PROP_DESC_REQFAILED"), new String[] {uid, e.getMessage()})); //$A1C $A6C
  289. if (Trace.isTraceOn()) //$A6A
  290. Trace.log(Trace.ERROR, e); //$A6A
  291. if (e instanceof IOException) //$A4A
  292. throw (IOException)e; //$A4A
  293. else if (e instanceof ServletException) //$A4A
  294. throw (ServletException)e; //$A4A
  295. else if (e instanceof RuntimeException) // @A4C
  296. throw (RuntimeException)e; // @A4C
  297. else //$A4C
  298. throw new ServletException(e.getMessage()); // @A4C
  299. }
  300. log(loader_.substitute(loader_.getText("PROP_DESC_REQCOMPLETED"), new String[] {req.getRemoteHost(), req.getRemoteAddr()})); //$A1C
  301. return;
  302. }
  303. // respond with realm challenge
  304. sendAuthenticationResponse(resp, realmDisplayName_);
  305. }
  306. else
  307. {
  308. super.service(req, resp);
  309. }
  310. }
  311. /**
  312. * Set the realm that will be used for the authentication. For the IBM i system, the realm is the
  313. * system name.
  314. *
  315. * @param realm The realm, which refers to the system name.
  316. **/
  317. public void setRealm(String realm)
  318. {
  319. if (realm == null)
  320. throw new NullPointerException("realm");
  321. if (realm.equalsIgnoreCase("localhost"))
  322. {
  323. try
  324. {
  325. InetAddress local = InetAddress.getLocalHost();
  326. realmDisplayName_ = local.getHostName();
  327. realm_ = realmDisplayName_; // @A7A
  328. }
  329. catch (UnknownHostException e)
  330. {
  331. log(loader_.getText("PROP_DESC_REALMFAILED")); //$A1C $A6C
  332. if (Trace.isTraceOn()) //$A6A
  333. Trace.log(Trace.ERROR, e); //$A6A
  334. realm_ = realm; // @A7A
  335. realmDisplayName_ = realm;
  336. }
  337. }
  338. else
  339. {
  340. realm_ = realm; // @A7A
  341. realmDisplayName_ = realm;
  342. }
  343. }
  344. /**
  345. * Set the user ID. This method can be used to set the user ID to a default user after bypassing
  346. * authenticaiton.
  347. *
  348. * @param user The user ID to use.
  349. **/
  350. public void setUser(String user)
  351. {
  352. if (user == null)
  353. throw new NullPointerException("user");
  354. Thread currentThread = Thread.currentThread();
  355. String threadId = currentThread.getName();
  356. Properties p = (Properties)sessionTable_.get(threadId);
  357. if (p == null)
  358. p = new Properties();
  359. p.put("uid", user);
  360. }
  361. /**
  362. * Method used to validate. The default implementation does nothing. Subclasses should override this method
  363. * and implement appropriate validation scheme.
  364. *
  365. * @param realm The realm to validate against.
  366. * @param uid The user ID to use for validation.
  367. * @param pw The password to use for validation.
  368. *
  369. * @return true if the servlet should continue authenticating; false otherwise. The default is true;
  370. *
  371. * @exception SecurityException This exception should be thrown if validation fails.
  372. * @exception IOException This exception should be thrown if a communication error occurs during validation.
  373. **/
  374. public boolean validateAuthority(String realm, String uid, String pw) //$A5C
  375. throws SecurityException, IOException
  376. {
  377. return true;
  378. }
  379. /**
  380. * Method called after validation has occured. The default implementation does nothing.
  381. * Subclasses should override this method to continue processing the request.
  382. *
  383. * @param req The HTTP servlet request.
  384. * @param resp The HTTP servlet response.
  385. *
  386. * @return true if the servlet should continue authenticating; false otherwise. The default is true;
  387. *
  388. * @exception ServletException A ServletException is thrown if a problem with the servlet occurs.
  389. * @exception IOException An IOException is thrown if a communications error occurs.
  390. **/
  391. public boolean postValidation(HttpServletRequest req, HttpServletResponse resp) //$A3 //$A5C
  392. throws ServletException, IOException
  393. {
  394. return true;
  395. }
  396. }