flwr 1.13.1__py3-none-any.whl → 1.15.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flwr/cli/app.py +5 -0
- flwr/cli/auth_plugin/__init__.py +31 -0
- flwr/cli/auth_plugin/oidc_cli_plugin.py +150 -0
- flwr/cli/build.py +1 -0
- flwr/cli/cli_user_auth_interceptor.py +90 -0
- flwr/cli/config_utils.py +43 -149
- flwr/cli/constant.py +27 -0
- flwr/cli/example.py +1 -0
- flwr/cli/install.py +2 -1
- flwr/cli/log.py +34 -37
- flwr/cli/login/__init__.py +22 -0
- flwr/cli/login/login.py +116 -0
- flwr/cli/ls.py +214 -106
- flwr/cli/new/__init__.py +1 -0
- flwr/cli/new/new.py +2 -1
- flwr/cli/new/templates/app/.gitignore.tpl +3 -0
- flwr/cli/new/templates/app/README.md.tpl +3 -2
- flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +4 -4
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +4 -4
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +4 -4
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +2 -2
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +3 -4
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +2 -2
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +4 -4
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +3 -3
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +2 -2
- flwr/cli/run/__init__.py +1 -0
- flwr/cli/run/run.py +103 -43
- flwr/cli/stop.py +139 -0
- flwr/cli/utils.py +186 -8
- flwr/client/app.py +49 -50
- flwr/client/client.py +1 -32
- flwr/client/clientapp/app.py +23 -26
- flwr/client/clientapp/utils.py +2 -1
- flwr/client/grpc_adapter_client/connection.py +1 -1
- flwr/client/grpc_client/connection.py +2 -13
- flwr/client/grpc_rere_client/client_interceptor.py +19 -119
- flwr/client/grpc_rere_client/connection.py +59 -43
- flwr/client/grpc_rere_client/grpc_adapter.py +12 -12
- flwr/client/message_handler/message_handler.py +1 -2
- flwr/client/message_handler/task_handler.py +0 -17
- flwr/client/mod/comms_mods.py +1 -0
- flwr/client/mod/localdp_mod.py +1 -1
- flwr/client/nodestate/__init__.py +1 -0
- flwr/client/nodestate/nodestate.py +1 -0
- flwr/client/nodestate/nodestate_factory.py +1 -0
- flwr/client/numpy_client.py +0 -44
- flwr/client/rest_client/connection.py +37 -29
- flwr/client/supernode/app.py +20 -74
- flwr/common/address.py +1 -0
- flwr/common/args.py +26 -47
- flwr/common/auth_plugin/__init__.py +24 -0
- flwr/common/auth_plugin/auth_plugin.py +122 -0
- flwr/common/config.py +169 -17
- flwr/common/constant.py +38 -9
- flwr/common/differential_privacy.py +2 -1
- flwr/common/exit/__init__.py +24 -0
- flwr/common/exit/exit.py +99 -0
- flwr/common/exit/exit_code.py +93 -0
- flwr/common/exit_handlers.py +24 -10
- flwr/common/grpc.py +167 -4
- flwr/common/logger.py +66 -7
- flwr/common/message.py +1 -0
- flwr/common/object_ref.py +57 -54
- flwr/common/pyproject.py +1 -0
- flwr/common/record/__init__.py +1 -0
- flwr/common/record/parametersrecord.py +1 -0
- flwr/common/record/recordset.py +1 -1
- flwr/common/retry_invoker.py +77 -0
- flwr/common/secure_aggregation/crypto/symmetric_encryption.py +45 -0
- flwr/common/secure_aggregation/secaggplus_utils.py +2 -2
- flwr/common/serde.py +6 -4
- flwr/common/telemetry.py +15 -4
- flwr/common/typing.py +32 -0
- flwr/common/version.py +1 -0
- flwr/proto/clientappio_pb2.py +1 -1
- flwr/proto/error_pb2.py +1 -1
- flwr/proto/exec_pb2.py +27 -15
- flwr/proto/exec_pb2.pyi +80 -2
- flwr/proto/exec_pb2_grpc.py +102 -0
- flwr/proto/exec_pb2_grpc.pyi +39 -0
- flwr/proto/fab_pb2.py +5 -5
- flwr/proto/fab_pb2.pyi +4 -1
- flwr/proto/fleet_pb2.py +31 -31
- flwr/proto/fleet_pb2.pyi +23 -23
- flwr/proto/fleet_pb2_grpc.py +30 -30
- flwr/proto/fleet_pb2_grpc.pyi +20 -20
- flwr/proto/grpcadapter_pb2.py +1 -1
- flwr/proto/log_pb2.py +1 -1
- flwr/proto/message_pb2.py +1 -1
- flwr/proto/node_pb2.py +3 -3
- flwr/proto/node_pb2.pyi +1 -4
- flwr/proto/recordset_pb2.py +1 -1
- flwr/proto/run_pb2.py +1 -1
- flwr/proto/serverappio_pb2.py +24 -25
- flwr/proto/serverappio_pb2.pyi +32 -32
- flwr/proto/serverappio_pb2_grpc.py +62 -28
- flwr/proto/serverappio_pb2_grpc.pyi +29 -16
- flwr/proto/simulationio_pb2.py +3 -3
- flwr/proto/simulationio_pb2_grpc.py +34 -0
- flwr/proto/simulationio_pb2_grpc.pyi +13 -0
- flwr/proto/task_pb2.py +1 -1
- flwr/proto/transport_pb2.py +1 -1
- flwr/server/app.py +152 -112
- flwr/server/compat/app_utils.py +7 -2
- flwr/server/compat/driver_client_proxy.py +1 -2
- flwr/server/driver/grpc_driver.py +38 -85
- flwr/server/driver/inmemory_driver.py +7 -2
- flwr/server/run_serverapp.py +8 -9
- flwr/server/serverapp/app.py +37 -13
- flwr/server/strategy/dpfedavg_fixed.py +1 -0
- flwr/server/superlink/driver/serverappio_grpc.py +2 -1
- flwr/server/superlink/driver/serverappio_servicer.py +148 -63
- flwr/server/superlink/ffs/disk_ffs.py +1 -0
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +20 -87
- flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -0
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +2 -165
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +56 -35
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +99 -169
- flwr/server/superlink/fleet/message_handler/message_handler.py +69 -29
- flwr/server/superlink/fleet/rest_rere/rest_api.py +20 -19
- flwr/server/superlink/fleet/vce/__init__.py +1 -0
- flwr/server/superlink/fleet/vce/backend/__init__.py +1 -0
- flwr/server/superlink/fleet/vce/backend/raybackend.py +1 -0
- flwr/server/superlink/fleet/vce/vce_api.py +2 -2
- flwr/server/superlink/linkstate/in_memory_linkstate.py +60 -99
- flwr/server/superlink/linkstate/linkstate.py +30 -36
- flwr/server/superlink/linkstate/sqlite_linkstate.py +105 -188
- flwr/server/superlink/linkstate/utils.py +18 -8
- flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
- flwr/server/superlink/simulation/simulationio_servicer.py +33 -0
- flwr/server/superlink/utils.py +65 -0
- flwr/server/utils/validator.py +9 -34
- flwr/simulation/app.py +20 -10
- flwr/simulation/legacy_app.py +4 -2
- flwr/simulation/ray_transport/ray_actor.py +1 -0
- flwr/simulation/ray_transport/utils.py +1 -0
- flwr/simulation/run_simulation.py +36 -22
- flwr/simulation/simulationio_connection.py +5 -1
- flwr/superexec/app.py +1 -0
- flwr/superexec/deployment.py +1 -0
- flwr/superexec/exec_grpc.py +20 -2
- flwr/superexec/exec_servicer.py +97 -2
- flwr/superexec/exec_user_auth_interceptor.py +101 -0
- flwr/superexec/executor.py +1 -0
- {flwr-1.13.1.dist-info → flwr-1.15.0.dist-info}/METADATA +14 -13
- {flwr-1.13.1.dist-info → flwr-1.15.0.dist-info}/RECORD +150 -144
- flwr/proto/common_pb2.py +0 -36
- flwr/proto/common_pb2.pyi +0 -121
- flwr/proto/common_pb2_grpc.py +0 -4
- flwr/proto/common_pb2_grpc.pyi +0 -4
- flwr/proto/control_pb2.py +0 -27
- flwr/proto/control_pb2.pyi +0 -7
- flwr/proto/control_pb2_grpc.py +0 -135
- flwr/proto/control_pb2_grpc.pyi +0 -53
- {flwr-1.13.1.dist-info → flwr-1.15.0.dist-info}/LICENSE +0 -0
- {flwr-1.13.1.dist-info → flwr-1.15.0.dist-info}/WHEEL +0 -0
- {flwr-1.13.1.dist-info → flwr-1.15.0.dist-info}/entry_points.txt +0 -0
flwr/client/supernode/app.py
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Flower SuperNode."""
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
import argparse
|
|
18
|
-
import sys
|
|
19
19
|
from logging import DEBUG, ERROR, INFO, WARN
|
|
20
20
|
from pathlib import Path
|
|
21
21
|
from typing import Optional
|
|
@@ -39,8 +39,9 @@ from flwr.common.constant import (
|
|
|
39
39
|
TRANSPORT_TYPE_GRPC_RERE,
|
|
40
40
|
TRANSPORT_TYPE_REST,
|
|
41
41
|
)
|
|
42
|
+
from flwr.common.exit import ExitCode, flwr_exit
|
|
42
43
|
from flwr.common.exit_handlers import register_exit_handlers
|
|
43
|
-
from flwr.common.logger import log
|
|
44
|
+
from flwr.common.logger import log
|
|
44
45
|
|
|
45
46
|
from ..app import start_client_internal
|
|
46
47
|
from ..clientapp.utils import get_load_client_app_fn
|
|
@@ -49,7 +50,6 @@ from ..clientapp.utils import get_load_client_app_fn
|
|
|
49
50
|
def run_supernode() -> None:
|
|
50
51
|
"""Run Flower SuperNode."""
|
|
51
52
|
args = _parse_args_run_supernode().parse_args()
|
|
52
|
-
_warn_deprecated_server_arg(args)
|
|
53
53
|
|
|
54
54
|
log(INFO, "Starting Flower SuperNode")
|
|
55
55
|
|
|
@@ -63,17 +63,6 @@ def run_supernode() -> None:
|
|
|
63
63
|
"Ignoring `--flwr-dir`.",
|
|
64
64
|
)
|
|
65
65
|
|
|
66
|
-
# Exit if unsupported argument is passed by the user
|
|
67
|
-
if args.app is not None:
|
|
68
|
-
log(
|
|
69
|
-
ERROR,
|
|
70
|
-
"The `app` argument is deprecated. The SuperNode now automatically "
|
|
71
|
-
"uses the ClientApp delivered from the SuperLink. Providing the app "
|
|
72
|
-
"directory manually is no longer supported. Please remove the `app` "
|
|
73
|
-
"argument from your command.",
|
|
74
|
-
)
|
|
75
|
-
sys.exit(1)
|
|
76
|
-
|
|
77
66
|
root_certificates = try_obtain_root_certificates(args, args.superlink)
|
|
78
67
|
load_fn = get_load_client_app_fn(
|
|
79
68
|
default_app_ref="",
|
|
@@ -85,6 +74,12 @@ def run_supernode() -> None:
|
|
|
85
74
|
|
|
86
75
|
log(DEBUG, "Isolation mode: %s", args.isolation)
|
|
87
76
|
|
|
77
|
+
# Register handlers for graceful shutdown
|
|
78
|
+
register_exit_handlers(
|
|
79
|
+
event_type=EventType.RUN_SUPERNODE_LEAVE,
|
|
80
|
+
exit_message="SuperNode terminated gracefully.",
|
|
81
|
+
)
|
|
82
|
+
|
|
88
83
|
start_client_internal(
|
|
89
84
|
server_address=args.superlink,
|
|
90
85
|
load_client_app_fn=load_fn,
|
|
@@ -102,60 +97,22 @@ def run_supernode() -> None:
|
|
|
102
97
|
clientappio_api_address=args.clientappio_api_address,
|
|
103
98
|
)
|
|
104
99
|
|
|
105
|
-
# Graceful shutdown
|
|
106
|
-
register_exit_handlers(
|
|
107
|
-
event_type=EventType.RUN_SUPERNODE_LEAVE,
|
|
108
|
-
)
|
|
109
|
-
|
|
110
100
|
|
|
111
101
|
def run_client_app() -> None:
|
|
112
102
|
"""Run Flower client app."""
|
|
113
103
|
event(EventType.RUN_CLIENT_APP_ENTER)
|
|
114
104
|
log(
|
|
115
105
|
ERROR,
|
|
116
|
-
"The command `flower-client-app` has been replaced by `
|
|
106
|
+
"The command `flower-client-app` has been replaced by `flwr run`.",
|
|
117
107
|
)
|
|
118
|
-
log(INFO, "Execute `flower-supernode --help` to learn how to use it.")
|
|
119
108
|
register_exit_handlers(event_type=EventType.RUN_CLIENT_APP_LEAVE)
|
|
120
109
|
|
|
121
110
|
|
|
122
|
-
def _warn_deprecated_server_arg(args: argparse.Namespace) -> None:
|
|
123
|
-
"""Warn about the deprecated argument `--server`."""
|
|
124
|
-
if args.server != FLEET_API_GRPC_RERE_DEFAULT_ADDRESS:
|
|
125
|
-
warn = "Passing flag --server is deprecated. Use --superlink instead."
|
|
126
|
-
warn_deprecated_feature(warn)
|
|
127
|
-
|
|
128
|
-
if args.superlink != FLEET_API_GRPC_RERE_DEFAULT_ADDRESS:
|
|
129
|
-
# if `--superlink` also passed, then
|
|
130
|
-
# warn user that this argument overrides what was passed with `--server`
|
|
131
|
-
log(
|
|
132
|
-
WARN,
|
|
133
|
-
"Both `--server` and `--superlink` were passed. "
|
|
134
|
-
"`--server` will be ignored. Connecting to the Superlink Fleet API "
|
|
135
|
-
"at %s.",
|
|
136
|
-
args.superlink,
|
|
137
|
-
)
|
|
138
|
-
else:
|
|
139
|
-
args.superlink = args.server
|
|
140
|
-
|
|
141
|
-
|
|
142
111
|
def _parse_args_run_supernode() -> argparse.ArgumentParser:
|
|
143
112
|
"""Parse flower-supernode command line arguments."""
|
|
144
113
|
parser = argparse.ArgumentParser(
|
|
145
114
|
description="Start a Flower SuperNode",
|
|
146
115
|
)
|
|
147
|
-
|
|
148
|
-
parser.add_argument(
|
|
149
|
-
"app",
|
|
150
|
-
nargs="?",
|
|
151
|
-
default=None,
|
|
152
|
-
help=(
|
|
153
|
-
"(REMOVED) This argument is removed. The SuperNode now automatically "
|
|
154
|
-
"uses the ClientApp delivered from the SuperLink, so there is no need to "
|
|
155
|
-
"provide the app directory manually. This argument will be removed in a "
|
|
156
|
-
"future version."
|
|
157
|
-
),
|
|
158
|
-
)
|
|
159
116
|
_parse_args_common(parser)
|
|
160
117
|
parser.add_argument(
|
|
161
118
|
"--flwr-dir",
|
|
@@ -228,15 +185,12 @@ def _parse_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
228
185
|
help="Specifies the path to the PEM-encoded root certificate file for "
|
|
229
186
|
"establishing secure HTTPS connections.",
|
|
230
187
|
)
|
|
231
|
-
parser.add_argument(
|
|
232
|
-
"--server",
|
|
233
|
-
default=FLEET_API_GRPC_RERE_DEFAULT_ADDRESS,
|
|
234
|
-
help="Server address",
|
|
235
|
-
)
|
|
236
188
|
parser.add_argument(
|
|
237
189
|
"--superlink",
|
|
238
190
|
default=FLEET_API_GRPC_RERE_DEFAULT_ADDRESS,
|
|
239
|
-
help="SuperLink Fleet API
|
|
191
|
+
help="SuperLink Fleet API address (IPv4, IPv6, or a domain name). If using the "
|
|
192
|
+
"REST (experimental) transport, ensure your address is in the form "
|
|
193
|
+
"`http://...` or `https://...` when TLS is enabled.",
|
|
240
194
|
)
|
|
241
195
|
parser.add_argument(
|
|
242
196
|
"--max-retries",
|
|
@@ -280,11 +234,7 @@ def _try_setup_client_authentication(
|
|
|
280
234
|
return None
|
|
281
235
|
|
|
282
236
|
if not args.auth_supernode_private_key or not args.auth_supernode_public_key:
|
|
283
|
-
|
|
284
|
-
"Authentication requires file paths to both "
|
|
285
|
-
"'--auth-supernode-private-key' and '--auth-supernode-public-key'"
|
|
286
|
-
"to be provided (providing only one of them is not sufficient)."
|
|
287
|
-
)
|
|
237
|
+
flwr_exit(ExitCode.SUPERNODE_NODE_AUTH_KEYS_REQUIRED)
|
|
288
238
|
|
|
289
239
|
try:
|
|
290
240
|
ssh_private_key = load_ssh_private_key(
|
|
@@ -294,11 +244,9 @@ def _try_setup_client_authentication(
|
|
|
294
244
|
if not isinstance(ssh_private_key, ec.EllipticCurvePrivateKey):
|
|
295
245
|
raise ValueError()
|
|
296
246
|
except (ValueError, UnsupportedAlgorithm):
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
"
|
|
300
|
-
"curve private and public key pair. Please ensure that the file "
|
|
301
|
-
"path points to a valid private key file and try again."
|
|
247
|
+
flwr_exit(
|
|
248
|
+
ExitCode.SUPERNODE_NODE_AUTH_KEYS_INVALID,
|
|
249
|
+
"Unable to parse the private key file.",
|
|
302
250
|
)
|
|
303
251
|
|
|
304
252
|
try:
|
|
@@ -308,11 +256,9 @@ def _try_setup_client_authentication(
|
|
|
308
256
|
if not isinstance(ssh_public_key, ec.EllipticCurvePublicKey):
|
|
309
257
|
raise ValueError()
|
|
310
258
|
except (ValueError, UnsupportedAlgorithm):
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
"
|
|
314
|
-
"curve private and public key pair. Please ensure that the file "
|
|
315
|
-
"path points to a valid public key file and try again."
|
|
259
|
+
flwr_exit(
|
|
260
|
+
ExitCode.SUPERNODE_NODE_AUTH_KEYS_INVALID,
|
|
261
|
+
"Unable to parse the public key file.",
|
|
316
262
|
)
|
|
317
263
|
|
|
318
264
|
return (
|
flwr/common/address.py
CHANGED
flwr/common/args.py
CHANGED
|
@@ -14,18 +14,15 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Common Flower arguments."""
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
import argparse
|
|
18
19
|
import sys
|
|
19
20
|
from logging import DEBUG, ERROR, WARN
|
|
20
21
|
from os.path import isfile
|
|
21
22
|
from pathlib import Path
|
|
22
|
-
from typing import Optional
|
|
23
|
+
from typing import Optional, Union
|
|
23
24
|
|
|
24
|
-
from flwr.common.constant import
|
|
25
|
-
TRANSPORT_TYPE_GRPC_ADAPTER,
|
|
26
|
-
TRANSPORT_TYPE_GRPC_RERE,
|
|
27
|
-
TRANSPORT_TYPE_REST,
|
|
28
|
-
)
|
|
25
|
+
from flwr.common.constant import TRANSPORT_TYPE_REST
|
|
29
26
|
from flwr.common.logger import log
|
|
30
27
|
|
|
31
28
|
|
|
@@ -54,9 +51,9 @@ def add_args_flwr_app_common(parser: argparse.ArgumentParser) -> None:
|
|
|
54
51
|
def try_obtain_root_certificates(
|
|
55
52
|
args: argparse.Namespace,
|
|
56
53
|
grpc_server_address: str,
|
|
57
|
-
) -> Optional[bytes]:
|
|
54
|
+
) -> Optional[Union[bytes, str]]:
|
|
58
55
|
"""Validate and return the root certificates."""
|
|
59
|
-
root_cert_path = args.root_certificates
|
|
56
|
+
root_cert_path: Optional[str] = args.root_certificates
|
|
60
57
|
if args.insecure:
|
|
61
58
|
if root_cert_path is not None:
|
|
62
59
|
sys.exit(
|
|
@@ -92,56 +89,38 @@ def try_obtain_root_certificates(
|
|
|
92
89
|
grpc_server_address,
|
|
93
90
|
root_cert_path,
|
|
94
91
|
)
|
|
92
|
+
if args.transport == TRANSPORT_TYPE_REST:
|
|
93
|
+
return root_cert_path
|
|
95
94
|
return root_certificates
|
|
96
95
|
|
|
97
96
|
|
|
98
97
|
def try_obtain_server_certificates(
|
|
99
98
|
args: argparse.Namespace,
|
|
100
|
-
transport_type: str,
|
|
101
99
|
) -> Optional[tuple[bytes, bytes, bytes]]:
|
|
102
100
|
"""Validate and return the CA cert, server cert, and server private key."""
|
|
103
101
|
if args.insecure:
|
|
104
102
|
log(WARN, "Option `--insecure` was set. Starting insecure HTTP server.")
|
|
105
103
|
return None
|
|
106
104
|
# Check if certificates are provided
|
|
107
|
-
if
|
|
108
|
-
if
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
)
|
|
127
|
-
if transport_type == TRANSPORT_TYPE_REST:
|
|
128
|
-
if args.ssl_certfile and args.ssl_keyfile:
|
|
129
|
-
if not isfile(args.ssl_certfile):
|
|
130
|
-
sys.exit("Path argument `--ssl-certfile` does not point to a file.")
|
|
131
|
-
if not isfile(args.ssl_keyfile):
|
|
132
|
-
sys.exit("Path argument `--ssl-keyfile` does not point to a file.")
|
|
133
|
-
certificates = (
|
|
134
|
-
b"",
|
|
135
|
-
Path(args.ssl_certfile).read_bytes(), # server certificate
|
|
136
|
-
Path(args.ssl_keyfile).read_bytes(), # server private key
|
|
137
|
-
)
|
|
138
|
-
return certificates
|
|
139
|
-
if args.ssl_certfile or args.ssl_keyfile:
|
|
140
|
-
sys.exit(
|
|
141
|
-
"You need to provide valid file paths to `--ssl-certfile` "
|
|
142
|
-
"and `--ssl-keyfile` to create a secure connection "
|
|
143
|
-
"in Fleet API server (REST, experimental)."
|
|
144
|
-
)
|
|
105
|
+
if args.ssl_certfile and args.ssl_keyfile and args.ssl_ca_certfile:
|
|
106
|
+
if not isfile(args.ssl_ca_certfile):
|
|
107
|
+
sys.exit("Path argument `--ssl-ca-certfile` does not point to a file.")
|
|
108
|
+
if not isfile(args.ssl_certfile):
|
|
109
|
+
sys.exit("Path argument `--ssl-certfile` does not point to a file.")
|
|
110
|
+
if not isfile(args.ssl_keyfile):
|
|
111
|
+
sys.exit("Path argument `--ssl-keyfile` does not point to a file.")
|
|
112
|
+
certificates = (
|
|
113
|
+
Path(args.ssl_ca_certfile).read_bytes(), # CA certificate
|
|
114
|
+
Path(args.ssl_certfile).read_bytes(), # server certificate
|
|
115
|
+
Path(args.ssl_keyfile).read_bytes(), # server private key
|
|
116
|
+
)
|
|
117
|
+
return certificates
|
|
118
|
+
if args.ssl_certfile or args.ssl_keyfile or args.ssl_ca_certfile:
|
|
119
|
+
sys.exit(
|
|
120
|
+
"You need to provide valid file paths to `--ssl-certfile`, "
|
|
121
|
+
"`--ssl-keyfile`, and `—-ssl-ca-certfile` to create a secure "
|
|
122
|
+
"connection in Fleet API server (gRPC-rere)."
|
|
123
|
+
)
|
|
145
124
|
log(
|
|
146
125
|
ERROR,
|
|
147
126
|
"Certificates are required unless running in insecure mode. "
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Auth plugin components."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from .auth_plugin import CliAuthPlugin as CliAuthPlugin
|
|
19
|
+
from .auth_plugin import ExecAuthPlugin as ExecAuthPlugin
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"CliAuthPlugin",
|
|
23
|
+
"ExecAuthPlugin",
|
|
24
|
+
]
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Abstract classes for Flower User Auth Plugin."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
from collections.abc import Sequence
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Optional, Union
|
|
22
|
+
|
|
23
|
+
from flwr.proto.exec_pb2_grpc import ExecStub
|
|
24
|
+
|
|
25
|
+
from ..typing import UserAuthCredentials, UserAuthLoginDetails
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ExecAuthPlugin(ABC):
|
|
29
|
+
"""Abstract Flower Auth Plugin class for ExecServicer.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
user_auth_config_path : Path
|
|
34
|
+
Path to the YAML file containing the authentication configuration.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
user_auth_config_path: Path,
|
|
41
|
+
verify_tls_cert: bool,
|
|
42
|
+
):
|
|
43
|
+
"""Abstract constructor."""
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def get_login_details(self) -> Optional[UserAuthLoginDetails]:
|
|
47
|
+
"""Get the login details."""
|
|
48
|
+
|
|
49
|
+
@abstractmethod
|
|
50
|
+
def validate_tokens_in_metadata(
|
|
51
|
+
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
|
52
|
+
) -> bool:
|
|
53
|
+
"""Validate authentication tokens in the provided metadata."""
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def get_auth_tokens(self, device_code: str) -> Optional[UserAuthCredentials]:
|
|
57
|
+
"""Get authentication tokens."""
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def refresh_tokens(
|
|
61
|
+
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
|
62
|
+
) -> Optional[Sequence[tuple[str, Union[str, bytes]]]]:
|
|
63
|
+
"""Refresh authentication tokens in the provided metadata."""
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class CliAuthPlugin(ABC):
|
|
67
|
+
"""Abstract Flower Auth Plugin class for CLI.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
credentials_path : Path
|
|
72
|
+
Path to the user's authentication credentials file.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
@abstractmethod
|
|
77
|
+
def login(
|
|
78
|
+
login_details: UserAuthLoginDetails,
|
|
79
|
+
exec_stub: ExecStub,
|
|
80
|
+
) -> UserAuthCredentials:
|
|
81
|
+
"""Authenticate the user and retrieve authentication credentials.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
login_details : UserAuthLoginDetails
|
|
86
|
+
An object containing the user's login details.
|
|
87
|
+
exec_stub : ExecStub
|
|
88
|
+
A stub for executing RPC calls to the server.
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
UserAuthCredentials
|
|
93
|
+
The authentication credentials obtained after login.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
@abstractmethod
|
|
97
|
+
def __init__(self, credentials_path: Path):
|
|
98
|
+
"""Abstract constructor."""
|
|
99
|
+
|
|
100
|
+
@abstractmethod
|
|
101
|
+
def store_tokens(self, credentials: UserAuthCredentials) -> None:
|
|
102
|
+
"""Store authentication tokens to the `credentials_path`.
|
|
103
|
+
|
|
104
|
+
The credentials, including tokens, will be saved as a JSON file
|
|
105
|
+
at `credentials_path`.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
@abstractmethod
|
|
109
|
+
def load_tokens(self) -> None:
|
|
110
|
+
"""Load authentication tokens from the `credentials_path`."""
|
|
111
|
+
|
|
112
|
+
@abstractmethod
|
|
113
|
+
def write_tokens_to_metadata(
|
|
114
|
+
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
|
115
|
+
) -> Sequence[tuple[str, Union[str, bytes]]]:
|
|
116
|
+
"""Write authentication tokens to the provided metadata."""
|
|
117
|
+
|
|
118
|
+
@abstractmethod
|
|
119
|
+
def read_tokens_from_metadata(
|
|
120
|
+
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
|
121
|
+
) -> Optional[UserAuthCredentials]:
|
|
122
|
+
"""Read authentication tokens from the provided metadata."""
|