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

feat: add simple auth to server requests #1449

Merged
merged 4 commits into from
Jan 19, 2025
Merged

feat: add simple auth to server requests #1449

merged 4 commits into from
Jan 19, 2025

Conversation

cpvalente
Copy link
Owner

@cpvalente cpvalente commented Jan 14, 2025

This is a proposal for protecting the HTTP connections with a password

Strategy

  • requests go through authentication middleware
  • if the password is active and the user has not provided a password in the cookie or params
  • a) for the client assets, we serve a login page instead
  • b) for the data endpoints, we refuse the request
  • when the user sets the correct password in the login form, we set the cookie that will be with all requests

Notes:

  • had to do some cheating to allow the client to access public files, which are requested before the connection is made
  • need to test the token in query params solution, do we want UI to generate this? or pass the password in the websocket request? The token in query params will be important for generating an authenticated URL and for the companion module

Whis is a viable solution for ontime-cloud, but not for Ontime

Copy link
Contributor

coderabbitai bot commented Jan 14, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The pull request introduces a comprehensive authentication mechanism for the application. It adds WebSocket authentication, creates a login page, implements authentication middleware, and enhances route security. The changes focus on protecting server routes and WebSocket connections by introducing token-based authentication, a login interface, and methods to validate user credentials. The implementation ensures that critical routes and connections require proper authentication before granting access.

Changes

File Change Summary
apps/server/src/adapters/WebsocketAdapter.ts Added authentication mechanism for WebSocket connections, modifying connection event handler to include request validation
apps/server/src/app.ts Integrated cookie parsing, added login router, implemented authentication middleware for routes /data, /api, and static file serving
apps/server/src/externals.ts Added password constant exported from environment variables
apps/server/src/html/login.html Created new login page with styling and form for user authentication
apps/server/src/middleware/authenticate.ts Implemented login router, authentication middleware for HTTP and WebSocket connections
apps/server/src/middleware/noop.ts Added no-operation middleware function
apps/server/src/setup/index.ts Added path for login HTML file in source files configuration
apps/server/src/utils/hash.ts Introduced hashPassword function using SHA-1 hash with base64url encoding

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@cpvalente cpvalente force-pushed the cloud-password branch 3 times, most recently from d4ff59c to ec9f2a6 Compare January 14, 2025 19:23
if (key === 'token' && value === hashedPassword) {
return next();
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
}
}
const url = new URL(`http://localhost${req.url}`);
const maybeToken = url.searchParams.get('token');
if (maybeToken === hashedPassword) {
return next();
}

allow ws clients without cookies to connect

Copy link
Owner Author

Choose a reason for hiding this comment

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

how would the token come up here? do we need an interface in ontime to generate the token or should the websocket client include the raw password in the connection?
What is the normal use case?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I was thinking for when companion connects to the ws endpoint directly

Yeah some place to get the token would be needed, but that could be in the dashboard

@cpvalente cpvalente changed the title feat: add naive auth to server requests feat: add simple auth to server requests Jan 17, 2025
@cpvalente
Copy link
Owner Author

@coderabbitai full review

Copy link
Contributor

coderabbitai bot commented Jan 18, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 13

🧹 Nitpick comments (3)
apps/server/src/middleware/authenticate.ts (1)

66-73: Refactor duplicate authentication logic to improve maintainability.

The authentication logic in the authenticate middleware (lines 66-73) and the authenticateSocket function (lines 116-139) share similar patterns for validating tokens from cookies and query parameters. Refactoring this common logic into a shared utility function will reduce code duplication and enhance maintainability.

Consider creating a utility function, such as isAuthenticated(req: Request | IncomingMessage): boolean, that encapsulates the token validation logic for both HTTP requests and WebSocket connections.

Also applies to: 116-139

apps/server/src/middleware/noop.ts (1)

3-5: Add documentation to clarify the purpose of noopMiddleware.

Providing a brief comment or JSDoc annotation will help other developers understand why this middleware exists and when it should be used.

