security.html.twig 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. {% extends '@WebProfiler/Profiler/layout.html.twig' %}
  2. {% block page_title 'Security' %}
  3. {% block toolbar %}
  4. {% if collector.token %}
  5. {% set is_authenticated = collector.enabled and collector.authenticated %}
  6. {% set color_code = is_authenticated ? '' : 'yellow' %}
  7. {% else %}
  8. {% set color_code = collector.enabled ? 'red' : '' %}
  9. {% endif %}
  10. {% set icon %}
  11. {{ include('@Security/Collector/icon.svg') }}
  12. <span class="sf-toolbar-value">{{ collector.user|default('n/a') }}</span>
  13. {% endset %}
  14. {% set text %}
  15. {% if collector.impersonated %}
  16. <div class="sf-toolbar-info-group">
  17. <div class="sf-toolbar-info-piece">
  18. <b>Impersonator</b>
  19. <span>{{ collector.impersonatorUser }}</span>
  20. </div>
  21. </div>
  22. {% endif %}
  23. <div class="sf-toolbar-info-group">
  24. {% if collector.enabled %}
  25. {% if collector.token %}
  26. <div class="sf-toolbar-info-piece">
  27. <b>Logged in as</b>
  28. <span>{{ collector.user }}</span>
  29. </div>
  30. <div class="sf-toolbar-info-piece">
  31. <b>Authenticated</b>
  32. <span class="sf-toolbar-status sf-toolbar-status-{{ is_authenticated ? 'green' : 'red' }}">{{ is_authenticated ? 'Yes' : 'No' }}</span>
  33. </div>
  34. <div class="sf-toolbar-info-piece">
  35. <b>Token class</b>
  36. <span>{{ collector.tokenClass|abbr_class }}</span>
  37. </div>
  38. {% else %}
  39. <div class="sf-toolbar-info-piece">
  40. <b>Authenticated</b>
  41. <span class="sf-toolbar-status sf-toolbar-status-red">No</span>
  42. </div>
  43. {% endif %}
  44. {% if collector.firewall %}
  45. <div class="sf-toolbar-info-piece">
  46. <b>Firewall name</b>
  47. <span>{{ collector.firewall.name }}</span>
  48. </div>
  49. {% endif %}
  50. {% if collector.token and collector.logoutUrl %}
  51. <div class="sf-toolbar-info-piece">
  52. <b>Actions</b>
  53. <span>
  54. <a href="{{ collector.logoutUrl }}">Logout</a>
  55. {% if collector.impersonated and collector.impersonationExitPath %}
  56. | <a href="{{ collector.impersonationExitPath }}">Exit impersonation</a>
  57. {% endif %}
  58. </span>
  59. </div>
  60. {% endif %}
  61. {% else %}
  62. <div class="sf-toolbar-info-piece">
  63. <span>The security is disabled.</span>
  64. </div>
  65. {% endif %}
  66. </div>
  67. {% endset %}
  68. {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url, status: color_code }) }}
  69. {% endblock %}
  70. {% block menu %}
  71. <span class="label {{ not collector.enabled or not collector.token ? 'disabled' }}">
  72. <span class="icon">{{ include('@Security/Collector/icon.svg') }}</span>
  73. <strong>Security</strong>
  74. </span>
  75. {% endblock %}
  76. {% block panel %}
  77. <h2>Security Token</h2>
  78. {% if collector.enabled %}
  79. {% if collector.token %}
  80. <div class="metrics">
  81. <div class="metric">
  82. <span class="value">{{ collector.user == 'anon.' ? 'Anonymous' : collector.user }}</span>
  83. <span class="label">Username</span>
  84. </div>
  85. <div class="metric">
  86. <span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.authenticated ? 'yes' : 'no') ~ '.svg') }}</span>
  87. <span class="label">Authenticated</span>
  88. </div>
  89. </div>
  90. <table>
  91. <thead>
  92. <tr>
  93. <th scope="col" class="key">Property</th>
  94. <th scope="col">Value</th>
  95. </tr>
  96. </thead>
  97. <tbody>
  98. <tr>
  99. <th>Roles</th>
  100. <td>
  101. {{ collector.roles is empty ? 'none' : profiler_dump(collector.roles, maxDepth=1) }}
  102. {% if not collector.authenticated and collector.roles is empty %}
  103. <p class="help">User is not authenticated probably because they have no roles.</p>
  104. {% endif %}
  105. </td>
  106. </tr>
  107. {% if collector.supportsRoleHierarchy %}
  108. <tr>
  109. <th>Inherited Roles</th>
  110. <td>{{ collector.inheritedRoles is empty ? 'none' : profiler_dump(collector.inheritedRoles, maxDepth=1) }}</td>
  111. </tr>
  112. {% endif %}
  113. {% if collector.token %}
  114. <tr>
  115. <th>Token</th>
  116. <td>{{ profiler_dump(collector.token) }}</td>
  117. </tr>
  118. {% endif %}
  119. </tbody>
  120. </table>
  121. {% elseif collector.enabled %}
  122. <div class="empty">
  123. <p>There is no security token.</p>
  124. </div>
  125. {% endif %}
  126. <h2>Security Firewall</h2>
  127. {% if collector.firewall %}
  128. <div class="metrics">
  129. <div class="metric">
  130. <span class="value">{{ collector.firewall.name }}</span>
  131. <span class="label">Name</span>
  132. </div>
  133. <div class="metric">
  134. <span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.firewall.security_enabled ? 'yes' : 'no') ~ '.svg') }}</span>
  135. <span class="label">Security enabled</span>
  136. </div>
  137. <div class="metric">
  138. <span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.firewall.stateless ? 'yes' : 'no') ~ '.svg') }}</span>
  139. <span class="label">Stateless</span>
  140. </div>
  141. <div class="metric">
  142. <span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.firewall.allows_anonymous ? 'yes' : 'no') ~ '.svg') }}</span>
  143. <span class="label">Allows anonymous</span>
  144. </div>
  145. </div>
  146. {% if collector.firewall.security_enabled %}
  147. <h4>Configuration</h4>
  148. <table>
  149. <thead>
  150. <tr>
  151. <th scope="col" class="key">Key</th>
  152. <th scope="col">Value</th>
  153. </tr>
  154. </thead>
  155. <tbody>
  156. <tr>
  157. <th>provider</th>
  158. <td>{{ collector.firewall.provider ?: '(none)' }}</td>
  159. </tr>
  160. <tr>
  161. <th>context</th>
  162. <td>{{ collector.firewall.context ?: '(none)' }}</td>
  163. </tr>
  164. <tr>
  165. <th>entry_point</th>
  166. <td>{{ collector.firewall.entry_point ?: '(none)' }}</td>
  167. </tr>
  168. <tr>
  169. <th>user_checker</th>
  170. <td>{{ collector.firewall.user_checker ?: '(none)' }}</td>
  171. </tr>
  172. <tr>
  173. <th>access_denied_handler</th>
  174. <td>{{ collector.firewall.access_denied_handler ?: '(none)' }}</td>
  175. </tr>
  176. <tr>
  177. <th>access_denied_url</th>
  178. <td>{{ collector.firewall.access_denied_url ?: '(none)' }}</td>
  179. </tr>
  180. <tr>
  181. <th>listeners</th>
  182. <td>{{ collector.firewall.listeners is empty ? '(none)' : profiler_dump(collector.firewall.listeners, maxDepth=1) }}</td>
  183. </tr>
  184. </tbody>
  185. </table>
  186. <h4>Listeners</h4>
  187. {% if collector.listeners|default([]) is empty %}
  188. <div class="empty">
  189. <p>No security listeners have been recorded. Check that debugging is enabled in the kernel.</p>
  190. </div>
  191. {% else %}
  192. <table>
  193. <thead>
  194. <tr>
  195. <th>Listener</th>
  196. <th>Duration</th>
  197. <th>Response</th>
  198. </tr>
  199. </thead>
  200. {% set previous_event = (collector.listeners|first) %}
  201. {% for listener in collector.listeners %}
  202. {% if loop.first or listener != previous_event %}
  203. {% if not loop.first %}
  204. </tbody>
  205. {% endif %}
  206. <tbody>
  207. {% set previous_event = listener %}
  208. {% endif %}
  209. <tr>
  210. <td class="font-normal">{{ profiler_dump(listener.stub) }}</td>
  211. <td class="no-wrap">{{ '%0.2f'|format(listener.time * 1000) }} ms</td>
  212. <td class="font-normal">{{ listener.response ? profiler_dump(listener.response) : '(none)' }}</td>
  213. </tr>
  214. {% if loop.last %}
  215. </tbody>
  216. {% endif %}
  217. {% endfor %}
  218. </table>
  219. {% endif %}
  220. {% endif %}
  221. {% elseif collector.enabled %}
  222. <div class="empty">
  223. <p>This request was not covered by any firewall.</p>
  224. </div>
  225. {% endif %}
  226. {% else %}
  227. <div class="empty">
  228. <p>The security component is disabled.</p>
  229. </div>
  230. {% endif %}
  231. {% if collector.voters|default([]) is not empty %}
  232. <h2>Security Voters <small>({{ collector.voters|length }})</small></h2>
  233. <div class="metrics">
  234. <div class="metric">
  235. <span class="value">{{ collector.voterStrategy|default('unknown') }}</span>
  236. <span class="label">Strategy</span>
  237. </div>
  238. </div>
  239. <table class="voters">
  240. <thead>
  241. <tr>
  242. <th>#</th>
  243. <th>Voter class</th>
  244. </tr>
  245. </thead>
  246. <tbody>
  247. {% for voter in collector.voters %}
  248. <tr>
  249. <td class="font-normal text-small text-muted nowrap">{{ loop.index }}</td>
  250. <td class="font-normal">{{ profiler_dump(voter) }}</td>
  251. </tr>
  252. {% endfor %}
  253. </tbody>
  254. </table>
  255. {% endif %}
  256. {% if collector.accessDecisionLog|default([]) is not empty %}
  257. <h2>Access decision log</h2>
  258. <table class="decision-log">
  259. <col style="width: 30px">
  260. <col style="width: 120px">
  261. <col style="width: 25%">
  262. <col style="width: 60%">
  263. <thead>
  264. <tr>
  265. <th>#</th>
  266. <th>Result</th>
  267. <th>Attributes</th>
  268. <th>Object</th>
  269. </tr>
  270. </thead>
  271. <tbody>
  272. {% for decision in collector.accessDecisionLog %}
  273. <tr class="voter_result">
  274. <td class="font-normal text-small text-muted nowrap">{{ loop.index }}</td>
  275. <td class="font-normal">
  276. {{ decision.result
  277. ? '<span class="label status-success same-width">GRANTED</span>'
  278. : '<span class="label status-error same-width">DENIED</span>'
  279. }}
  280. </td>
  281. <td>
  282. {% if decision.attributes|length == 1 %}
  283. {% set attribute = decision.attributes|first %}
  284. {% if attribute.expression is defined %}
  285. Expression: <pre><code>{{ attribute.expression }}</code></pre>
  286. {% elseif attribute.type == 'string' %}
  287. {{ attribute }}
  288. {% else %}
  289. {{ profiler_dump(attribute) }}
  290. {% endif %}
  291. {% else %}
  292. {{ profiler_dump(decision.attributes) }}
  293. {% endif %}
  294. </td>
  295. <td>{{ profiler_dump(decision.seek('object')) }}</td>
  296. </tr>
  297. <tr class="voter_details">
  298. <td></td>
  299. <td colspan="3">
  300. {% if decision.voter_details is not empty %}
  301. {% set voter_details_id = 'voter-details-' ~ loop.index %}
  302. <div id="{{ voter_details_id }}" class="sf-toggle-content sf-toggle-hidden">
  303. <table>
  304. <tbody>
  305. {% for voter_detail in decision.voter_details %}
  306. <tr>
  307. <td class="font-normal">{{ profiler_dump(voter_detail['class']) }}</td>
  308. {% if collector.voterStrategy == constant('Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManager::STRATEGY_UNANIMOUS') %}
  309. <td class="font-normal text-small">attribute {{ voter_detail['attributes'][0] }}</td>
  310. {% endif %}
  311. <td class="font-normal text-small">
  312. {% if voter_detail['vote'] == constant('Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::ACCESS_GRANTED') %}
  313. ACCESS GRANTED
  314. {% elseif voter_detail['vote'] == constant('Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::ACCESS_ABSTAIN') %}
  315. ACCESS ABSTAIN
  316. {% elseif voter_detail['vote'] == constant('Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::ACCESS_DENIED') %}
  317. ACCESS DENIED
  318. {% else %}
  319. unknown ({{ voter_detail['vote'] }})
  320. {% endif %}
  321. </td>
  322. </tr>
  323. {% endfor %}
  324. </tbody>
  325. </table>
  326. </div>
  327. <a class="btn btn-link text-small sf-toggle" data-toggle-selector="#{{ voter_details_id }}" data-toggle-alt-content="Hide voter details">Show voter details</a>
  328. {% endif %}
  329. </td>
  330. </tr>
  331. {% endfor %}
  332. </tbody>
  333. </table>
  334. {% endif %}
  335. {% endblock %}