mantis_api_client 5.5.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.
- mantis_api_client/__init__.py +21 -0
- mantis_api_client/cli_parser/account_parser.py +451 -0
- mantis_api_client/cli_parser/attack_parser.py +317 -0
- mantis_api_client/cli_parser/bas_parser.py +1204 -0
- mantis_api_client/cli_parser/basebox_parser.py +258 -0
- mantis_api_client/cli_parser/dataset_parser.py +200 -0
- mantis_api_client/cli_parser/lab_parser.py +805 -0
- mantis_api_client/cli_parser/labs_parser.py +87 -0
- mantis_api_client/cli_parser/log_collector_parser.py +71 -0
- mantis_api_client/cli_parser/redteam_parser.py +375 -0
- mantis_api_client/cli_parser/scenario_parser.py +311 -0
- mantis_api_client/cli_parser/signature_parser.py +147 -0
- mantis_api_client/cli_parser/topology_parser.py +255 -0
- mantis_api_client/cli_parser/user_parser.py +225 -0
- mantis_api_client/config.py +73 -0
- mantis_api_client/dataset_api.py +267 -0
- mantis_api_client/exceptions.py +27 -0
- mantis_api_client/mantis.py +186 -0
- mantis_api_client/oidc.py +302 -0
- mantis_api_client/scenario_api.py +1196 -0
- mantis_api_client/user_api.py +282 -0
- mantis_api_client/utils.py +130 -0
- mantis_api_client-5.5.0.dist-info/AUTHORS +1 -0
- mantis_api_client-5.5.0.dist-info/LICENSE +19 -0
- mantis_api_client-5.5.0.dist-info/METADATA +33 -0
- mantis_api_client-5.5.0.dist-info/RECORD +28 -0
- mantis_api_client-5.5.0.dist-info/WHEEL +4 -0
- mantis_api_client-5.5.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2016-2021 AMOSSYS
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
# copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
# SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
import argparse
|
|
25
|
+
import sys
|
|
26
|
+
from typing import List
|
|
27
|
+
|
|
28
|
+
import argcomplete
|
|
29
|
+
from omegaconf import OmegaConf
|
|
30
|
+
from rich_argparse import RichHelpFormatter
|
|
31
|
+
|
|
32
|
+
from mantis_api_client.cli_parser.account_parser import add_account_parser
|
|
33
|
+
from mantis_api_client.cli_parser.attack_parser import add_attack_parser
|
|
34
|
+
from mantis_api_client.cli_parser.basebox_parser import add_basebox_parser
|
|
35
|
+
from mantis_api_client.cli_parser.dataset_parser import add_dataset_parser
|
|
36
|
+
from mantis_api_client.cli_parser.lab_parser import add_lab_parser
|
|
37
|
+
from mantis_api_client.cli_parser.labs_parser import add_labs_parser
|
|
38
|
+
from mantis_api_client.cli_parser.log_collector_parser import add_log_collector_parser
|
|
39
|
+
from mantis_api_client.cli_parser.scenario_parser import add_scenario_parser
|
|
40
|
+
from mantis_api_client.cli_parser.signature_parser import add_signature_parser
|
|
41
|
+
from mantis_api_client.cli_parser.topology_parser import add_topology_parser
|
|
42
|
+
from mantis_api_client.cli_parser.user_parser import add_user_parser
|
|
43
|
+
from mantis_api_client.cli_parser.bas_parser import add_bas_parser
|
|
44
|
+
from mantis_api_client.config import mantis_api_client_config
|
|
45
|
+
from mantis_api_client.oidc import initialize_oidc_client
|
|
46
|
+
from mantis_api_client.utils import colored
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def create_mantis_cli_parser() -> argparse.ArgumentParser:
|
|
50
|
+
parser = argparse.ArgumentParser(formatter_class=RichHelpFormatter)
|
|
51
|
+
|
|
52
|
+
# Config file argument
|
|
53
|
+
parser.add_argument("--config", help="Configuration file")
|
|
54
|
+
|
|
55
|
+
# Common debug argument
|
|
56
|
+
parser.add_argument(
|
|
57
|
+
"-d",
|
|
58
|
+
"--debug",
|
|
59
|
+
action="store_true",
|
|
60
|
+
dest="debug_mode",
|
|
61
|
+
help="Activate debug mode (default: %(default)s)",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
subparsers = parser.add_subparsers()
|
|
65
|
+
|
|
66
|
+
# --------------------
|
|
67
|
+
# --- Scenario API options (bas)
|
|
68
|
+
# --------------------
|
|
69
|
+
|
|
70
|
+
add_bas_parser(root_parser=parser, subparsers=subparsers)
|
|
71
|
+
|
|
72
|
+
# --------------------
|
|
73
|
+
# --- Scenario API options (attack)
|
|
74
|
+
# --------------------
|
|
75
|
+
|
|
76
|
+
add_attack_parser(root_parser=parser, subparsers=subparsers)
|
|
77
|
+
|
|
78
|
+
# --------------------
|
|
79
|
+
# --- Scenario API options (basebox)
|
|
80
|
+
# --------------------
|
|
81
|
+
|
|
82
|
+
add_basebox_parser(root_parser=parser, subparsers=subparsers)
|
|
83
|
+
|
|
84
|
+
# --------------------
|
|
85
|
+
# --- Scenario API options (dataset)
|
|
86
|
+
# --------------------
|
|
87
|
+
|
|
88
|
+
add_dataset_parser(root_parser=parser, subparsers=subparsers)
|
|
89
|
+
|
|
90
|
+
# --------------------
|
|
91
|
+
# --- Scenario API options (scenario)
|
|
92
|
+
# --------------------
|
|
93
|
+
|
|
94
|
+
add_scenario_parser(root_parser=parser, subparsers=subparsers)
|
|
95
|
+
|
|
96
|
+
# --------------------
|
|
97
|
+
# --- Scenario API options (topology)
|
|
98
|
+
# --------------------
|
|
99
|
+
|
|
100
|
+
add_topology_parser(root_parser=parser, subparsers=subparsers)
|
|
101
|
+
|
|
102
|
+
# --------------------
|
|
103
|
+
# --- Scenario API options (log_collector)
|
|
104
|
+
# --------------------
|
|
105
|
+
|
|
106
|
+
add_log_collector_parser(root_parser=parser, subparsers=subparsers)
|
|
107
|
+
|
|
108
|
+
# --------------------
|
|
109
|
+
# --- Scenario API options (signature)
|
|
110
|
+
# --------------------
|
|
111
|
+
|
|
112
|
+
add_signature_parser(root_parser=parser, subparsers=subparsers)
|
|
113
|
+
|
|
114
|
+
# --------------------
|
|
115
|
+
# --- User API options
|
|
116
|
+
# --------------------
|
|
117
|
+
|
|
118
|
+
add_user_parser(root_parser=parser, subparsers=subparsers)
|
|
119
|
+
|
|
120
|
+
# -------------------
|
|
121
|
+
# --- Labs subparser
|
|
122
|
+
# -------------------
|
|
123
|
+
|
|
124
|
+
add_labs_parser(root_parser=parser, subparsers=subparsers)
|
|
125
|
+
|
|
126
|
+
# -------------------
|
|
127
|
+
# --- Lab subparser
|
|
128
|
+
# -------------------
|
|
129
|
+
|
|
130
|
+
add_lab_parser(root_parser=parser, subparsers=subparsers)
|
|
131
|
+
|
|
132
|
+
# -------------------
|
|
133
|
+
# --- login options
|
|
134
|
+
# -------------------
|
|
135
|
+
|
|
136
|
+
add_account_parser(root_parser=parser, subparsers=subparsers)
|
|
137
|
+
|
|
138
|
+
return parser
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def handle_command_line(command_line_args: List[str]) -> None:
|
|
142
|
+
try:
|
|
143
|
+
initialize_oidc_client()
|
|
144
|
+
except Exception as e:
|
|
145
|
+
print(colored(str(e), "white", "on_red"))
|
|
146
|
+
sys.exit(1)
|
|
147
|
+
|
|
148
|
+
parser = create_mantis_cli_parser()
|
|
149
|
+
|
|
150
|
+
argcomplete.autocomplete(parser)
|
|
151
|
+
|
|
152
|
+
parser_defaults = {
|
|
153
|
+
k: mantis_api_client_config[k]
|
|
154
|
+
for k in mantis_api_client_config
|
|
155
|
+
if not OmegaConf.is_missing(mantis_api_client_config, k)
|
|
156
|
+
}
|
|
157
|
+
parser.set_defaults(
|
|
158
|
+
func=lambda _: parser.print_help(), **parser_defaults
|
|
159
|
+
) # all arguments must be set at same time
|
|
160
|
+
|
|
161
|
+
args, left_argv = parser.parse_known_args(command_line_args)
|
|
162
|
+
|
|
163
|
+
# Parse remaining args from command line (overriding potential config file
|
|
164
|
+
# parameters)
|
|
165
|
+
args = parser.parse_args(left_argv, args)
|
|
166
|
+
|
|
167
|
+
# If in a 'lab' namespace, we set specific environment variables
|
|
168
|
+
# to allow remote access to the running lab
|
|
169
|
+
if hasattr(args, "set_lab"):
|
|
170
|
+
args.set_lab(args)
|
|
171
|
+
|
|
172
|
+
args.func(args)
|
|
173
|
+
|
|
174
|
+
if hasattr(args, "set_lab"):
|
|
175
|
+
args.unset_lab(args)
|
|
176
|
+
|
|
177
|
+
sys.exit(0)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def main() -> None:
|
|
181
|
+
command_line_args = sys.argv[1:]
|
|
182
|
+
handle_command_line(command_line_args)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
if __name__ == "__main__":
|
|
186
|
+
main()
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2016-2021 AMOSSYS
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
# copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
# SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
import json
|
|
25
|
+
import sys
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
from typing import Any
|
|
28
|
+
from typing import Callable
|
|
29
|
+
from typing import Dict
|
|
30
|
+
from typing import Optional
|
|
31
|
+
from typing import TypeVar
|
|
32
|
+
from typing import Union
|
|
33
|
+
|
|
34
|
+
from mantis_authz import MantisOpenID
|
|
35
|
+
from mantis_authz.config import authz_config
|
|
36
|
+
from pydantic import BaseModel
|
|
37
|
+
from pydantic import Field
|
|
38
|
+
from pydantic import ValidationError
|
|
39
|
+
from rich.prompt import Confirm
|
|
40
|
+
from ruamel.yaml import YAML
|
|
41
|
+
|
|
42
|
+
from mantis_api_client.config import mantis_api_client_config
|
|
43
|
+
|
|
44
|
+
RT = TypeVar("RT")
|
|
45
|
+
|
|
46
|
+
oidc_client = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ConfigurationError(ValueError):
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Profile(BaseModel):
|
|
54
|
+
domain: str
|
|
55
|
+
refresh_token: str
|
|
56
|
+
default_workspace: Optional[str] = None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class Session(BaseModel):
|
|
60
|
+
active_profile: Optional[str] = None
|
|
61
|
+
profiles: Dict[str, Profile] = Field(default_factory=dict)
|
|
62
|
+
|
|
63
|
+
def get_active_profile(self, raise_exc: bool = True) -> Optional[Profile]:
|
|
64
|
+
if self.active_profile is None:
|
|
65
|
+
if raise_exc:
|
|
66
|
+
raise ConfigurationError(
|
|
67
|
+
"Not authenticated, you need to execute 'mantis account login"
|
|
68
|
+
)
|
|
69
|
+
return None
|
|
70
|
+
return self.profiles[self.active_profile]
|
|
71
|
+
|
|
72
|
+
def set_active_profile(self, name: str) -> None:
|
|
73
|
+
if name not in self.profiles:
|
|
74
|
+
raise ValueError(f"Unknown profile '{name}'")
|
|
75
|
+
self.active_profile = name
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class ConfigFileManager:
|
|
79
|
+
def __init__(self, path: Union[str, Path]) -> None:
|
|
80
|
+
if isinstance(path, str):
|
|
81
|
+
path = Path(path)
|
|
82
|
+
if path.suffix in (".yaml", ".yml"):
|
|
83
|
+
klass = YAML()
|
|
84
|
+
loader = klass.load
|
|
85
|
+
dumper = klass.dump
|
|
86
|
+
# elif path.suffix == ".json":
|
|
87
|
+
# loader = json.load
|
|
88
|
+
# dumper = json.dump
|
|
89
|
+
else:
|
|
90
|
+
raise ValueError(f"Unknown file suffix '{path.suffix}'")
|
|
91
|
+
self.loader = loader
|
|
92
|
+
self.dumper = dumper
|
|
93
|
+
self.path = path
|
|
94
|
+
|
|
95
|
+
def load(self) -> Dict:
|
|
96
|
+
return self.loader(self.path) or {}
|
|
97
|
+
|
|
98
|
+
def dump(self, obj) -> None:
|
|
99
|
+
self.dumper(obj, self.path)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class OIDCClient:
|
|
103
|
+
"""
|
|
104
|
+
Provide a wrapper arround OIDC client providing token refreshing for API
|
|
105
|
+
calls.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
def __init__(self) -> None:
|
|
109
|
+
try:
|
|
110
|
+
self._session = self._parse_session_from_config()
|
|
111
|
+
except FileNotFoundError:
|
|
112
|
+
self._session = Session()
|
|
113
|
+
self.set_context()
|
|
114
|
+
self._oidc: Optional[MantisOpenID] = self._get_oidc()
|
|
115
|
+
self._access_token: Optional[str] = None
|
|
116
|
+
|
|
117
|
+
def get_active_profile_domain(self, **kwargs) -> Optional[str]:
|
|
118
|
+
active_profile = self._session.get_active_profile(**kwargs)
|
|
119
|
+
if active_profile is None:
|
|
120
|
+
return None
|
|
121
|
+
return active_profile.domain
|
|
122
|
+
|
|
123
|
+
def get_default_workspace(self, **kwargs) -> Optional[str]:
|
|
124
|
+
active_profile = self._session.get_active_profile(**kwargs)
|
|
125
|
+
if active_profile is None:
|
|
126
|
+
return None
|
|
127
|
+
return active_profile.default_workspace
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def _parse_session_from_config() -> Session:
|
|
131
|
+
obj = ConfigFileManager(mantis_api_client_config.config_file).load()
|
|
132
|
+
try:
|
|
133
|
+
session = Session(
|
|
134
|
+
active_profile=obj.get("active_profile"),
|
|
135
|
+
profiles=obj.get("profiles", {}),
|
|
136
|
+
)
|
|
137
|
+
except ValidationError:
|
|
138
|
+
exit("Configuration format is incorrect.\nRun `mantis init` again")
|
|
139
|
+
if (
|
|
140
|
+
session.active_profile is not None
|
|
141
|
+
and session.active_profile not in session.profiles
|
|
142
|
+
):
|
|
143
|
+
raise ConfigurationError(
|
|
144
|
+
"Unknown default profile '{}'".format(obj["active_profile"])
|
|
145
|
+
)
|
|
146
|
+
return session
|
|
147
|
+
|
|
148
|
+
def _store_session_to_config(self) -> None:
|
|
149
|
+
cfgmgr = ConfigFileManager(mantis_api_client_config.config_file)
|
|
150
|
+
cfgmgr.dump(self._session.dict())
|
|
151
|
+
|
|
152
|
+
def _get_oidc(self, domain: Optional[str] = None) -> Optional[MantisOpenID]:
|
|
153
|
+
mantis_api_client_config.config_file.touch(exist_ok=True)
|
|
154
|
+
|
|
155
|
+
if domain is None:
|
|
156
|
+
# return early when no session is available
|
|
157
|
+
if self._session.active_profile is None:
|
|
158
|
+
return None
|
|
159
|
+
active_profile = self._session.get_active_profile()
|
|
160
|
+
assert active_profile is not None
|
|
161
|
+
domain = active_profile.domain
|
|
162
|
+
else:
|
|
163
|
+
self.set_context(profile=domain)
|
|
164
|
+
return MantisOpenID(
|
|
165
|
+
server_url=mantis_api_client_config.oidc.server_url,
|
|
166
|
+
realm_name=mantis_api_client_config.oidc.realm,
|
|
167
|
+
client_id=mantis_api_client_config.oidc.client_id,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def set_context(self, profile: Optional[str] = None) -> None:
|
|
171
|
+
if profile is None:
|
|
172
|
+
profile = self._session.active_profile
|
|
173
|
+
if profile is None: # Production configuration
|
|
174
|
+
profile = "mantis-platform.io"
|
|
175
|
+
if profile:
|
|
176
|
+
# prod mode
|
|
177
|
+
mantis_domain = profile
|
|
178
|
+
app_base_url = f"https://app.{mantis_domain}"
|
|
179
|
+
id_base_url = f"https://id.{mantis_domain}"
|
|
180
|
+
mantis_api_client_config.update(
|
|
181
|
+
{
|
|
182
|
+
"dataset_api_url": f"{app_base_url}/api/dataset",
|
|
183
|
+
"dataset_web_url": f"{app_base_url}/datasets/resources",
|
|
184
|
+
"scenario_api_url": f"{app_base_url}/api/scenario",
|
|
185
|
+
"user_api_url": f"{app_base_url}/api/backoffice",
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
mantis_api_client_config.oidc.server_url = id_base_url
|
|
189
|
+
del app_base_url, id_base_url
|
|
190
|
+
authz_config.use_permissions = True
|
|
191
|
+
|
|
192
|
+
def configure_profile(
|
|
193
|
+
self,
|
|
194
|
+
domain: Optional[str] = None,
|
|
195
|
+
token: Optional[str] = None,
|
|
196
|
+
workspace_id: Optional[str] = None,
|
|
197
|
+
) -> None:
|
|
198
|
+
profile_name = domain
|
|
199
|
+
if profile_name is None:
|
|
200
|
+
# remove profile
|
|
201
|
+
if self._session.active_profile is not None:
|
|
202
|
+
self._session.profiles.pop(self._session.active_profile, None)
|
|
203
|
+
else:
|
|
204
|
+
assert domain is not None and token is not None
|
|
205
|
+
profile = Profile(
|
|
206
|
+
domain=domain,
|
|
207
|
+
refresh_token=token,
|
|
208
|
+
default_workspace=workspace_id,
|
|
209
|
+
)
|
|
210
|
+
self._session.profiles[profile_name] = profile
|
|
211
|
+
self._oidc = self._get_oidc(domain)
|
|
212
|
+
self._session.active_profile = profile_name
|
|
213
|
+
self.set_context(profile_name)
|
|
214
|
+
self._store_session_to_config()
|
|
215
|
+
|
|
216
|
+
def get_active_tokens(self) -> Dict:
|
|
217
|
+
active_profile = self._session.get_active_profile()
|
|
218
|
+
assert active_profile is not None and self._oidc is not None
|
|
219
|
+
return self._oidc.refresh_token(active_profile.refresh_token)
|
|
220
|
+
|
|
221
|
+
def token(self, domain: str, *args, **kwargs):
|
|
222
|
+
oidc = self._get_oidc(domain)
|
|
223
|
+
assert oidc is not None
|
|
224
|
+
return oidc.token(*args, **kwargs)
|
|
225
|
+
|
|
226
|
+
def auth_url(self, domain: str, *args, **kwargs):
|
|
227
|
+
oidc = self._get_oidc(domain)
|
|
228
|
+
assert oidc is not None
|
|
229
|
+
return oidc.auth_url(*args, **kwargs)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def authorize(func: Callable[..., RT]) -> Callable[..., RT]:
|
|
233
|
+
def authorize_wrapper(route: str, **kwargs: Any) -> Any:
|
|
234
|
+
tokens = get_oidc_client().get_active_tokens()
|
|
235
|
+
access_token = tokens["access_token"]
|
|
236
|
+
kwargs.setdefault("headers", {}).update(
|
|
237
|
+
{"Authorization": f"Bearer {access_token}"}
|
|
238
|
+
)
|
|
239
|
+
return func(route, **kwargs)
|
|
240
|
+
|
|
241
|
+
if authz_config.use_permissions:
|
|
242
|
+
return authorize_wrapper
|
|
243
|
+
return func
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _migrate_legacy_session_file() -> None:
|
|
247
|
+
config_file = mantis_api_client_config.config_file
|
|
248
|
+
legacy_config_file = config_file.parent / "session.json"
|
|
249
|
+
if legacy_config_file.exists() and not config_file.exists():
|
|
250
|
+
print(f"Legacy configuration file found at `{legacy_config_file}`")
|
|
251
|
+
confirm = Confirm.ask("Do you want to convert it automatically ?", default=True)
|
|
252
|
+
if confirm:
|
|
253
|
+
try:
|
|
254
|
+
with legacy_config_file.open() as f:
|
|
255
|
+
legacy_config = json.load(f)
|
|
256
|
+
with config_file.open("w") as f:
|
|
257
|
+
YAML().dump(_convert_legacy_config_file(legacy_config), f)
|
|
258
|
+
legacy_config_file.unlink()
|
|
259
|
+
except Exception:
|
|
260
|
+
if Confirm.ask(
|
|
261
|
+
"Migration failed. You should remove the configuration file. Proceed ?",
|
|
262
|
+
default=True,
|
|
263
|
+
):
|
|
264
|
+
legacy_config_file.unlink()
|
|
265
|
+
else:
|
|
266
|
+
print(f"Migration completed. New configuration file is `{config_file}`")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _convert_legacy_config_file(legacy_config: Dict) -> Dict:
|
|
270
|
+
return {
|
|
271
|
+
"active_profile": legacy_config.pop("active_profile")[11:],
|
|
272
|
+
"profiles": {
|
|
273
|
+
domain[11:]: {"domain": domain[11:], **conf}
|
|
274
|
+
for domain, conf in legacy_config.items()
|
|
275
|
+
},
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def initialize_oidc_client() -> None:
|
|
280
|
+
global oidc_client
|
|
281
|
+
mantis_api_client_config.config_file.parent.mkdir(parents=True, exist_ok=True)
|
|
282
|
+
_migrate_legacy_session_file()
|
|
283
|
+
oidc_client = OIDCClient()
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def get_oidc_client() -> OIDCClient:
|
|
287
|
+
if oidc_client is None:
|
|
288
|
+
try:
|
|
289
|
+
initialize_oidc_client()
|
|
290
|
+
except Exception as e:
|
|
291
|
+
from mantis_api_client.utils import colored
|
|
292
|
+
|
|
293
|
+
print(colored(str(e), "white", "on_red"))
|
|
294
|
+
sys.exit(1)
|
|
295
|
+
|
|
296
|
+
assert oidc_client is not None
|
|
297
|
+
return oidc_client
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
# Call OIDCClient initialization once here, to prevent some internal initialization issues
|
|
301
|
+
# like authz_config.use_permissions not being set properly
|
|
302
|
+
get_oidc_client()
|