From 42e2e7cfd507f9cb4842d3e361844849d745cb4e Mon Sep 17 00:00:00 2001 From: Heng Pan Date: Tue, 4 Feb 2025 21:09:30 +0800 Subject: [PATCH 1/2] refactor(framework) Add allowance for system time drift in the node authentication (#4899) --- src/py/flwr/common/constant.py | 3 ++- .../server/superlink/fleet/grpc_rere/server_interceptor.py | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/py/flwr/common/constant.py b/src/py/flwr/common/constant.py index 664eb5a30cd7..48c17aefad7d 100644 --- a/src/py/flwr/common/constant.py +++ b/src/py/flwr/common/constant.py @@ -116,7 +116,8 @@ PUBLIC_KEY_HEADER = "public-key-bin" # Must end with "-bin" for binary data SIGNATURE_HEADER = "signature-bin" # Must end with "-bin" for binary data TIMESTAMP_HEADER = "timestamp" -TIMESTAMP_TOLERANCE = 10 # Tolerance for timestamp verification +TIMESTAMP_TOLERANCE = 10 # General tolerance for timestamp verification +SYSTEM_TIME_TOLERANCE = 5 # Allowance for system time drift class MessageType: diff --git a/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py b/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py index 2e60a8e0220c..c7b5370f415b 100644 --- a/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +++ b/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py @@ -25,6 +25,7 @@ from flwr.common.constant import ( PUBLIC_KEY_HEADER, SIGNATURE_HEADER, + SYSTEM_TIME_TOLERANCE, TIMESTAMP_HEADER, TIMESTAMP_TOLERANCE, ) @@ -38,6 +39,9 @@ ) from flwr.server.superlink.linkstate import LinkStateFactory +MIN_TIMESTAMP_DIFF = -SYSTEM_TIME_TOLERANCE +MAX_TIMESTAMP_DIFF = TIMESTAMP_TOLERANCE + SYSTEM_TIME_TOLERANCE + def _unary_unary_rpc_terminator(message: str) -> grpc.RpcMethodHandler: def terminate(_request: GrpcMessage, context: grpc.ServicerContext) -> GrpcMessage: @@ -100,7 +104,7 @@ def intercept_service( current = now() time_diff = current - datetime.datetime.fromisoformat(timestamp_iso) # Abort the RPC call if the timestamp is too old or in the future - if not 0 < time_diff.total_seconds() < TIMESTAMP_TOLERANCE: + if not MIN_TIMESTAMP_DIFF < time_diff.total_seconds() < MAX_TIMESTAMP_DIFF: return _unary_unary_rpc_terminator("Invalid timestamp") # Continue the RPC call From 0538cb6e6a64e95e93c82d7c65df2b277eabeeca Mon Sep 17 00:00:00 2001 From: Javier Date: Tue, 4 Feb 2025 15:29:18 +0100 Subject: [PATCH 2/2] refactor(framework) Rename constants for gRPC metadata keys for node auth / user auth (#4902) Co-authored-by: Heng Pan --- src/py/flwr/cli/auth_plugin/oidc_cli_plugin.py | 4 ++-- src/py/flwr/cli/utils.py | 4 ++-- src/py/flwr/common/constant.py | 13 +++++++------ src/py/flwr/server/app.py | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/py/flwr/cli/auth_plugin/oidc_cli_plugin.py b/src/py/flwr/cli/auth_plugin/oidc_cli_plugin.py index 3eb7355c6de1..fc6143813780 100644 --- a/src/py/flwr/cli/auth_plugin/oidc_cli_plugin.py +++ b/src/py/flwr/cli/auth_plugin/oidc_cli_plugin.py @@ -26,7 +26,7 @@ from flwr.common.auth_plugin import CliAuthPlugin from flwr.common.constant import ( ACCESS_TOKEN_KEY, - AUTH_TYPE_KEY, + AUTH_TYPE_JSON_KEY, REFRESH_TOKEN_KEY, AuthType, ) @@ -97,7 +97,7 @@ def store_tokens(self, credentials: UserAuthCredentials) -> None: self.access_token = credentials.access_token self.refresh_token = credentials.refresh_token json_dict = { - AUTH_TYPE_KEY: AuthType.OIDC, + AUTH_TYPE_JSON_KEY: AuthType.OIDC, ACCESS_TOKEN_KEY: credentials.access_token, REFRESH_TOKEN_KEY: credentials.refresh_token, } diff --git a/src/py/flwr/cli/utils.py b/src/py/flwr/cli/utils.py index bd3a2dade5fc..6954f26bb1e8 100644 --- a/src/py/flwr/cli/utils.py +++ b/src/py/flwr/cli/utils.py @@ -28,7 +28,7 @@ from flwr.cli.cli_user_auth_interceptor import CliUserAuthInterceptor from flwr.common.auth_plugin import CliAuthPlugin -from flwr.common.constant import AUTH_TYPE_KEY, CREDENTIALS_DIR, FLWR_DIR +from flwr.common.constant import AUTH_TYPE_JSON_KEY, CREDENTIALS_DIR, FLWR_DIR from flwr.common.grpc import ( GRPC_MAX_MESSAGE_LENGTH, create_channel, @@ -239,7 +239,7 @@ def try_obtain_cli_auth_plugin( try: with config_path.open("r", encoding="utf-8") as file: json_file = json.load(file) - auth_type = json_file[AUTH_TYPE_KEY] + auth_type = json_file[AUTH_TYPE_JSON_KEY] except (FileNotFoundError, KeyError): typer.secho( "❌ Missing or invalid credentials for user authentication. " diff --git a/src/py/flwr/common/constant.py b/src/py/flwr/common/constant.py index 48c17aefad7d..5530f7c7804e 100644 --- a/src/py/flwr/common/constant.py +++ b/src/py/flwr/common/constant.py @@ -108,14 +108,15 @@ # Constants for user authentication CREDENTIALS_DIR = ".credentials" -AUTH_TYPE_KEY = "auth_type" -ACCESS_TOKEN_KEY = "access_token" -REFRESH_TOKEN_KEY = "refresh_token" +AUTH_TYPE_JSON_KEY = "auth-type" # For key name in JSON file +AUTH_TYPE_YAML_KEY = "auth_type" # For key name in YAML file +ACCESS_TOKEN_KEY = "flwr-oidc-access-token" +REFRESH_TOKEN_KEY = "flwr-oidc-refresh-token" # Constants for node authentication -PUBLIC_KEY_HEADER = "public-key-bin" # Must end with "-bin" for binary data -SIGNATURE_HEADER = "signature-bin" # Must end with "-bin" for binary data -TIMESTAMP_HEADER = "timestamp" +PUBLIC_KEY_HEADER = "flwr-public-key-bin" # Must end with "-bin" for binary data +SIGNATURE_HEADER = "flwr-signature-bin" # Must end with "-bin" for binary data +TIMESTAMP_HEADER = "flwr-timestamp" TIMESTAMP_TOLERANCE = 10 # General tolerance for timestamp verification SYSTEM_TIME_TOLERANCE = 5 # Allowance for system time drift diff --git a/src/py/flwr/server/app.py b/src/py/flwr/server/app.py index 079e4b8af80d..97b899d555e5 100644 --- a/src/py/flwr/server/app.py +++ b/src/py/flwr/server/app.py @@ -40,7 +40,7 @@ from flwr.common.auth_plugin import ExecAuthPlugin from flwr.common.config import get_flwr_dir, parse_config_args from flwr.common.constant import ( - AUTH_TYPE_KEY, + AUTH_TYPE_YAML_KEY, CLIENT_OCTET, EXEC_API_DEFAULT_SERVER_ADDRESS, FLEET_API_GRPC_BIDI_DEFAULT_ADDRESS, @@ -578,7 +578,7 @@ def _try_obtain_exec_auth_plugin( # Load authentication configuration auth_config: dict[str, Any] = config.get("authentication", {}) - auth_type: str = auth_config.get(AUTH_TYPE_KEY, "") + auth_type: str = auth_config.get(AUTH_TYPE_YAML_KEY, "") # Load authentication plugin try: