/tags/release/7010/aipo/jetspeed/src/main/java/org/apache/jetspeed/services/security/JetspeedDBSecurityService.java

http://aipo.googlecode.com/ · Java · 508 lines · 220 code · 52 blank · 236 comment · 21 complexity · 71fdef2827bce9e0dfabfabd78738b34 MD5 · raw file

  1. /*
  2. * Copyright 2000-2001,2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.jetspeed.services.security;
  17. import java.util.ArrayList;
  18. import java.util.HashMap;
  19. import java.util.Iterator;
  20. import java.util.List;
  21. import javax.servlet.ServletConfig;
  22. import org.apache.jetspeed.om.security.JetspeedUser;
  23. import org.apache.jetspeed.om.security.JetspeedUserFactory;
  24. import org.apache.jetspeed.om.security.UserNamePrincipal;
  25. import org.apache.jetspeed.portal.Portlet;
  26. import org.apache.jetspeed.services.JetspeedPortalAccessController;
  27. import org.apache.jetspeed.services.JetspeedSecurity;
  28. import org.apache.jetspeed.services.JetspeedUserManagement;
  29. import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
  30. import org.apache.jetspeed.services.logging.JetspeedLogger;
  31. import org.apache.jetspeed.services.rundata.JetspeedRunData;
  32. import org.apache.turbine.om.security.User;
  33. import org.apache.turbine.services.InitializationException;
  34. import org.apache.turbine.services.TurbineBaseService;
  35. import org.apache.turbine.services.TurbineServices;
  36. import org.apache.turbine.services.resources.ResourceService;
  37. /**
  38. * <p>This is an implementation of the <code>JetspeedSecurityService</code> interface.
  39. *
  40. *
  41. * @author <a href="mailto:david@bluesunrise.com">David Sean Taylor</a>
  42. * @author <a href="mailto:sgala@hisitech.com">Santiago Gala</a>
  43. * @version $Id: JetspeedDBSecurityService.java,v 1.25 2004/03/31 04:49:10 morciuch Exp $
  44. */
  45. public class JetspeedDBSecurityService extends TurbineBaseService
  46. implements JetspeedSecurityService
  47. {
  48. /**
  49. * Static initialization of the logger for this class
  50. */
  51. private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(JetspeedDBSecurityService.class.getName());
  52. private final static String CONFIG_CASEINSENSITIVE_USERNAME = "caseinsensitive.username";
  53. private final static String CONFIG_CASEINSENSITIVE_PASSWORD = "caseinsensitive.password";
  54. private final static String CONFIG_CASEINSENSITIVE_UPPER = "caseinsensitive.upper";
  55. private final static String CONFIG_LOGON_STRIKE_COUNT = "logon.strike.count";
  56. private final static String CONFIG_LOGON_STRIKE_MAX = "logon.strike.max";
  57. private final static String CONFIG_LOGON_STRIKE_INTERVAL = "logon.strike.interval";
  58. private final static String CONFIG_LOGON_AUTO_DISABLE = "logon.auto.disable";
  59. private final static String CONFIG_ACTIONS_ANON_DISABLE = "actions.anon.disable";
  60. private final static String CONFIG_ACTIONS_ALLUSERS_DISABLE = "actions.allusers.disable";
  61. private final static String CONFIG_ACTIONS_ADMIN_ROLES = "admin.roles";
  62. private final static String CONFIG_NEWUSER_ROLES = "newuser.roles";
  63. private final static String CONFIG_DEFAULT_PERMISSION_LOGGEDIN = "permission.default.loggedin";
  64. private final static String CONFIG_DEFAULT_PERMISSION_ANONYMOUS = "permission.default.anonymous";
  65. private final static String CONFIG_ANONYMOUS_USER = "user.anonymous";
  66. private final static String [] DEFAULT_PERMISSIONS = {""};
  67. private final static String [] DEFAULT_CONFIG_NEWUSER_ROLES =
  68. { "user" };
  69. private final static String [] DEFAULT_ADMIN_ROLES =
  70. { "admin" };
  71. String roles[] = null;
  72. boolean caseInsensitiveUsername = false;
  73. boolean caseInsensitivePassword = false;
  74. boolean caseInsensitiveUpper = true;
  75. boolean actionsAnonDisable = true;
  76. boolean actionsAllUsersDisable = false;
  77. String anonymousUser = "anon";
  78. String[] adminRoles = null;
  79. int strikeCount = 3; // 3 within the interval
  80. int strikeMax = 20; // 20 total failures
  81. long strikeInterval = 300; // five minutes
  82. boolean autoLogonDisable = false;
  83. private static HashMap users = new HashMap();
  84. private static Object sem = new Object();
  85. /**
  86. * This is the early initialization method called by the
  87. * Turbine <code>Service</code> framework
  88. * @param conf The <code>ServletConfig</code>
  89. * @exception throws a <code>InitializationException</code> if the service
  90. * fails to initialize
  91. */
  92. public synchronized void init(ServletConfig conf) throws InitializationException
  93. {
  94. // already initialized
  95. if (getInit()) return;
  96. super.init(conf);
  97. // get configuration parameters from Jetspeed Resources
  98. ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
  99. .getResources(JetspeedSecurityService.SERVICE_NAME);
  100. try
  101. {
  102. roles = serviceConf.getStringArray(CONFIG_NEWUSER_ROLES);
  103. adminRoles = serviceConf.getStringArray(CONFIG_ACTIONS_ADMIN_ROLES);
  104. }
  105. catch (Exception e)
  106. {}
  107. if (null == roles || roles.length == 0)
  108. {
  109. roles = DEFAULT_CONFIG_NEWUSER_ROLES;
  110. }
  111. if (null == adminRoles || adminRoles.length == 0)
  112. {
  113. adminRoles = DEFAULT_ADMIN_ROLES;
  114. }
  115. caseInsensitiveUsername = serviceConf.getBoolean(CONFIG_CASEINSENSITIVE_USERNAME, caseInsensitiveUsername);
  116. caseInsensitivePassword = serviceConf.getBoolean(CONFIG_CASEINSENSITIVE_PASSWORD, caseInsensitivePassword);
  117. caseInsensitiveUpper = serviceConf.getBoolean(CONFIG_CASEINSENSITIVE_UPPER, caseInsensitiveUpper);
  118. strikeCount = serviceConf.getInt(CONFIG_LOGON_STRIKE_COUNT, strikeCount);
  119. strikeInterval = serviceConf.getLong(CONFIG_LOGON_STRIKE_INTERVAL, strikeInterval);
  120. strikeMax = serviceConf.getInt(CONFIG_LOGON_STRIKE_MAX, strikeMax);
  121. autoLogonDisable = serviceConf.getBoolean(CONFIG_LOGON_AUTO_DISABLE, autoLogonDisable);
  122. actionsAnonDisable = serviceConf.getBoolean(CONFIG_ACTIONS_ANON_DISABLE, actionsAnonDisable);
  123. actionsAllUsersDisable = serviceConf.getBoolean(CONFIG_ACTIONS_ALLUSERS_DISABLE, actionsAllUsersDisable);
  124. anonymousUser = serviceConf.getString(CONFIG_ANONYMOUS_USER, anonymousUser);
  125. // initialization done
  126. setInit(true);
  127. }
  128. //////////////////////////////////////////////////////////////////////////
  129. //
  130. // Required JetspeedSecurity Functions
  131. //
  132. // Required Features provided by default JetspeedSecurity
  133. //
  134. //////////////////////////////////////////////////////////////////////////
  135. /*
  136. * Factory to create a new JetspeedUser, using JetspeedUserFactory.
  137. * The class that is created by the default JetspeedUserFactory is configured
  138. * in the JetspeedSecurity properties:
  139. *
  140. * services.JetspeedSecurity.user.class=
  141. * org.apache.jetspeed.om.security.BaseJetspeedUser
  142. *
  143. * @return JetspeedUser a newly created user that implements JetspeedUser.
  144. */
  145. public JetspeedUser getUserInstance()
  146. {
  147. try
  148. {
  149. return JetspeedUserFactory.getInstance();
  150. }
  151. catch (UserException e)
  152. {
  153. return null;
  154. }
  155. }
  156. //////////////////////////////////////////////////////////////////////////
  157. //
  158. // Optional JetspeedSecurity Features
  159. //
  160. // Features are not required to be implemented by Security Provider
  161. //
  162. //////////////////////////////////////////////////////////////////////////
  163. /*
  164. * During logon, the username can be case sensitive or case insensitive.
  165. *
  166. * Given a username, converts the username to either lower or upper case.
  167. * This optional feature is configurable from the JetspeedSecurity.properties:
  168. *
  169. * <code>services.JetspeedSecurity.caseinsensitive.username = true/false</code>
  170. * <code>services.JetspeedSecurity.caseinsensitive.upper = true/false</code>
  171. *
  172. * If <code>caseinsensitive.username</code> is true,
  173. * then conversion is enabled and the username will be converted before
  174. * being sent to the Authentication provider.
  175. *
  176. * @param username The username to be converted depending on configuration.
  177. * @return The converted username.
  178. *
  179. */
  180. public String convertUserName(String username)
  181. {
  182. if (caseInsensitiveUsername)
  183. {
  184. username = (caseInsensitiveUpper) ? username.toUpperCase() : username.toLowerCase();
  185. }
  186. return username;
  187. }
  188. /*
  189. * During logon, the password can be case sensitive or case insensitive.
  190. *
  191. * Given a password, converts the password to either lower or upper case.
  192. * This optional feature is configurable from the JetspeedSecurity.properties:
  193. *
  194. * <code>services.JetspeedSecurity.caseinsensitive.password = true/false</code>
  195. * <code>services.JetspeedSecurity.caseinsensitive.upper = true/false</code>
  196. *
  197. * If <code>caseinsensitive.password</code> is true,
  198. * then conversion is enabled and the password will be converted before
  199. * being sent to the Authentication provider.
  200. *
  201. * @param password The password to be converted depending on configuration.
  202. * @return The converted password.
  203. *
  204. */
  205. public String convertPassword(String password)
  206. {
  207. if (caseInsensitivePassword)
  208. {
  209. password = (caseInsensitiveUpper) ? password.toUpperCase() : password.toLowerCase();
  210. }
  211. return password;
  212. }
  213. /*
  214. * Logon Failure / Account Disabling Feature
  215. *
  216. * Checks and tracks failed user-logon attempts.
  217. * If the user fails to logon after a configurable number of logon attempts,
  218. * then the user's account will be disabled.
  219. *
  220. * This optional feature is configurable from the JetspeedSecurity.properties:
  221. *
  222. * <code>services.JetspeedSecurity.logon.auto.disable=false</code>
  223. *
  224. * The example setting below allows for 3 logon strikes per 300 seconds.
  225. * When the strike.count is exceeded over the strike.interval, the account
  226. * is disabled. The strike.max is the cumulative maximum.
  227. *
  228. * <code>services.JetspeedSecurity.logon.strike.count=3</code>
  229. * <code>services.JetspeedSecurity.logon.strike.interval=300</code>
  230. * <code>services.JetspeedSecurity.logon.strike.max=10</code>
  231. *
  232. * These settings are not persisted, and in a distributed environment are
  233. * only tracked per node.
  234. *
  235. * @param username The username to be checked.
  236. * @return True if the strike count reached the maximum threshold and the
  237. * user's account was disabled, otherwise False.
  238. *
  239. */
  240. public boolean checkDisableAccount(String username)
  241. {
  242. username = convertUserName(username);
  243. // TODO: make this work across a cluster of servers
  244. UserLogonStats stat = (UserLogonStats)users.get(username);
  245. if (stat == null)
  246. {
  247. stat = new UserLogonStats(username);
  248. synchronized (sem)
  249. {
  250. users.put(username, stat);
  251. }
  252. }
  253. boolean disabled = stat.failCheck(strikeCount, strikeInterval, strikeMax);
  254. if (disabled)
  255. {
  256. try
  257. {
  258. // disable the account
  259. JetspeedUser user = (JetspeedUser)JetspeedSecurity.getUser(username);
  260. if (user != null)
  261. {
  262. user.setDisabled("T");
  263. JetspeedSecurity.saveUser(user);
  264. }
  265. }
  266. catch (Exception e)
  267. {
  268. logger.error("Could not disable user: " + username, e);
  269. }
  270. }
  271. return disabled;
  272. }
  273. /*
  274. * Logon Failure / Account Disabling Feature
  275. *
  276. * Returns state of the the logon failure / account disabling feature.
  277. *
  278. * If the user fails to logon after a configurable number of logon attempts,
  279. * then the user's account will be disabled.
  280. *
  281. * @see JetspeedSecurityService#checkLogonFailures
  282. *
  283. * @return True if the feature is enabled, false if the feature is disabled.
  284. *
  285. */
  286. public boolean isDisableAccountCheckEnabled()
  287. {
  288. return autoLogonDisable;
  289. }
  290. /*
  291. * Logon Failure / Account Disabling Feature
  292. *
  293. * Resets counters for the logon failure / account disabling feature.
  294. *
  295. * If the user fails to logon after a configurable number of logon attempts,
  296. * then the user's account will be disabled.
  297. *
  298. * @see JetspeedSecurityService#checkLogonFailures
  299. *
  300. * @param username The username to reset the logon failure counters.
  301. *
  302. */
  303. public void resetDisableAccountCheck(String username)
  304. {
  305. // TODO: make this work across a cluster of servers
  306. username = convertUserName(username);
  307. UserLogonStats stat = (UserLogonStats)users.get(username);
  308. if (stat == null)
  309. {
  310. stat = new UserLogonStats(username);
  311. synchronized (sem)
  312. {
  313. users.put(username, stat);
  314. }
  315. }
  316. stat.reset();
  317. }
  318. //////////////////////////////////////////////////////////////////////////
  319. //
  320. // Optional JetspeedSecurity Helpers
  321. //
  322. //////////////////////////////////////////////////////////////////////////
  323. /**
  324. * Helper to UserManagement.
  325. * Retrieves a <code>JetspeedUser</code> given the primary principle username.
  326. * The principal can be any valid Jetspeed Security Principal:
  327. * <code>org.apache.jetspeed.om.security.UserNamePrincipal</code>
  328. * <code>org.apache.jetspeed.om.security.UserIdPrincipal</code>
  329. *
  330. * The security service may optionally check the current user context
  331. * to determine if the requestor has permission to perform this action.
  332. *
  333. * @param username The username principal.
  334. * @return a <code>JetspeedUser</code> associated to the principal identity.
  335. * @exception UserException when the security provider has a general failure retrieving a user.
  336. * @exception UnknownUserException when the security provider cannot match
  337. * the principal identity to a user.
  338. * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
  339. */
  340. public JetspeedUser getUser(String username)
  341. throws JetspeedSecurityException
  342. {
  343. return JetspeedUserManagement.getUser(new UserNamePrincipal(username));
  344. }
  345. /**
  346. * Helper to PortalAuthorization.
  347. * Gets a <code>JetspeedUser</code> from rundata, authorize user to perform the secured action on
  348. * the given <code>Portlet</code> resource. If the user does not have
  349. * sufficient privilege to perform the action on the resource, the check returns false,
  350. * otherwise when sufficient privilege is present, checkPermission returns true.
  351. *
  352. * @param rundata request that the user is taken from rundatas
  353. * @param action the secured action to be performed on the resource by the user.
  354. * @param portlet the portlet resource.
  355. * @return boolean true if the user has sufficient privilege.
  356. */
  357. public boolean checkPermission(JetspeedRunData runData, String action, Portlet portlet)
  358. {
  359. return JetspeedPortalAccessController.checkPermission(runData.getJetspeedUser(),
  360. portlet,
  361. action);
  362. }
  363. /**
  364. * Helper to PortalAuthorization.
  365. * Gets a <code>JetspeedUser</code> from rundata, authorize user to perform the secured action on
  366. * the given <code>Entry</code> resource. If the user does not have
  367. * sufficient privilege to perform the action on the resource, the check returns false,
  368. * otherwise when sufficient privilege is present, checkPermission returns true.
  369. *
  370. * @param rundata request that the user is taken from rundatas
  371. * @param action the secured action to be performed on the resource by the user.
  372. * @param entry the portal entry resource.
  373. * @return boolean true if the user has sufficient privilege.
  374. public boolean checkPermission(JetspeedRunData runData, String action, RegistryEntry entry)
  375. {
  376. return JetspeedPortalAccessController.checkPermission(runData.getJetspeedUser(),
  377. entry,
  378. action);
  379. }
  380. */
  381. /*
  382. * Security configuration setting to disable all action buttons for the Anon user
  383. * This setting is readonly and is edited in the JetspeedSecurity deployment
  384. *
  385. *
  386. * @return True if the feature actions are disabled for the anon user
  387. *
  388. */
  389. public boolean areActionsDisabledForAnon()
  390. {
  391. return actionsAnonDisable;
  392. }
  393. /*
  394. * Security configuration setting to disable all action buttons for all users
  395. * This setting is readonly and is edited in the JetspeedSecurity deployment
  396. *
  397. *
  398. * @return True if the feature actions are disabled for the all users
  399. *
  400. */
  401. public boolean areActionsDisabledForAllUsers()
  402. {
  403. return actionsAllUsersDisable;
  404. }
  405. /*
  406. * Gets the name of the anonymous user account if applicable
  407. *
  408. *
  409. * @return String the name of the anonymous user account
  410. *
  411. */
  412. public String getAnonymousUserName()
  413. {
  414. return anonymousUser;
  415. }
  416. /*
  417. * Gets the list of administrative roles
  418. *
  419. * @return list of admin roles
  420. */
  421. public List getAdminRoles()
  422. {
  423. List result = new ArrayList();
  424. for (int i = 0; i < adminRoles.length; i++)
  425. {
  426. result.add(adminRoles[i]);
  427. }
  428. return result;
  429. }
  430. /**
  431. * Returns true if user has administrative role
  432. *
  433. * @param user
  434. * @return true if user has administrative role
  435. */
  436. public boolean hasAdminRole(User user)
  437. {
  438. String username = user.getUserName();
  439. try
  440. {
  441. List adminRoles = getAdminRoles();
  442. for (Iterator it = adminRoles.iterator(); it.hasNext();)
  443. {
  444. if (JetspeedSecurity.hasRole(username, (String)it.next()))
  445. {
  446. return true;
  447. }
  448. }
  449. }
  450. catch (Exception e)
  451. {
  452. logger.error(e);
  453. }
  454. return false;
  455. }
  456. }