Conversation
This comment was marked as duplicate.
This comment was marked as duplicate.
This comment was marked as duplicate.
This comment was marked as duplicate.
1 similar comment
This comment was marked as duplicate.
This comment was marked as duplicate.
This comment was marked as resolved.
This comment was marked as resolved.
|
@cla-bot check |
735beb2 to
cdef4c4
Compare
This comment was marked as resolved.
This comment was marked as resolved.
Al2Klimov
left a comment
There was a problem hiding this comment.
13 review comments should be enough for a Friday 13th. :D
| $useCustomCsp = $this->getPopulatedValue('use_custom_csp', 'n') === 'y'; | ||
| if ($useCustomCsp) { | ||
| $this->addHtml((new Callout( | ||
| CalloutType::Warning, |
There was a problem hiding this comment.
- Get Introduce Callout ipl-web#358 done before merging this PR
There was a problem hiding this comment.
Already listed as a requirement
| use ipl\Web\Compat\CompatForm; | ||
| use ipl\Web\Widget\Callout; | ||
|
|
||
| class CspConfigForm extends CompatForm |
There was a problem hiding this comment.
This currently doesn't output the config.ini to the screen like the old ConfigForm did.
I think changing the form type to a CompatForm is still the right call, because we don't want to rely on Zend_Forms forever.
If this behavior essential, we should reimplement the behavior of ConfigFrom as a CompatForm instead.
There was a problem hiding this comment.
Even in new modules we reimplemented this behavior: Icinga/icingadb-web#1269
So I'd not downgrade this functionality.
| ); | ||
|
|
||
| $this->addPolicyTable( | ||
| t('Dashboard'), |
There was a problem hiding this comment.
If you're concerned about #5477 (comment), you should be about this one too:
As not a IW2 dev, I'd have absolutely no clue that these are only my dashboards (if any!) and others may have their own.
Consider listing the dashboard-CSPs of all users, after all we have them (by name) in the preference store or something idk.
Module-provided dashboards should already be included as you should see all modules as admin. I guess they may contain external URLs as well.
There was a problem hiding this comment.
I'm not sure if we always have access to all users in something like LDAP.
Also listing all dashboards and menu entries for all users in an organization on every initial request seems pretty expensive.
If a module wants something whitelisted beyond what is automatically detected, it can already do that.
There was a problem hiding this comment.
We always have access to all users' dashboards and menu entries.
Imagine you make a custom CSP based on the generated one, but latter misses non-your dashboards.
f9f19b4 to
3a4e7ac
Compare
- Reload of form change if Csp was previously enabled in `ConfigController` - Use default attributes in `CspConfigurationTable` - Rename `$policyDirectives` to `$directivePolicies` in `Csp`
This tab requires the new config/security permission
This allows for checkboxes integrated inside the table. This commit also adds disabling modules, dashboards and navigation items individualy.
711be73 to
8c73a47
Compare
be79bd9 to
f25a499
Compare
Al2Klimov
left a comment
There was a problem hiding this comment.
(Nächste Aufgabe V. Don't hurry. I'm not even done, yet...)
My test setup
- Install Fedora 42
- Apply https://github.com/Al2Klimov/ansible-icinga-fedora
- Enable strict CSP
- Upgrade to https://git.icinga.com/packages/icinga-php-library/-/jobs/846553
- Downgrade to https://git.icinga.com/packages/icingaweb/-/jobs/846577
Preparation
Icinga Web 2 packages
https://git.icinga.com/packages/icingaweb/-/jobs/846577
Build icingaweb2 packages from allow-custom-csp-header-5333 branch.
ipl packages
https://git.icinga.com/packages/icinga-php-library/-/jobs/846553
git -C ipl-web checkout origin/maingit -C ipl-web merge --no-edit origin/cps origin/calloutsgit -C ipl-web switch -C $USER/review-cspgit -C ipl-web push -fucd icinga-php-librarygit checkout origin/mainperl -pi -e 'if (m~ipl/web~) { s~main~$ENV{USER}/review-csp~ }' bin/make-snapshot.shperl -pi -e 's~^(PHP_VERSION)=.*~$1=8.2~' bin/make-snapshot.shbin/make-snapshot.sh $USER/review-cspgit diff --stat origin/snapshot/nightly..HEADgit push -fu- Build icinga-php-library packages from $USER/review-csp branch
| } | ||
|
|
||
| try { | ||
| if ($config->get('csp_enable_dashboards', '1')) { |
There was a problem hiding this comment.
When I upgrade IW2 with CSP already being enabled, ...
There was a problem hiding this comment.
Yes, they would be enabled by default. The way I understand @lippserd is that things should just work out of the box.
I would expect most people to have CSP disabled in their setup because of its current limitations.
Just so that I understand what you are saying, it should work like this:
- CSP is off by default, if the admin enables it via the config form, all three of these toggles should automatically enable (despite no entry in the config) and be stored in their on state once the admin submits the form.
- If CSP was already enabled beforehand, they should stay off (again no value in the configuration)
There was a problem hiding this comment.
Exactly! Then it would "just work out of the box" for people who enable it later.
Upgraders who already have CSP enabled did latter because the v2.13 behavior fits their needs. They simply don't expect this behavior change coming from behind through the cold kitchen.
| } | ||
|
|
||
| try { | ||
| if ($config->get('csp_enable_navigation', '1')) { |
There was a problem hiding this comment.
... wouldn't these two toggles suddenly be enabled "by default" and widen my CSP w/o asking?
(I mean, we could default-enable them IN THE FORM, while someone enables CSP at all, but here... ?)
| 'info-circle', | ||
| [ | ||
| 'class' => 'csp-policy-info', | ||
| 'title' => t('This is an automatically generated nonce. Its value is unique per request.'), |
There was a problem hiding this comment.
Unique per request? Are you sure? Because I toggle the CSP settings container reload and get the same nonce.
There was a problem hiding this comment.
It is unique per initial request to icingaweb2 (without javascript XHR request).
If you know a better word, please suggest one.
- request: not clear enough
- session: I would say that refers to a user session (being logged in)
- page load: icinga loads pages all the time, user might not know that (same problem as request)
- leaving it out: But when is it generated?
There was a problem hiding this comment.
@flourish86 I'm not sure what the best wording for this is. Technically it is for each initial request that doesn't come from JavaScript.
Co-authored-by: Alexander Aleksandrovič Klimov <alexander.klimov@icinga.com>
Al2Klimov
left a comment
There was a problem hiding this comment.
31 review comments at once should be enough for a Tuesday 31st. :)
| $csps = Csp::load(new ConfigObject([ | ||
| 'csp_enable_modules' => '1', | ||
| 'csp_enable_dashboards' => '1', | ||
| 'csp_enable_navigation' => '1', |
There was a problem hiding this comment.
Changes to the CSP and enabled modules already trigger page reloads. This is good.
In contrast, dashboard/navigation changes in the GUI don't trigger page reloads, even with these two toggles being enabled. This is bad.
After adding iframe?url=https://packages.icinga.com to the dashboard, Safari complains: "Refused to load https://packages.icinga.com/ because it does not appear in the frame-src directive of the Content Security Policy." I had to open the dev console to see it! And to reload the window to fix it.
There was a problem hiding this comment.
I'm not sure what the best way to solve this is. We can of course reload the page if the user edits one of these two. But that doesn't solve the problem for other users if the item ends up being shared between users.
|
|
||
| if (count($rows) === 0) { | ||
| $this->add( | ||
| HtmlElement::create('p', ['class' => 'csp-form-hint'], sprintf('No %s policies found.', $title)) |
There was a problem hiding this comment.
Not only this reads "No Modules policies found", this is a nightmare for translation.
|
|
||
| if ($field !== null) { | ||
| $this->addElement('checkbox', $field, [ | ||
| 'label' => sprintf($this->translate('Enable %s'), $title), |
There was a problem hiding this comment.
Yet another nightmare for translation...
| * | ||
| * @return void | ||
| */ | ||
| protected function addPolicyTable( |
There was a problem hiding this comment.
Navigation literally says Type: "menu-item". In the UI. What about mapping such rather technical strings to translatable, human-readable text?
There was a problem hiding this comment.
Menu items are extensible and modules can create new types if they desire. So while we can create a mapping it would only ever cover out own types.
There was a problem hiding this comment.
Types from extensions can be displayed literally, unless:
Please check whether we could extend the respective hook with an optional method providing a (possibly translated) display name.
There was a problem hiding this comment.
There is no hook for this. This is part of the modules configuration.php.
I will use the label attribute of the defined navigation type, it is the same as in the configuration screen for the user's navigation.
| $this->addHtml((new Callout( | ||
| CalloutType::Warning, | ||
| $this->translate( | ||
| 'Be aware that the custom CSP-Header completely overrides the automatically generated one.' |
There was a problem hiding this comment.
I miss instructions for the nonce. Keep this in mind when you write the docs.
| * @param string $module the module to load the CSP directive for | ||
| */ | ||
| public function __construct( | ||
| public readonly string $module, |
There was a problem hiding this comment.
Yes, but consider making the whole class readonly instead (as in #5442) while on it.
| { | ||
| public function __construct( | ||
| public readonly string $type, | ||
| public readonly NavigationItem $item, |
There was a problem hiding this comment.
Yes, but consider making the whole class readonly instead (as in #5442).
| class NavigationCspReason extends CspReason | ||
| { | ||
| public function __construct( | ||
| public readonly string $type, |
There was a problem hiding this comment.
Sounds like an enum makes sense here. I'll let it up to you.
| * @param string $name the name to display for CSP reason | ||
| */ | ||
| public function __construct( | ||
| public readonly string $name, |
There was a problem hiding this comment.
Yes, but consider making the whole class readonly instead (as in #5442) while on it.
| * Base class for CSP loaders. | ||
| * A loader is responsible for loading CSP directives from a specific source. | ||
| */ | ||
| abstract class CspLoader |
There was a problem hiding this comment.
Whenever I have the completely free choice of making a class or interface, I make an interface. (PHP doesn't support multiple inheritance.)
| { | ||
| $user = Auth::getInstance()->getUser(); | ||
| if ($user === null) { | ||
| throw new RuntimeException('No user logged in'); |
There was a problem hiding this comment.
I know this only ends up as log warning. But even for a warning, this is a too small "problem" IMAO. I mean, sure, no user logged in. And... now what? Panic? Is this such an uncommon scenario where:
- Admin allows dashboard CSP
- User visits the login page to log in
|
|
||
| $auth = Auth::getInstance(); | ||
| if (! $auth->isAuthenticated()) { | ||
| throw new RuntimeException('No user logged in'); |
There was a problem hiding this comment.
I wonder whether a simple return would be enough...
| public static function fromCsp(Csp $csp, CspReason $reason): static | ||
| { | ||
| $instance = new static($reason); | ||
| $instance->directives = $csp->directives; |
There was a problem hiding this comment.
Yes, directives is protected. Hence accessible. I wonder, though, whether this -and Csp as base class- is actually necessary or a dead simple readonly class with two properties would do it as well. You decide.
In Icinga/icinga2#10397, to be fair, I also enthusiastically used advanced inheritance tricks, but colleagues told me to just make it a property. (K.I.S.S.)
| $header = static::getHeader(); | ||
| $response->setHeader('Content-Security-Policy', $header, true); |
There was a problem hiding this comment.
| $header = static::getHeader(); | |
| $response->setHeader('Content-Security-Policy', $header, true); | |
| $response->setHeader('Content-Security-Policy', static::getHeader(), true); |
| $section['use_custom_csp'] = $this->getValue('use_custom_csp'); | ||
| $section['custom_csp'] = $this->getValue('custom_csp'); | ||
|
|
||
| $this->changed = ! empty(array_diff_assoc( |
There was a problem hiding this comment.
Strange, my CSP page reloads on EVERY saving...







Taking over #5337 (#5337 (comment)) and implementing an override for a completely custom CSP-Header.
As well as adding a table below the form which displays the source of the automatically generated CSP-Header.
Styling for this table is still WIP.
requires Icinga/ipl-web#358
requires Icinga/ipl-web#361
closes #5337
closes #5333