Skip to content

Commit 460bfe3

Browse files
authored
Merge pull request #295 from ligangty/radas-cfg
RADAS: add radas configurations
2 parents ae19c1b + 54aeae8 commit 460bfe3

File tree

3 files changed

+333
-0
lines changed

3 files changed

+333
-0
lines changed

charon/config.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,69 @@
2424
logger = logging.getLogger(__name__)
2525

2626

27+
class RadasConfig(object):
28+
def __init__(self, data: Dict):
29+
self.__umb_host: str = data.get("umb_host", None)
30+
self.__umb_host_port: str = data.get("umb_host_port", "5671")
31+
self.__result_queue: str = data.get("result_queue", None)
32+
self.__request_queue: str = data.get("request_queue", None)
33+
self.__client_ca: str = data.get("client_ca", None)
34+
self.__client_key: str = data.get("client_key", None)
35+
self.__client_key_pass_file: str = data.get("client_key_pass_file", None)
36+
self.__root_ca: str = data.get("root_ca", "/etc/pki/tls/certs/ca-bundle.crt")
37+
38+
def validate(self) -> bool:
39+
if not self.__umb_host:
40+
logger.error("Missing host name setting for UMB!")
41+
return False
42+
if not self.__result_queue:
43+
logger.error("Missing the queue setting to receive siging result in UMB!")
44+
return False
45+
if not self.__request_queue:
46+
logger.error("Missing the queue setting to send signing request in UMB!")
47+
return False
48+
if self.__client_ca and not os.access(self.__client_ca, os.R_OK):
49+
logger.error("The client CA file is not valid!")
50+
return False
51+
if self.__client_key and not os.access(self.__client_key, os.R_OK):
52+
logger.error("The client key file is not valid!")
53+
return False
54+
if self.__client_key_pass_file and not os.access(self.__client_key_pass_file, os.R_OK):
55+
logger.error("The client key password file is not valid!")
56+
return False
57+
if self.__root_ca and not os.access(self.__root_ca, os.R_OK):
58+
logger.error("The root ca file is not valid!")
59+
return False
60+
return True
61+
62+
def umb_target(self) -> str:
63+
return f'amqps://{self.__umb_host}:{self.__umb_host_port}'
64+
65+
def result_queue(self) -> str:
66+
return self.__result_queue
67+
68+
def request_queue(self) -> str:
69+
return self.__request_queue
70+
71+
def client_ca(self) -> str:
72+
return self.__client_ca
73+
74+
def client_key(self) -> str:
75+
return self.__client_key
76+
77+
def client_key_password(self) -> str:
78+
pass_file = self.__client_key_pass_file
79+
if os.access(pass_file, os.R_OK):
80+
with open(pass_file, 'r') as f:
81+
return f.read()
82+
elif pass_file:
83+
logger.warning("The key password file is not accessible. Will ignore the password.")
84+
return ""
85+
86+
def root_ca(self) -> str:
87+
return self.__root_ca
88+
89+
2790
class CharonConfig(object):
2891
"""CharonConfig is used to store all configurations for charon
2992
tools.
@@ -39,6 +102,9 @@ def __init__(self, data: Dict):
39102
self.__ignore_signature_suffix: Dict = data.get("ignore_signature_suffix", None)
40103
self.__signature_command: str = data.get("detach_signature_command", None)
41104
self.__aws_cf_enable: bool = data.get("aws_cf_enable", False)
105+
radas_config: Dict = data.get("radas", None)
106+
if radas_config:
107+
self.__radas_config__: RadasConfig = RadasConfig(radas_config)
42108

43109
def get_ignore_patterns(self) -> List[str]:
44110
return self.__ignore_patterns
@@ -67,6 +133,9 @@ def get_detach_signature_command(self) -> str:
67133
def is_aws_cf_enable(self) -> bool:
68134
return self.__aws_cf_enable
69135

136+
def get_radas_config(self) -> RadasConfig:
137+
return self.__radas_config__
138+
70139

71140
def get_config(cfgPath=None) -> CharonConfig:
72141
config_file_path = cfgPath

charon/schemas/charon.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,44 @@
3030
"type": "string",
3131
"description": "signature command to be used for signature"
3232
},
33+
"radas": {
34+
"type": "object",
35+
"descrition": "",
36+
"properties": {
37+
"umb_host": {
38+
"type": "string",
39+
"description": "The host of UMB"
40+
},
41+
"umb_host_port": {
42+
"type": "string",
43+
"description": "The port of UMB host"
44+
},
45+
"result_queue": {
46+
"type": "string",
47+
"description": "The queue in UMB to receive radas signing result"
48+
},
49+
"request_queue": {
50+
"type": "string",
51+
"description": "The queue in UMB to send signing request to RADAS"
52+
},
53+
"client_ca": {
54+
"type": "string",
55+
"description": "the client ca file path"
56+
},
57+
"client_key": {
58+
"type": "string",
59+
"description": "the client key file path"
60+
},
61+
"client_key_pass_file":{
62+
"type": "string",
63+
"description": "the file contains password of the client key"
64+
},
65+
"root_ca": {
66+
"type": "string",
67+
"description": "the root ca file path"
68+
}
69+
}
70+
},
3371
"targets": {
3472
"type": "object",
3573
"patternProperties": {

tests/test_config_radas.py

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
"""
2+
Copyright (C) 2022 Red Hat, Inc. (https://github.com/Commonjava/charon)
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
"""
16+
import unittest
17+
import os
18+
import charon.config as config
19+
import shutil
20+
import tempfile
21+
from tests.base import BaseTest
22+
from charon.utils.files import overwrite_file
23+
24+
25+
class RadasConfigTest(unittest.TestCase):
26+
def setUp(self) -> None:
27+
self.__base = BaseTest()
28+
self.__prepare_ca()
29+
30+
def tearDown(self) -> None:
31+
self.__base.tearDown()
32+
self.__clear_ca()
33+
34+
def test_full_radas_config(self):
35+
radas_settings = """
36+
radas:
37+
umb_host: test.umb.api.com
38+
result_queue: queue.result.test
39+
request_queue: queue.request.test
40+
client_ca: {}
41+
client_key: {}
42+
client_key_pass_file: {}
43+
root_ca: {}
44+
45+
targets:
46+
ga:
47+
- bucket: charon-test
48+
""".format(self.__client_ca_path, self.__client_key_path,
49+
self.__client_key_pass_file, self.__root_ca)
50+
print(radas_settings)
51+
self.__change_config_content(radas_settings)
52+
conf = config.get_config()
53+
self.assertIsNotNone(conf)
54+
rconf = conf.get_radas_config()
55+
self.assertIsNotNone(rconf)
56+
self.assertTrue(rconf.validate())
57+
58+
def test_missing_umb_host(self):
59+
radas_settings = """
60+
radas:
61+
result_queue: queue.result.test
62+
request_queue: queue.request.test
63+
client_ca: {}
64+
client_key: {}
65+
client_key_pass_file: {}
66+
67+
targets:
68+
ga:
69+
- bucket: charon-test
70+
""".format(self.__client_ca_path, self.__client_key_path, self.__client_key_pass_file)
71+
self.__change_config_content(radas_settings)
72+
conf = config.get_config()
73+
self.assertIsNotNone(conf)
74+
rconf = conf.get_radas_config()
75+
self.assertIsNotNone(rconf)
76+
self.assertFalse(rconf.validate())
77+
78+
def test_missing_result_queue(self):
79+
radas_settings = """
80+
radas:
81+
umb_host: test.umb.api.com
82+
request_queue: queue.request.test
83+
client_ca: {}
84+
client_key: {}
85+
client_key_pass_file: {}
86+
87+
targets:
88+
ga:
89+
- bucket: charon-test
90+
""".format(self.__client_ca_path, self.__client_key_path, self.__client_key_pass_file)
91+
self.__change_config_content(radas_settings)
92+
conf = config.get_config()
93+
self.assertIsNotNone(conf)
94+
rconf = conf.get_radas_config()
95+
self.assertIsNotNone(rconf)
96+
self.assertFalse(rconf.validate())
97+
98+
def test_missing_request_queue(self):
99+
radas_settings = """
100+
radas:
101+
umb_host: test.umb.api.com
102+
result_queue: queue.result.test
103+
client_ca: {}
104+
client_key: {}
105+
client_key_pass_file: {}
106+
107+
targets:
108+
ga:
109+
- bucket: charon-test
110+
""".format(self.__client_ca_path, self.__client_key_path, self.__client_key_pass_file)
111+
self.__change_config_content(radas_settings)
112+
conf = config.get_config()
113+
self.assertIsNotNone(conf)
114+
rconf = conf.get_radas_config()
115+
self.assertIsNotNone(rconf)
116+
self.assertFalse(rconf.validate())
117+
118+
def test_unaccessible_client_ca(self):
119+
radas_settings = """
120+
radas:
121+
umb_host: test.umb.api.com
122+
result_queue: queue.result.test
123+
request_queue: queue.request.test
124+
client_ca: {}
125+
client_key: {}
126+
client_key_pass_file: {}
127+
128+
targets:
129+
ga:
130+
- bucket: charon-test
131+
""".format(self.__client_ca_path, self.__client_key_path, self.__client_key_pass_file)
132+
os.remove(self.__client_ca_path)
133+
self.__change_config_content(radas_settings)
134+
conf = config.get_config()
135+
self.assertIsNotNone(conf)
136+
rconf = conf.get_radas_config()
137+
self.assertIsNotNone(rconf)
138+
self.assertFalse(rconf.validate())
139+
140+
def test_unaccessible_client_key(self):
141+
radas_settings = """
142+
radas:
143+
umb_host: test.umb.api.com
144+
result_queue: queue.result.test
145+
request_queue: queue.request.test
146+
client_ca: {}
147+
client_key: {}
148+
client_key_pass_file: {}
149+
150+
targets:
151+
ga:
152+
- bucket: charon-test
153+
""".format(self.__client_ca_path, self.__client_key_path, self.__client_key_pass_file)
154+
os.remove(self.__client_key_path)
155+
self.__change_config_content(radas_settings)
156+
conf = config.get_config()
157+
self.assertIsNotNone(conf)
158+
rconf = conf.get_radas_config()
159+
self.assertIsNotNone(rconf)
160+
self.assertFalse(rconf.validate())
161+
162+
def test_unaccessible_client_password_file(self):
163+
radas_settings = """
164+
radas:
165+
umb_host: test.umb.api.com
166+
result_queue: queue.result.test
167+
request_queue: queue.request.test
168+
client_ca: {}
169+
client_key: {}
170+
client_key_pass_file: {}
171+
172+
targets:
173+
ga:
174+
- bucket: charon-test
175+
""".format(self.__client_ca_path, self.__client_key_path, self.__client_key_pass_file)
176+
os.remove(self.__client_key_pass_file)
177+
self.__change_config_content(radas_settings)
178+
conf = config.get_config()
179+
self.assertIsNotNone(conf)
180+
rconf = conf.get_radas_config()
181+
self.assertIsNotNone(rconf)
182+
self.assertFalse(rconf.validate())
183+
184+
def test_unaccessible_root_ca(self):
185+
radas_settings = """
186+
radas:
187+
umb_host: test.umb.api.com
188+
result_queue: queue.result.test
189+
request_queue: queue.request.test
190+
client_ca: {}
191+
client_key: {}
192+
client_key_pass_file: {}
193+
root_ca: {}
194+
195+
targets:
196+
ga:
197+
- bucket: charon-test
198+
""".format(self.__client_ca_path, self.__client_key_path,
199+
self.__client_key_pass_file, self.__root_ca)
200+
os.remove(self.__root_ca)
201+
self.__change_config_content(radas_settings)
202+
conf = config.get_config()
203+
self.assertIsNotNone(conf)
204+
rconf = conf.get_radas_config()
205+
self.assertIsNotNone(rconf)
206+
self.assertFalse(rconf.validate())
207+
208+
def __change_config_content(self, content: str):
209+
self.__base.change_home()
210+
config_base = self.__base.get_config_base()
211+
os.mkdir(config_base)
212+
self.__base.prepare_config(config_base, content)
213+
214+
def __prepare_ca(self):
215+
self.__tempdir = tempfile.mkdtemp()
216+
self.__client_ca_path = os.path.join(self.__tempdir, "client_ca.crt")
217+
self.__client_key_path = os.path.join(self.__tempdir, "client_key.crt")
218+
self.__client_key_pass_file = os.path.join(self.__tempdir, "client_key_password.txt")
219+
self.__root_ca = os.path.join(self.__tempdir, "root_ca.crt")
220+
overwrite_file(self.__client_ca_path, "client ca")
221+
overwrite_file(self.__client_key_path, "client key")
222+
overwrite_file(self.__client_key_pass_file, "it's password")
223+
overwrite_file(self.__root_ca, "root ca")
224+
225+
def __clear_ca(self):
226+
shutil.rmtree(self.__tempdir)

0 commit comments

Comments
 (0)