Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(settings): define a 'heartbeat' route, so SecurityHeaders can handle redirected root #45228

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

smokris
Copy link

@smokris smokris commented May 8, 2024

Problem

On sites where the root (/) path is redirected (e.g. when using the Social login plugin), the Admin Overview page incorrectly shows errors about security headers not being set:

Some headers are not set correctly on your instance - The X-Robots-Tag HTTP header is not set to noindex,nofollow. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly. - The X-Permitted-Cross-Domain-Policies HTTP header is not set to none. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly. For more details see the documentation ↗.

Analysis

In lib/base.php, the request path /heartbeat is handled specially by returning early, but no formal route is defined for it.

OCA\Settings\SetupChecks\SecurityHeaders calls URLGenerator::linkToRoute('heartbeat'), but the generated URL is emptystring, since there's no route defined by that name.

It then performs a request on the root (/) path (instead of the expected /heartbeat path). On sites where the root path redirects, SecurityHeaders then incorrectly analyzes the headers of the redirect, instead of analyzing the headers of the Nextcloud heartbeat page.

Proposed solution

Define a heartbeat route, so that URLGenerator::linkToRoute('heartbeat') returns /heartbeat as the SecurityHeaders test seems to expect.

Checklist

…dle redirected root

Signed-off-by: Steve Mokris <steve@kosada.com>
Copy link
Member

@provokateurin provokateurin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to add a test to the setup checks that validates that the check now works.

core/routes.php Show resolved Hide resolved
Comment on lines +43 to +44
/** @var Router */
private $router;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** @var Router */
private $router;
private Router $router;

@provokateurin
Copy link
Member

TBH I've never seen this warning on my local dev instance, can you tell me how to reproduce it?

@come-nc
Copy link
Contributor

come-nc commented May 13, 2024

I cannot tell if adding a route like this is the right fix for this. The heartbeat short circuits a lot of things so it cannot be put in a controller.
It is still a supported URL endpoint so maybe it’s fine to add it like that?

Copy link

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

@cdammanintopix
Copy link
Contributor

cdammanintopix commented May 22, 2024

Hello,
Thank you for this fix.
Without it, I had the following issue in my logs:

{
  "reqId": "xxxxxxxxxx",
  "level": 1,
  "time": "2024-05-22T08:09:18+00:00",
  "remoteAddr": "xxxxxxxxxx",
  "user": "xxxxxxxxxx",
  "app": "no app in context",
  "method": "GET",
  "url": "/settings/ajax/checksetup",
  "message": "Unable to generate a URL for the named route \"heartbeat\" as such route does not exist.",
  "userAgent": "xxxxxxxxxx",
  "version": "29.0.0.19",
  "exception": {
    "Exception": "Symfony\\Component\\Routing\\Exception\\RouteNotFoundException",
    "Message": "Unable to generate a URL for the named route \"heartbeat\" as such route does not exist.",
    "Code": 0,
    "Trace": [
      {
        "file": "/var/www/html/lib/private/Route/Router.php",
        "line": 410,
        "function": "generate",
        "class": "Symfony\\Component\\Routing\\Generator\\UrlGenerator",
        "type": "->",
        "args": [
          "heartbeat",
          [],
          1
        ]
      },
      {
        "file": "/var/www/html/lib/private/Route/CachingRouter.php",
        "line": 65,
        "function": "generate",
        "class": "OC\\Route\\Router",
        "type": "->",
        "args": [
          "heartbeat",
          [],
          false
        ]
      },
      {
        "file": "/var/www/html/lib/private/URLGenerator.php",
        "line": 103,
        "function": "generate",
        "class": "OC\\Route\\CachingRouter",
        "type": "->",
        "args": [
          "heartbeat",
          []
        ]
      },
      {
        "file": "/var/www/html/apps/settings/lib/SetupChecks/SecurityHeaders.php",
        "line": 60,
        "function": "linkToRoute",
        "class": "OC\\URLGenerator",
        "type": "->",
        "args": [
          "heartbeat"
        ]
      },
      {
        "file": "/var/www/html/lib/private/SetupCheck/SetupCheckManager.php",
        "line": 51,
        "function": "run",
        "class": "OCA\\Settings\\SetupChecks\\SecurityHeaders",
        "type": "->",
        "args": []
      },
      {
        "file": "/var/www/html/apps/settings/lib/Controller/CheckSetupController.php",
        "line": 179,
        "function": "runAll",
        "class": "OC\\SetupCheck\\SetupCheckManager",
        "type": "->",
        "args": []
      },
      {
        "file": "/var/www/html/lib/private/AppFramework/Http/Dispatcher.php",
        "line": 232,
        "function": "check",
        "class": "OCA\\Settings\\Controller\\CheckSetupController",
        "type": "->",
        "args": []
      },
      {
        "file": "/var/www/html/lib/private/AppFramework/Http/Dispatcher.php",
        "line": 138,
        "function": "executeController",
        "class": "OC\\AppFramework\\Http\\Dispatcher",
        "type": "->",
        "args": [
          [
            "OCA\\Settings\\Controller\\CheckSetupController"
          ],
          "check"
        ]
      },
      {
        "file": "/var/www/html/lib/private/AppFramework/App.php",
        "line": 184,
        "function": "dispatch",
        "class": "OC\\AppFramework\\Http\\Dispatcher",
        "type": "->",
        "args": [
          [
            "OCA\\Settings\\Controller\\CheckSetupController"
          ],
          "check"
        ]
      },
      {
        "file": "/var/www/html/lib/private/Route/Router.php",
        "line": 338,
        "function": "main",
        "class": "OC\\AppFramework\\App",
        "type": "::",
        "args": [
          "OCA\\Settings\\Controller\\CheckSetupController",
          "check",
          [
            "OC\\AppFramework\\DependencyInjection\\DIContainer"
          ],
          [
            "settings.checksetup.check"
          ]
        ]
      },
      {
        "file": "/var/www/html/lib/base.php",
        "line": 1050,
        "function": "match",
        "class": "OC\\Route\\Router",
        "type": "->",
        "args": [
          "/settings/ajax/checksetup"
        ]
      },
      {
        "file": "/var/www/html/index.php",
        "line": 49,
        "function": "handleRequest",
        "class": "OC",
        "type": "::",
        "args": []
      }
    ],
    "File": "/var/www/html/3rdparty/symfony/routing/Generator/UrlGenerator.php",
    "Line": 144,
    "message": "Unable to generate a URL for the named route \"heartbeat\" as such route does not exist.",
    "exception": [],
    "CustomMessage": "Unable to generate a URL for the named route \"heartbeat\" as such route does not exist."
  },
  "id": "xxxxxxxxxx"
}

Applying this change fixed the issue.

Setup to reproduce: run the docker image as mentioned in the docs with version 29, and go to the page /settings/admin/overview

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants