PageRenderTime 26ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/javamelody-core/src/main/java/net/bull/javamelody/JiraMonitoringFilter.java

http://javamelody.googlecode.com/
Java | 299 lines | 216 code | 21 blank | 62 comment | 32 complexity | bb253528a6b15ac43ef1bac34e6ebba0 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0
  1. /*
  2. * Copyright 2008-2012 by Emeric Vernat
  3. *
  4. * This file is part of Java Melody.
  5. *
  6. * Java Melody is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Java Melody is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with Java Melody. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package net.bull.javamelody;
  20. import java.io.IOException;
  21. import javax.servlet.FilterChain;
  22. import javax.servlet.FilterConfig;
  23. import javax.servlet.ServletException;
  24. import javax.servlet.ServletRequest;
  25. import javax.servlet.ServletResponse;
  26. import javax.servlet.http.HttpServletRequest;
  27. import javax.servlet.http.HttpServletResponse;
  28. import javax.servlet.http.HttpSession;
  29. /**
  30. * Filter of monitoring JavaMelody for JIRA/Bamboo/Confluence with security check for system administrator.
  31. * @author Emeric Vernat
  32. */
  33. public class JiraMonitoringFilter extends PluginMonitoringFilter {
  34. private static final boolean PLUGIN_AUTHENTICATION_DISABLED = Boolean.parseBoolean(System
  35. .getProperty("javamelody.plugin-authentication-disabled"));
  36. // valeur de com.atlassian.jira.security.Permissions.SYSTEM_ADMIN
  37. private static final int SYSTEM_ADMIN = 44;
  38. // valeur de DefaultAuthenticator.LOGGED_IN_KEY
  39. private static final String LOGGED_IN_KEY = "seraph_defaultauthenticator_user";
  40. private static Class<?> jiraUserClass;
  41. // initialisation ici et non dans la méthode init, car on ne sait pas trčs bien
  42. // quand la méthode init serait appelée dans les systčmes de plugins
  43. private final boolean jira = isJira();
  44. private final boolean confluence = isConfluence();
  45. private final boolean bamboo = isBamboo();
  46. /** {@inheritDoc} */
  47. @Override
  48. public void init(FilterConfig config) throws ServletException {
  49. super.init(config);
  50. if (jira) {
  51. LOG.debug("JavaMelody is monitoring JIRA");
  52. } else if (confluence) {
  53. LOG.debug("JavaMelody is monitoring Confluence");
  54. } else if (bamboo) {
  55. LOG.debug("JavaMelody is monitoring Bamboo");
  56. } else {
  57. LOG.debug("JavaMelody is monitoring unknown, access to monitoring reports is not secured by JavaMelody");
  58. }
  59. if (PLUGIN_AUTHENTICATION_DISABLED) {
  60. LOG.debug("Authentication for monitoring reports has been disabled");
  61. }
  62. }
  63. /** {@inheritDoc} */
  64. @Override
  65. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  66. throws IOException, ServletException {
  67. if (!(request instanceof HttpServletRequest)) {
  68. super.doFilter(request, response, chain);
  69. return;
  70. }
  71. final HttpServletRequest httpRequest = (HttpServletRequest) request;
  72. final HttpServletResponse httpResponse = (HttpServletResponse) response;
  73. if (httpRequest.getRequestURI().equals(getMonitoringUrl(httpRequest))
  74. && hasNotPermission(httpRequest, httpResponse)) {
  75. return;
  76. }
  77. super.doFilter(request, response, chain);
  78. }
  79. private boolean hasNotPermission(HttpServletRequest httpRequest,
  80. HttpServletResponse httpResponse) throws IOException {
  81. return !PLUGIN_AUTHENTICATION_DISABLED
  82. && (jira && !checkJiraAdminPermission(httpRequest, httpResponse) || confluence
  83. && !checkConfluenceAdminPermission(httpRequest, httpResponse) || bamboo
  84. && !checkBambooAdminPermission(httpRequest, httpResponse));
  85. }
  86. private boolean checkJiraAdminPermission(HttpServletRequest httpRequest,
  87. HttpServletResponse httpResponse) throws IOException {
  88. // only the administrator can view the monitoring report
  89. final Object user = getUser(httpRequest);
  90. if (user == null) {
  91. // si non authentifié, on redirige vers la page de login en indiquant la page
  92. // d'origine (sans le contexte) ŕ afficher aprčs le login
  93. final String destination = getMonitoringUrl(httpRequest).substring(
  94. httpRequest.getContextPath().length());
  95. httpResponse.sendRedirect("login.jsp?os_destination=" + destination);
  96. return false;
  97. }
  98. if (!hasJiraSystemAdminPermission(user)) {
  99. // si authentifié mais sans la permission system admin, alors Forbidden
  100. httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden access");
  101. return false;
  102. }
  103. return true;
  104. }
  105. private boolean checkConfluenceAdminPermission(HttpServletRequest httpRequest,
  106. HttpServletResponse httpResponse) throws IOException {
  107. // only the administrator can view the monitoring report
  108. final Object user = getUser(httpRequest);
  109. if (user == null) {
  110. // si non authentifié, on redirige vers la page de login en indiquant la page
  111. // d'origine (sans le contexte) ŕ afficher aprčs le login
  112. final String destination = getMonitoringUrl(httpRequest).substring(
  113. httpRequest.getContextPath().length());
  114. httpResponse.sendRedirect("login.action?os_destination=" + destination);
  115. return false;
  116. }
  117. if (!hasConfluenceAdminPermission(user)) {
  118. // si authentifié mais sans la permission system admin, alors Forbidden
  119. httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden access");
  120. return false;
  121. }
  122. return true;
  123. }
  124. private boolean checkBambooAdminPermission(HttpServletRequest httpRequest,
  125. HttpServletResponse httpResponse) throws IOException {
  126. // only the administrator can view the monitoring report
  127. final Object user = getUser(httpRequest);
  128. if (user == null) {
  129. // si non authentifié, on redirige vers la page de login en indiquant la page
  130. // d'origine (sans le contexte) ŕ afficher aprčs le login
  131. final String destination = getMonitoringUrl(httpRequest).substring(
  132. httpRequest.getContextPath().length());
  133. httpResponse.sendRedirect("userlogin!default.action?os_destination=" + destination);
  134. return false;
  135. }
  136. if (!hasBambooAdminPermission(user)) {
  137. // si authentifié mais sans la permission admin, alors Forbidden
  138. httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden access");
  139. return false;
  140. }
  141. return true;
  142. }
  143. private static boolean hasJiraSystemAdminPermission(Object user) {
  144. try {
  145. final Class<?> managerFactoryClass = Class.forName("com.atlassian.jira.ManagerFactory");
  146. final Class<?> userClass = getJiraUserClass();
  147. // on travaille par réflexion car la compilation normale introduirait une dépendance
  148. // trop compliquée et trop lourde ŕ télécharger pour maven
  149. final Object permissionManager = managerFactoryClass.getMethod("getPermissionManager")
  150. .invoke(null);
  151. final Boolean result = (Boolean) permissionManager.getClass()
  152. .getMethod("hasPermission", Integer.TYPE, userClass)
  153. .invoke(permissionManager, SYSTEM_ADMIN, user);
  154. return result;
  155. } catch (final Exception e) {
  156. throw new IllegalStateException(e);
  157. }
  158. // return user != null
  159. // && com.atlassian.jira.ManagerFactory.getPermissionManager().hasPermission(
  160. // SYSTEM_ADMIN, (com.opensymphony.user.User) user);
  161. }
  162. private static synchronized Class<?> getJiraUserClass() throws ClassNotFoundException { // NOPMD
  163. if (jiraUserClass == null) {
  164. try {
  165. // before JIRA 5:
  166. jiraUserClass = Class.forName("com.opensymphony.user.User");
  167. } catch (final ClassNotFoundException e) {
  168. // since JIRA 5:
  169. jiraUserClass = Class.forName("com.atlassian.crowd.embedded.api.User");
  170. }
  171. }
  172. return jiraUserClass;
  173. }
  174. private static boolean hasConfluenceAdminPermission(Object user) {
  175. try {
  176. final Class<?> containerManagerClass = Class
  177. .forName("com.atlassian.spring.container.ContainerManager");
  178. final Class<?> userClass = Class.forName("com.atlassian.user.User");
  179. // on travaille par réflexion car la compilation normale introduirait une dépendance
  180. // trop compliquée et trop lourde ŕ télécharger pour maven
  181. final Object permissionManager = containerManagerClass.getMethod("getComponent",
  182. String.class).invoke(null, "permissionManager");
  183. final Boolean result = (Boolean) permissionManager.getClass()
  184. .getMethod("isConfluenceAdministrator", userClass)
  185. .invoke(permissionManager, user);
  186. return result;
  187. } catch (final Exception e) {
  188. throw new IllegalStateException(e);
  189. }
  190. // return user != null
  191. // && com.atlassian.spring.container.ContainerManager.getComponent("permissionManager").
  192. // isConfluenceAdministrator((com.opensymphony.user.User) user);
  193. }
  194. private static boolean hasBambooAdminPermission(Object user) {
  195. try {
  196. final Class<?> containerManagerClass = Class
  197. .forName("com.atlassian.spring.container.ContainerManager");
  198. // on travaille par réflexion car la compilation normale introduirait une dépendance
  199. // trop compliquée et trop lourde ŕ télécharger pour maven
  200. final Object bambooPermissionManager = containerManagerClass.getMethod("getComponent",
  201. String.class).invoke(null, "bambooPermissionManager");
  202. Boolean result;
  203. try {
  204. // since Bamboo 3.1 (issue 192):
  205. result = (Boolean) bambooPermissionManager.getClass()
  206. .getMethod("isSystemAdmin", String.class)
  207. .invoke(bambooPermissionManager, user.toString());
  208. } catch (final NoSuchMethodException e) {
  209. // before Bamboo 3.1 (issue 192):
  210. final Class<?> globalApplicationSecureObjectClass = Class
  211. .forName("com.atlassian.bamboo.security.GlobalApplicationSecureObject");
  212. final Object globalApplicationSecureObject = globalApplicationSecureObjectClass
  213. .getField("INSTANCE").get(null);
  214. result = (Boolean) bambooPermissionManager
  215. .getClass()
  216. .getMethod("hasPermission", String.class, String.class, Object.class)
  217. .invoke(bambooPermissionManager, user.toString(), "ADMIN",
  218. globalApplicationSecureObject);
  219. }
  220. return result;
  221. } catch (final Exception e) {
  222. throw new IllegalStateException(e);
  223. }
  224. // return user != null
  225. // && com.atlassian.spring.container.ContainerManager.getComponent("bambooPermissionManager").
  226. // hasPermission(username, "ADMIN", GlobalApplicationSecureObject.INSTANCE);
  227. }
  228. private static Object getUser(HttpServletRequest httpRequest) {
  229. // ceci fonctionne dans JIRA et dans Confluence (et Bamboo ?)
  230. final HttpSession session = httpRequest.getSession(false);
  231. if (session == null) {
  232. return null;
  233. }
  234. Object result = session.getAttribute(LOGGED_IN_KEY);
  235. if (result != null
  236. && "com.atlassian.confluence.user.SessionSafePrincipal".equals(result.getClass()
  237. .getName())) {
  238. // since confluence 4.1.4 (or 4.1.?)
  239. final String userName = result.toString();
  240. // note: httpRequest.getRemoteUser() null in general
  241. try {
  242. final Class<?> containerManagerClass = Class
  243. .forName("com.atlassian.spring.container.ContainerManager");
  244. final Object userAccessor = containerManagerClass.getMethod("getComponent",
  245. String.class).invoke(null, "userAccessor");
  246. result = userAccessor.getClass().getMethod("getUser", String.class)
  247. .invoke(userAccessor, userName);
  248. } catch (final Exception e) {
  249. throw new IllegalStateException(e);
  250. }
  251. }
  252. return result;
  253. }
  254. private static boolean isJira() {
  255. try {
  256. Class.forName("com.atlassian.jira.ManagerFactory");
  257. return true;
  258. } catch (final ClassNotFoundException e) {
  259. return false;
  260. }
  261. }
  262. private static boolean isConfluence() {
  263. try {
  264. Class.forName("com.atlassian.confluence.security.PermissionManager");
  265. return true;
  266. } catch (final ClassNotFoundException e) {
  267. return false;
  268. }
  269. }
  270. private static boolean isBamboo() {
  271. try {
  272. Class.forName("com.atlassian.bamboo.security.BambooPermissionManager");
  273. return true;
  274. } catch (final ClassNotFoundException e) {
  275. return false;
  276. }
  277. }
  278. }