Compare commits

..

5 commits

Author SHA1 Message Date
Quantum 3d755031e4 Fix flake8 config 2024-10-08 00:28:59 -04:00
Quantum 43a7bb694f Release 0.0.4 2024-10-08 00:26:39 -04:00
Quantum 48b6cdb79b Add support for TLS certificate authentication 2024-10-08 00:18:14 -04:00
Quantum 7b51c69038 Bump version to 0.0.3 2024-10-07 23:16:13 -04:00
Quantum 2769dfd5f8 Make cookie a string 2023-12-21 03:25:50 -05:00
4 changed files with 43 additions and 10 deletions

View file

@ -3,5 +3,7 @@ max-line-length = 120
import-order-style = pycharm import-order-style = pycharm
enable-extensions = G enable-extensions = G
ignore = ignore =
W504, # line break occurred after a binary operator # line break occurred after a binary operator
C814 # missing trailing comma in Python 2 only W504,
# missing trailing comma in Python 2 only
C814

View file

@ -89,6 +89,27 @@ the client does not support Kerberos. To use this, configure:
There should be one `%s` symbol in this string, which will be replaced by the There should be one `%s` symbol in this string, which will be replaced by the
username. username.
### TLS Client Certificate
It's also possible to use client certificates on machines that have them for
authentication purposes instead of using LDAP or Kerberos. To do this, set
the environment variable `KRBAUTH_TLS_CERT_AUTH` to `1` or `yes`.
Then, pass the WSGI environment variable `NGINX_SSL_CLIENT_VERIFY` from `nginx`,
setting it to the value of `$ssl_client_verify`, like this:
```nginx
uwsgi_param NGINX_SSL_CLIENT_VERIFY "$ssl_client_verify";
```
You most likely want to make client certificate verification optional if you
are using it with `nginx-krbauth`:
```nginx
ssl_client_certificate /path/to/ca.crt;
ssl_verify_client optional;
```
## Example `nginx.conf` ## Example `nginx.conf`
```nginx ```nginx

View file

@ -41,6 +41,7 @@ else:
gssapi_creds = None gssapi_creds = None
COOKIE_SECURE = os.environ.get('KRBAUTH_SECURE_COOKIE', '1').lower() not in ('0', 'no') COOKIE_SECURE = os.environ.get('KRBAUTH_SECURE_COOKIE', '1').lower() not in ('0', 'no')
TLS_CERT_AUTH = os.environ.get('KRBAUTH_TLS_CERT_AUTH', '0').lower() in ('1', 'yes')
class Context: class Context:
@ -56,10 +57,10 @@ class Context:
return ''.join([self.ldap_group]).encode('utf-8') return ''.join([self.ldap_group]).encode('utf-8')
def make_cookie(context: Context) -> bytes: def make_cookie(context: Context) -> str:
message = timestamp.pack(int(time.time()) + DURATION) + os.urandom(RANDOM_SIZE) + context.bytes() message = timestamp.pack(int(time.time()) + DURATION) + os.urandom(RANDOM_SIZE) + context.bytes()
signature = hmac.new(HMAC_KEY, message, hmac_digest).digest() signature = hmac.new(HMAC_KEY, message, hmac_digest).digest()
return base64.b64encode(signature + message) return base64.b64encode(signature + message).decode()
def verify_cookie(cookie: Optional[str], context: Context) -> bool: def verify_cookie(cookie: Optional[str], context: Context) -> bool:
@ -170,12 +171,21 @@ def auth_basic(context: Context, next_url: str) -> Response:
return auth_success(context, next_url) return auth_success(context, next_url)
def check_tls() -> bool:
if not TLS_CERT_AUTH:
return False
return request.environ.get('NGINX_SSL_CLIENT_VERIFY') == 'SUCCESS'
@app.endpoint('krbauth.auth') @app.endpoint('krbauth.auth')
def auth() -> Response: def auth() -> Response:
next_url = request.args.get('next', '/') next_url = request.args.get('next', '/')
context = Context.from_request() context = Context.from_request()
authorization = request.headers.get('Authorization', '') authorization = request.headers.get('Authorization', '')
if check_tls():
return auth_success(context, next_url)
if authorization.startswith('Negotiate '): if authorization.startswith('Negotiate '):
return auth_spnego(context, next_url) return auth_spnego(context, next_url)
if LDAP_USER_DN and authorization.startswith('Basic '): if LDAP_USER_DN and authorization.startswith('Basic '):
@ -186,6 +196,6 @@ def auth() -> Response:
@app.endpoint('krbauth.check') @app.endpoint('krbauth.check')
def check() -> Response: def check() -> Response:
if verify_cookie(request.cookies.get('krbauth'), Context.from_request()): if check_tls() or verify_cookie(request.cookies.get('krbauth'), Context.from_request()):
return Response(status=200) return Response(status=200)
return Response(status=401) return Response(status=401)

View file

@ -7,7 +7,7 @@ with open(os.path.join(os.path.dirname(__file__), 'README.md')) as f:
setup( setup(
name='nginx_krbauth', name='nginx_krbauth',
version='0.0.2', version='0.0.4',
py_modules=['nginx_krbauth'], py_modules=['nginx_krbauth'],
install_requires=['flask', 'gssapi', 'python-ldap'], install_requires=['flask', 'gssapi', 'python-ldap'],
@ -27,11 +27,11 @@ setup(
'Operating System :: POSIX :: Linux', 'Operating System :: POSIX :: Linux',
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
'Topic :: Internet :: WWW/HTTP :: HTTP Servers', 'Topic :: Internet :: WWW/HTTP :: HTTP Servers',
'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
'Topic :: Security', 'Topic :: Security',