summaryrefslogtreecommitdiff
path: root/pam
diff options
context:
space:
mode:
authorSam Chudnick <sam@chudnick.com>2022-07-04 20:03:27 -0400
committerSam Chudnick <sam@chudnick.com>2022-07-04 20:03:27 -0400
commit2e840e7c381f88425952c6fa9d68e0d433084a5a (patch)
tree31f7888ade33fbc112bd2b7509aac5c39bb2af82 /pam
parent46564f357c175c7a01a36422307f05b543a83190 (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 'pam')
-rwxr-xr-xpam/pam_mfa.py46
1 files changed, 37 insertions, 9 deletions
diff --git a/pam/pam_mfa.py b/pam/pam_mfa.py
index 5a5a112..a5105a2 100755
--- a/pam/pam_mfa.py
+++ b/pam/pam_mfa.py
@@ -34,11 +34,12 @@ def parse_arguments():
34 default="/etc/mfa/mfa.conf") 34 default="/etc/mfa/mfa.conf")
35 parser.add_argument("--server",type=str,help="MFA server address") 35 parser.add_argument("--server",type=str,help="MFA server address")
36 parser.add_argument("--port",type=str,help="MFA server PAM connection port") 36 parser.add_argument("--port",type=str,help="MFA server PAM connection port")
37 parser.add_argument("--plain",action="store_true",help="Connect without TLS")
37 parser.add_argument("--insecure",action="store_true", 38 parser.add_argument("--insecure",action="store_true",
38 help="Accept invalid TLS certificates") 39 help="Accept invalid TLS certificates")
39 return parser.parse_args() 40 return parser.parse_args()
40 41
41def init_connection(mfa_server, pam_port, insecure): 42def init_connection_tls(mfa_server, pam_port, insecure):
42 # Attempts to connect to MFA server with provided address and port 43 # Attempts to connect to MFA server with provided address and port
43 # Repeats connection attempts once per second until timeout is reached 44 # Repeats connection attempts once per second until timeout is reached
44 # Returns the socket if connection was successful or None otherwise 45 # Returns the socket if connection was successful or None otherwise
@@ -52,7 +53,6 @@ def init_connection(mfa_server, pam_port, insecure):
52 context.verify_mode = 0 53 context.verify_mode = 0
53 while connection == None and timeout < timeout_length: 54 while connection == None and timeout < timeout_length:
54 try: 55 try:
55 #connection = socket.create_connection((mfa_server,client_port))
56 connection = context.wrap_socket(socket.socket(socket.AF_INET), 56 connection = context.wrap_socket(socket.socket(socket.AF_INET),
57 server_hostname=mfa_server) 57 server_hostname=mfa_server)
58 connection.connect((mfa_server,int(pam_port))) 58 connection.connect((mfa_server,int(pam_port)))
@@ -65,6 +65,24 @@ def init_connection(mfa_server, pam_port, insecure):
65 return None 65 return None
66 66
67 67
68def init_connection(mfa_server, pam_port):
69 # Attempts to connect to MFA server with provided address and port
70 # Repeats connection attempts once per second until timeout is reached
71 # Returns the socket if connection was successful or None otherwise
72 connection = None
73 timeout = 0
74 timeout_length = 5
75 sleep_length = 1
76 while connection == None and timeout < timeout_length:
77 try:
78 connection = socket.create_connection((mfa_server,pam_port))
79 return connection
80 except (ConnectionError,ConnectionRefusedError):
81 time.sleep(sleep_length)
82 timeout += sleep_length
83 return None
84
85
68def read_config(config_file): 86def read_config(config_file):
69 # Read config file for server and port info 87 # Read config file for server and port info
70 # Return tuple (server,port) 88 # Return tuple (server,port)
@@ -94,19 +112,28 @@ def get_vars(args,confparser):
94 112
95 server = None 113 server = None
96 port = None 114 port = None
115 plain = None
97 insecure = None 116 insecure = None
98 117
99 # Set values from config file first 118 # Set values from config file first
100 if confparser.has_section("pam"): 119 if confparser.has_section("pam"):
101 server = confparser.get("pam","server",fallback=None) 120 server = confparser.get("pam","server",fallback=None)
102 port = confparser.get("pam","port",fallback=None) 121 port = confparser.get("pam","port",fallback=None)
103 insecure = bool(confparser.get("pam","insecure",fallback=False)) 122 plain = confparser.get("client","plain",fallback=False)
123 insecure = confparser.get("client","insecure",fallback=False)
104 124
125 if plain.lower() == "false":
126 plain = False
127 if insecure.lower() == "false":
128 insecure = False
129
105 # Let command line args overwrite any values 130 # Let command line args overwrite any values
106 if args.server != None: 131 if args.server != None:
107 server = args.server 132 server = args.server
108 if args.port != None: 133 if args.port != None:
109 port = args.port 134 port = args.port
135 if args.plain:
136 plain = args.plain
110 if args.insecure: 137 if args.insecure:
111 insecure = args.insecure 138 insecure = args.insecure
112 139
@@ -115,7 +142,7 @@ def get_vars(args,confparser):
115 print("error: one or more items unspecified") 142 print("error: one or more items unspecified")
116 sys.exit(1) 143 sys.exit(1)
117 144
118 return server,port,insecure 145 return server,port,plain,insecure
119 146
120 147
121def main(): 148def main():
@@ -125,7 +152,7 @@ def main():
125 # Get arguments 152 # Get arguments
126 args = parse_arguments() 153 args = parse_arguments()
127 confparser = read_config(args.config) 154 confparser = read_config(args.config)
128 mfa_server,pam_port,insecure = get_vars(args,confparser) 155 mfa_server,pam_port,plain,insecure = get_vars(args,confparser)
129 user = args.user 156 user = args.user
130 service = args.service 157 service = args.service
131 158
@@ -144,12 +171,13 @@ def main():
144 hostname = args.host 171 hostname = args.host
145 data = user + "," + hostname + "," + service 172 data = user + "," + hostname + "," + service
146 173
147
148 # Initalize connection to MFA server. Quit if unable to connect. 174 # Initalize connection to MFA server. Quit if unable to connect.
149 connection = init_connection(mfa_server,pam_port,insecure) 175 if plain:
176 connection = init_connection(mfa_server, pam_port)
177 else:
178 connection = init_connection_tls(mfa_server,pam_port,insecure)
150 if connection == None: 179 if connection == None:
151 print(failed) 180 die("failed to connect")
152 sys.exit(1)
153 181
154 # Send authentication data to MFA server 182 # Send authentication data to MFA server
155 data_length = len(data) 183 data_length = len(data)