Skip to content

Commit

Permalink
Merge pull request from GHSA-4946-85pr-fvxh
Browse files Browse the repository at this point in the history
Implement server configuration option to specification of allowed CORS origins
  • Loading branch information
bartvanb committed Mar 7, 2024
2 parents a6de8bb + 1bf1603 commit 70bb4e1
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 15 deletions.
26 changes: 16 additions & 10 deletions docs/server/yaml/server_config.yaml
Expand Up @@ -43,29 +43,28 @@ jwt_secret_key: super-secret-key! # recommended but optional

# Settings for the logger
logging:

# Controls the logging output level. Could be one of the following
# levels: CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET
level: DEBUG
level: DEBUG

# Filename of the log-file, used by RotatingFileHandler
file: test.log
file: test.log

# Whether the output is shown in the console or not
use_console: True
use_console: True

# The number of log files that are kept, used by RotatingFileHandler
backup_count: 5

# Size in kB of a single log file, used by RotatingFileHandler
max_size: 1024
max_size: 1024

# format: input for logging.Formatter,
format: "%(asctime)s - %(name)-14s - %(levelname)-8s - %(message)s"
datefmt: "%Y-%m-%d %H:%M:%S"
format: "%(asctime)s - %(name)-14s - %(levelname)-8s - %(message)s"
datefmt: "%Y-%m-%d %H:%M:%S"

# (optional) set the individual log levels per logger name, for example
# mute some loggers that are too verbose.
# (optional) set the individual log levels per logger name, for example
# mute some loggers that are too verbose.
loggers:
- name: urllib3
level: warning
Expand All @@ -82,7 +81,6 @@ logging:

# Additional debug flags
debug:

# Set to `true` to enable debug mode for the socketio server
socketio: false

Expand Down Expand Up @@ -171,3 +169,11 @@ password_policy:
# number of minutes to wait between emails that alert a user that someone is
# trying to log in to their account. Default is 60.
between_email_blocked_login_minutes: 60

# set up with which origins the server should allow CORS requests. The default
# is to allow all origins. If you want to restrict this, you can specify a list
# of origins here. Below are examples to allow requests from the Cotopaxi UI, and
# port 3456 on localhost
cors_allowed_origins:
- https://portal.cotopaxi.vantage6.ai
- http://localhost:3456
48 changes: 43 additions & 5 deletions vantage6-server/vantage6/server/__init__.py
Expand Up @@ -5,6 +5,7 @@
through the API the server hosts. Finally, it also communicates with
authenticated nodes and users via the socketIO server that is run here.
"""

# -*- coding: utf-8 -*-
import os
from gevent import monkey
Expand Down Expand Up @@ -35,6 +36,7 @@
Response,
)
from flask_cors import CORS
from flask_cors.core import probably_regex
from flask_jwt_extended import JWTManager
from flask_marshmallow import Marshmallow
from flask_restful import Api
Expand Down Expand Up @@ -108,8 +110,14 @@ def __init__(self, ctx: ServerContext) -> None:
# Setup Principal, granular API access manegement
self.principal = Principal(self.app, use_sessions=False)

# Enable cross-origin resource sharing
self.cors = CORS(self.app)
# Enable cross-origin resource sharing. Note that Flask-CORS interprets
# the origins as regular expressions.
cors_allowed_origins = self.ctx.config.get("cors_allowed_origins", "*")
self._warn_if_cors_regex(cors_allowed_origins)
self.cors = CORS(
self.app,
resources={r"/*": {"origins": cors_allowed_origins}},
)

# SWAGGER documentation
self.swagger = Swagger(self.app, template=swagger_template)
Expand Down Expand Up @@ -138,6 +146,35 @@ def __init__(self, ctx: ServerContext) -> None:

log.info("Initialization done")

@staticmethod
def _warn_if_cors_regex(origins: str | list[str]) -> None:
"""
Give a warning if CORS origins are regular expressions. This will not work
properly for socket events (Flask-SocketIO checks for string equality and does
not use regex).
Note that we are using the `probably_regex` function from Flask-CORS to check
if the origins are probably regular expressions - the Flask implementation for
determining if it is a regex is a bit hacky (see
https://github.com/corydolphin/flask-cors/blob/3.0.10/flask_cors/core.py#L275-L285)
and Flask-CORS doesn't currently offer an opt out of regex's altogether.
Parameters
----------
origins: str | list[str]
The origins to check
"""
if isinstance(origins, str):
origins = [origins]

for origin in origins:
if probably_regex(origin):
log.warning(
"CORS origin '%s' is a regular expression. Socket events sent from "
"this origin will not be handled properly.",
origin,
)

def setup_socket_connection(self) -> SocketIO:
"""
Setup a socket connection. If a message queue is defined, connect the
Expand All @@ -149,21 +186,22 @@ def setup_socket_connection(self) -> SocketIO:
SocketIO
SocketIO object
"""

msg_queue = self.ctx.config.get("rabbitmq", {}).get("uri")
if msg_queue:
log.debug(f"Connecting to msg queue: {msg_queue}")

debug_mode = self.debug.get("socketio", False)
if debug_mode:
log.debug("SocketIO debug mode enabled")

cors_settings = self.ctx.config.get("cors_allowed_origins", "*")
try:
socketio = SocketIO(
self.app,
async_mode="gevent_uwsgi",
message_queue=msg_queue,
ping_timeout=60,
cors_allowed_origins="*",
cors_allowed_origins=cors_settings,
logger=debug_mode,
engineio_logger=debug_mode,
)
Expand All @@ -179,7 +217,7 @@ def setup_socket_connection(self) -> SocketIO:
self.app,
message_queue=msg_queue,
ping_timeout=60,
cors_allowed_origins="*",
cors_allowed_origins=cors_settings,
logger=debug_mode,
engineio_logger=debug_mode,
)
Expand Down

0 comments on commit 70bb4e1

Please sign in to comment.