Skip to content

Commit d8210ff

Browse files
Certificate Based Authentication (#133)
* Working CBA changes * working changes * Changes for CBA * remove cert password arg * refactor to new user args method * revert changes on create_connection * Revert pythonPath local change * Update SettingsFile.md for new setting * Additional spacing * tooltip update * add tests for client_certificate_path * forgot comma * escape slashes, forward slash to back slash * matching urls * Revisions/refactors * missing quote, revision * Option type the value parse Co-authored-by: landenblackmsft <[email protected]>
1 parent dd5b14c commit d8210ff

File tree

9 files changed

+35
-1
lines changed

9 files changed

+35
-1
lines changed

.vscode/launch.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
"name": "Python: All debug Options",
187187
"type": "python",
188188
"request": "launch",
189-
"pythonPath": "${command:python.interpreterPath}",
189+
"python": "${command:python.interpreterPath}",
190190
"program": "${file}",
191191
"module": "module.name",
192192
"env": {

docs/user-guide/SettingsFile.md

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ Checkers' Friendly Names:
2727
* PayloadBody
2828
* Examples
2929

30+
### client_certificate_path: str (default None)
31+
Path to your X.509 certificate file in PEM format.
32+
33+
If provided and valid, RESTler will attempt to use it during the SSL handshake.
34+
3035
### custom_bug_codes: list(str)
3136
List of status codes that will be flagged as bugs.
3237

restler/engine/transport_layer/messaging.py

+4
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ def __init__(self, connection_settings):
5353
context = ssl._create_unverified_context()
5454
else:
5555
context = ssl.create_default_context()
56+
if Settings().client_certificate_path:
57+
context.load_cert_chain(
58+
certfile=Settings().client_certificate_path
59+
)
5660
with socket.create_connection((target_ip, target_port or 443)) as sock:
5761
self._sock = context.wrap_socket(sock, server_hostname=host)
5862
else:

restler/restler.py

+4
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ def signal_handler(sig, frame):
246246
help='The cmd to execute in order to refresh the authentication token'
247247
' (default: None)',
248248
type=str, default=None, required=False)
249+
parser.add_argument('--client_certificate_path',
250+
help='Path to your X.509 certificate in PEM format. Provide for Certificate Based Authentication'
251+
' (default: None)',
252+
type=str, default=None, required=False)
249253
parser.add_argument('--producer_timing_delay',
250254
help='The time interval to wait after a resource-generating '
251255
'producer is executed (in seconds)'

restler/restler_settings.py

+6
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ def convert_wildcards_to_regex(str_value):
362362
self._checker_args.val = { checker_name.lower(): arg
363363
for checker_name, arg in self._checker_args.val.items() }
364364

365+
## Path to Client Cert for Certificate Based Authentication
366+
self._client_certificate_path = SettingsArg('client_certificate_path', str, None, user_args)
365367
## List of endpoints whose resource is to be created only once - Will be set with other per_resource settings
366368
self._create_once_endpoints = SettingsListArg('create_once', str, None, val_convert=str_to_hex_def)
367369
## List of status codes that will be flagged as bugs
@@ -458,6 +460,10 @@ def __deepcopy__(self, memo):
458460
""" Don't deepcopy this object, just return its reference """
459461
return self
460462

463+
@property
464+
def client_certificate_path(self):
465+
return self._client_certificate_path.val
466+
461467
@property
462468
def connection_settings(self):
463469
return self._connection_settings

restler/unit_tests/restler_user_settings.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"client_certificate_path": "\\path\\to\\file.pem",
23
"max_combinations": 20,
34
"max_request_execution_time": 90,
45
"global_producer_timing_delay": 2,

restler/unit_tests/test_restler_settings.py

+2
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ def test_valid_option_validation(self):
345345
'target_ip': '192.168.0.1',
346346
'token_refresh_cmd': 'some command',
347347
'token_refresh_interval': 30,
348+
'client_certificate_path': '\\path\\to\\file.pem',
348349
'fuzzing_mode': 'random-walk',
349350
'ignore_decoding_failures': True}
350351
try:
@@ -468,6 +469,7 @@ def test_settings_file_upload(self):
468469
self.assertEqual(True, hex_def(request1) in settings.create_once_endpoints)
469470
self.assertNotEqual(True, hex_def(request2) in settings.create_once_endpoints)
470471

472+
self.assertEqual("\\path\\to\\file.pem", settings.client_certificate_path)
471473
self.assertEqual(200, settings.dyn_objects_cache_size)
472474
self.assertEqual(2, settings.fuzzing_jobs)
473475
self.assertEqual('directed-smoke-test', settings.fuzzing_mode)

src/driver/Program.fs

+9
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ module Fuzz =
209209
sprintf "--custom_mutations \"%s\"" parameters.mutationsFilePath
210210
sprintf "--set_version %s" CurrentVersion
211211

212+
(match parameters.certFilePath with
213+
| None -> ""
214+
| Some cfPath -> sprintf "--client_certificate_path \"%s\"" cfPath
215+
)
212216
(match parameters.refreshableTokenOptions with
213217
| None -> ""
214218
| Some options ->
@@ -515,6 +519,11 @@ let rec parseEngineArgs task (args:EngineParameters) = function
515519
parseEngineArgs task { args with checkerOptions = args.checkerOptions @ [(checkerAction, specifiedCheckers |> String.concat " ")] } rest
516520
| "--no_results_analyzer"::rest ->
517521
parseEngineArgs task { args with runResultsAnalyzer = false } rest
522+
| "--client_certificate_path"::certFilePath::rest ->
523+
if not (File.Exists certFilePath) then
524+
Logging.logError <| sprintf "The Client Certificate Path %s does not exist." certFilePath
525+
usage()
526+
parseEngineArgs task { args with certFilePath = Some (Path.GetFullPath(certFilePath)) } rest
518527
| invalidArgument::rest ->
519528
Logging.logError <| sprintf "Invalid argument: %s" invalidArgument
520529
usage()

src/driver/Types.fs

+3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ type EngineParameters =
6565
/// Specifies whether to run results analyzer.
6666
runResultsAnalyzer : bool
6767

68+
/// File path to the client certificate.
69+
certFilePath : string option
6870
}
6971

7072
let DefaultEngineParameters =
@@ -83,6 +85,7 @@ let DefaultEngineParameters =
8385
pathRegex = None
8486
replayLogFilePath = None
8587
runResultsAnalyzer = true
88+
certFilePath = None
8689
}
8790

8891
/// Restler tasks that may be specified by the user

0 commit comments

Comments
 (0)