diff options
author | Sam Chudnick <sam@chudnick.com> | 2022-07-04 20:03:27 -0400 |
---|---|---|
committer | Sam Chudnick <sam@chudnick.com> | 2022-07-04 20:03:27 -0400 |
commit | 2e840e7c381f88425952c6fa9d68e0d433084a5a (patch) | |
tree | 31f7888ade33fbc112bd2b7509aac5c39bb2af82 /client | |
parent | 46564f357c175c7a01a36422307f05b543a83190 (diff) |
Support both TLS encrypted sessions and plaintext sessions
Added support for both TLS and plaintext connections. Server can accept
both types of connection simultaneously or in different combinations
(i.e encrypted client and plaintext PAM). Added options for specifying
dedicated TLS ports on server. Added --plain options for client and PAM
to force plaintext connections, default is to use encrypted connections.
Configuring encrypted client and PAM connections and plaintext server
connections allows for use of a reverse proxy setup with something like
nginx. This will avoid having to expose the MFA server directly in setups
that traverse the internet.
Diffstat (limited to 'client')
-rwxr-xr-x | client/client.py | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/client/client.py b/client/client.py index cc22d0b..0388073 100755 --- a/client/client.py +++ b/client/client.py | |||
@@ -26,6 +26,7 @@ def parse_arguments(): | |||
26 | parser.add_argument("--config",type=str,help="Path to config file",\ | 26 | parser.add_argument("--config",type=str,help="Path to config file",\ |
27 | default="/etc/mfa/mfa.conf") | 27 | default="/etc/mfa/mfa.conf") |
28 | parser.add_argument("--key",type=str,help="Client connection key") | 28 | parser.add_argument("--key",type=str,help="Client connection key") |
29 | parser.add_argument("--plain",action="store_true",help="Connect without TLS") | ||
29 | parser.add_argument("--insecure",action="store_true",\ | 30 | parser.add_argument("--insecure",action="store_true",\ |
30 | help="Accept invalid TLS certificates") | 31 | help="Accept invalid TLS certificates") |
31 | return parser.parse_args() | 32 | return parser.parse_args() |
@@ -37,7 +38,7 @@ def prompt_user(prompt): | |||
37 | return result | 38 | return result |
38 | 39 | ||
39 | 40 | ||
40 | def init_connection(mfa_server, client_port, client_key, insecure=False): | 41 | def init_connection_tls(mfa_server, client_port, client_key, insecure=False): |
41 | # Attempts to connect to MFA server with provided address,port, and key. | 42 | # Attempts to connect to MFA server with provided address,port, and key. |
42 | # Repeats attempt once a seconds until timeout is reached. | 43 | # Repeats attempt once a seconds until timeout is reached. |
43 | # Returns socket or None if unable to connect | 44 | # Returns socket or None if unable to connect |
@@ -70,6 +71,27 @@ def init_connection(mfa_server, client_port, client_key, insecure=False): | |||
70 | return connection | 71 | return connection |
71 | 72 | ||
72 | 73 | ||
74 | def init_connection(mfa_server, client_port, client_key): | ||
75 | connection = None | ||
76 | timeout = 0 | ||
77 | timeout_length = 5 | ||
78 | sleep_length = 1 | ||
79 | while connection == None and timeout < timeout_length: | ||
80 | try: | ||
81 | connection = socket.create_connection((mfa_server,client_port)) | ||
82 | connection.send(client_key.encode(FORMAT)) | ||
83 | response = connection.recv(ACK_LENGTH).decode(FORMAT) | ||
84 | if response == ACK_MESSAGE: | ||
85 | print("connected to mfa server") | ||
86 | elif response == DISCONNECT_MESSAGE: | ||
87 | print("server terminated connection") | ||
88 | sys.exit(1) | ||
89 | except ConnectionError: | ||
90 | time.sleep(sleep_length) | ||
91 | timeout += sleep_length | ||
92 | return connection | ||
93 | |||
94 | |||
73 | def read_config(config_file): | 95 | def read_config(config_file): |
74 | parser = configparser.ConfigParser(inline_comment_prefixes="#") | 96 | parser = configparser.ConfigParser(inline_comment_prefixes="#") |
75 | parser.read(config_file) | 97 | parser.read(config_file) |
@@ -84,6 +106,7 @@ def get_vars(args,confparser): | |||
84 | server = None | 106 | server = None |
85 | port = None | 107 | port = None |
86 | key = None | 108 | key = None |
109 | plain = None | ||
87 | insecure = None | 110 | insecure = None |
88 | 111 | ||
89 | # Set values from config file first | 112 | # Set values from config file first |
@@ -91,7 +114,13 @@ def get_vars(args,confparser): | |||
91 | server = confparser.get("client","server",fallback=None) | 114 | server = confparser.get("client","server",fallback=None) |
92 | port = confparser.get("client","port",fallback=None) | 115 | port = confparser.get("client","port",fallback=None) |
93 | key = confparser.get("client","key",fallback=None) | 116 | key = confparser.get("client","key",fallback=None) |
94 | insecure = bool(confparser.get("client","insecure",fallback=False)) | 117 | plain = confparser.get("client","plain",fallback=False) |
118 | insecure = confparser.get("client","insecure",fallback=False) | ||
119 | |||
120 | if plain.lower() == "false": | ||
121 | plain = False | ||
122 | if insecure.lower() == "false": | ||
123 | insecure = False | ||
95 | 124 | ||
96 | # Let command line args overwrite any values | 125 | # Let command line args overwrite any values |
97 | if args.server != None: | 126 | if args.server != None: |
@@ -100,6 +129,8 @@ def get_vars(args,confparser): | |||
100 | port = args.port | 129 | port = args.port |
101 | if args.key != None: | 130 | if args.key != None: |
102 | key = args.key | 131 | key = args.key |
132 | if args.plain: | ||
133 | plain = args.plain | ||
103 | if args.insecure: | 134 | if args.insecure: |
104 | insecure = args.insecure | 135 | insecure = args.insecure |
105 | 136 | ||
@@ -108,7 +139,7 @@ def get_vars(args,confparser): | |||
108 | print("error: one or more items unspecified") | 139 | print("error: one or more items unspecified") |
109 | sys.exit(1) | 140 | sys.exit(1) |
110 | 141 | ||
111 | return server,port,key,insecure | 142 | return server,port,key,plain,insecure |
112 | 143 | ||
113 | 144 | ||
114 | def main(): | 145 | def main(): |
@@ -116,7 +147,7 @@ def main(): | |||
116 | args = parse_arguments() | 147 | args = parse_arguments() |
117 | confparser = read_config(args.config) | 148 | confparser = read_config(args.config) |
118 | 149 | ||
119 | mfa_server,client_port,client_key,insecure = get_vars(args,confparser) | 150 | mfa_server,client_port,client_key,plain,insecure = get_vars(args,confparser) |
120 | 151 | ||
121 | # Exit if invalid key is provided | 152 | # Exit if invalid key is provided |
122 | if len(client_key) != KEY_LENGTH: | 153 | if len(client_key) != KEY_LENGTH: |
@@ -124,7 +155,10 @@ def main(): | |||
124 | sys.exit(1) | 155 | sys.exit(1) |
125 | 156 | ||
126 | # Open connection to server | 157 | # Open connection to server |
127 | conn = init_connection(mfa_server,client_port,client_key,insecure) | 158 | if plain: |
159 | conn = init_connection(mfa_server,client_port,client_key) | ||
160 | else: | ||
161 | conn = init_connection_tls(mfa_server,client_port,client_key,insecure) | ||
128 | if conn == None: | 162 | if conn == None: |
129 | print("timed out attempting to connect to server") | 163 | print("timed out attempting to connect to server") |
130 | sys.exit(1) | 164 | sys.exit(1) |