Example:

 /**
+ * A no-operation middleware function that simply calls `next()`.
+ * Used as a placeholder when no authentication is required.
  */
 export function noopMiddleware(_req: Request, _res: Response, next: NextFunction) {
   next();
 }
apps/server/src/app.ts (1)

98-100: Review static file authentication strategy.

The current implementation authenticates all static file requests, which might:

  1. Impact performance by checking authentication for public assets
  2. Expose sensitive path information in redirects

Consider:

  1. Creating a whitelist of public assets that don't require authentication
  2. Using a separate route for authenticated static files
  3. Implementing proper error handling for unauthorized requests
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a6fbc2 and d4112a4.

⛔ Files ignored due to path filters (2)
  • apps/server/package.json is excluded by none and included by none
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml and included by none
📒 Files selected for processing (8)
  • apps/server/src/adapters/WebsocketAdapter.ts (2 hunks)
  • apps/server/src/app.ts (3 hunks)
  • apps/server/src/externals.ts (1 hunks)
  • apps/server/src/html/login.html (1 hunks)
  • apps/server/src/middleware/authenticate.ts (1 hunks)
  • apps/server/src/middleware/noop.ts (1 hunks)
  • apps/server/src/setup/index.ts (1 hunks)
  • apps/server/src/utils/hash.ts (1 hunks)
🔇 Additional comments (2)
apps/server/src/middleware/authenticate.ts (1)

43-47: Verify secure and sameSite cookie options align with your deployment environment.

The authentication cookie is set with secure: true, which means it will only be sent over HTTPS connections. If the application is served over HTTP (e.g., during development or in environments without SSL), authentication may fail. Similarly, sameSite: 'strict' can prevent the cookie from being sent in some cross-origin requests.

Ensure that the secure and sameSite options are appropriate for your application's deployment environment. If necessary, adjust these settings or implement environment-specific configurations.

apps/server/src/setup/index.ts (1)

90-91: Validate login.html file existence during startup.

The login path is added but there's no validation to ensure the file exists. This could lead to 404 errors if the file is missing.

Run this script to check file existence:

Comment on lines +131 to +118
const url = new URL(req.url || '', `http://${req.headers.host}`);
const token = url.searchParams.get('token');
if (token === hashedPassword) {
return next();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Validate URL construction in authenticateSocket to prevent security risks.

When constructing the URL with new URL(req.url || '', \http://${req.headers.host}`), relying on req.headers.host` can be insecure, as headers can be spoofed by clients. This might lead to incorrect URL parsing or security vulnerabilities.

Apply this diff to use a trusted base URL:

-  const url = new URL(req.url || '', `http://${req.headers.host}`);
+  const url = new URL(req.url || '', 'http://localhost');

Alternatively, validate req.headers.host before use or employ a default value when it is undefined or untrusted.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const url = new URL(req.url || '', `http://${req.headers.host}`);
const token = url.searchParams.get('token');
if (token === hashedPassword) {
return next();
}
const url = new URL(req.url || '', 'http://localhost');
const token = url.searchParams.get('token');
if (token === hashedPassword) {
return next();
}

apps/server/src/middleware/authenticate.ts Outdated Show resolved Hide resolved
apps/server/src/middleware/authenticate.ts Outdated Show resolved Hide resolved
apps/server/src/utils/hash.ts Outdated Show resolved Hide resolved
apps/server/src/externals.ts Show resolved Hide resolved
apps/server/src/app.ts Show resolved Hide resolved
apps/server/src/html/login.html Outdated Show resolved Hide resolved
apps/server/src/html/login.html Outdated Show resolved Hide resolved
apps/server/src/html/login.html Outdated Show resolved Hide resolved
apps/server/src/html/login.html Outdated Show resolved Hide resolved
@cpvalente cpvalente added the priority Issue or PR to be prioritised label Jan 18, 2025
@cpvalente cpvalente requested a review from alex-Arc January 19, 2025 10:16
@cpvalente cpvalente merged commit 420cef8 into master Jan 19, 2025
4 checks passed
@cpvalente cpvalente deleted the cloud-password branch January 19, 2025 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority Issue or PR to be prioritised
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants