Merge df1aa028da into 795552e418
This commit is contained in:
commit
968a529b57
|
|
@ -0,0 +1,144 @@
|
||||||
|
'''
|
||||||
|
Django authentication plugins for Python WebSocket library.
|
||||||
|
Copyright 2015 Luca Capacci
|
||||||
|
Licensed under LGPL version 3
|
||||||
|
|
||||||
|
|
||||||
|
**************************************** SessionIdAuth ****************************************
|
||||||
|
|
||||||
|
SessionIdAuth grants access to the target only to the users authenticated in a django web app.
|
||||||
|
|
||||||
|
Usage: put the websockify folder inside the django project, as shown below:
|
||||||
|
|
||||||
|
django_project
|
||||||
|
|__________django_project
|
||||||
|
| |__________ settings.py
|
||||||
|
| |
|
||||||
|
| |__________ urls.py
|
||||||
|
| |
|
||||||
|
| |__________ wsgi.py
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|__________ websockify
|
||||||
|
| |__________ some files...
|
||||||
|
| |
|
||||||
|
| |__________ websockify
|
||||||
|
| |_____________ django_auth_plugins.py
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|__________ other files and folders...
|
||||||
|
|
||||||
|
Right after starting the django web app, run websockify with the --auth-plugin option (Example: ./websockify/run 6080 localhost:5900 --auth-plugin="websockify.django_auth_plugins.SessionIdAuth")
|
||||||
|
|
||||||
|
|
||||||
|
**************************************** SessionIdAuthAndHostPort ****************************************
|
||||||
|
|
||||||
|
SessionIdAuthAndHostPort determines the target based on the authenticated user.
|
||||||
|
|
||||||
|
Usage: put the websockify folder inside the django project, as shown below:
|
||||||
|
|
||||||
|
django_project
|
||||||
|
|__________django_project
|
||||||
|
| |__________ settings.py
|
||||||
|
| |
|
||||||
|
| |__________ urls.py
|
||||||
|
| |
|
||||||
|
| |__________ wsgi.py
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|__________ websockify
|
||||||
|
| |__________ some files...
|
||||||
|
| |
|
||||||
|
| |__________ websockify
|
||||||
|
| |_____________ django_auth_plugins.py
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|__________ other files and folders...
|
||||||
|
|
||||||
|
|
||||||
|
Edit get_host_port(current_user) to implement an algorithm to determine a target and a host for each user.
|
||||||
|
|
||||||
|
Right after starting the django web app, run websockify with the --auth-plugin and the --auth-host-port options (Example: ./websockify/run 6080 --auth-plugin="websockify.django_auth_plugins.SessionIdAuthAndHostPort" --auth-host-port)
|
||||||
|
|
||||||
|
For a complete example: https://github.com/lucacapacci/noVncDjangoPoC
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
from auth_plugins import AuthenticationError
|
||||||
|
|
||||||
|
|
||||||
|
class SessionIdAuth(object):
|
||||||
|
def __init__(self, src=None):
|
||||||
|
init_django()
|
||||||
|
|
||||||
|
def authenticate(self, headers, target_host, target_port):
|
||||||
|
try:
|
||||||
|
cookies = headers.get('Cookie').split("; ")
|
||||||
|
for cookie in cookies:
|
||||||
|
if cookie.startswith("sessionid"):
|
||||||
|
session_token = cookie.split("=")[1]
|
||||||
|
current_user = user_from_session_key(session_token)
|
||||||
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
if type(current_user) is AnonymousUser:
|
||||||
|
raise AuthenticationError(response_code=403)
|
||||||
|
except:
|
||||||
|
raise AuthenticationError(response_code=403)
|
||||||
|
|
||||||
|
|
||||||
|
class SessionIdAuthAndHostPort(object):
|
||||||
|
def __init__(self, src=None):
|
||||||
|
init_django()
|
||||||
|
|
||||||
|
def authenticate(self, headers, target_host, target_port):
|
||||||
|
try:
|
||||||
|
cookies = headers.get('Cookie').split("; ")
|
||||||
|
for cookie in cookies:
|
||||||
|
if cookie.startswith("sessionid"):
|
||||||
|
session_token = cookie.split("=")[1]
|
||||||
|
current_user = user_from_session_key(session_token)
|
||||||
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
if type(current_user) is AnonymousUser:
|
||||||
|
raise AuthenticationError(response_code=403)
|
||||||
|
return get_host_port(current_user)
|
||||||
|
except:
|
||||||
|
raise AuthenticationError(response_code=403)
|
||||||
|
|
||||||
|
|
||||||
|
def get_host_port(current_user):
|
||||||
|
host_port_dict = {'john': ('localhost', 5900),
|
||||||
|
'bob': ('localhost', 5901)}
|
||||||
|
|
||||||
|
if current_user.username in host_port_dict:
|
||||||
|
return host_port_dict[current_user.username]
|
||||||
|
else:
|
||||||
|
raise AuthenticationError(response_code=403)
|
||||||
|
|
||||||
|
|
||||||
|
def user_from_session_key(session_key):
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.auth import SESSION_KEY, BACKEND_SESSION_KEY, load_backend
|
||||||
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
|
||||||
|
session_engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
|
||||||
|
session_wrapper = session_engine.SessionStore(session_key)
|
||||||
|
session = session_wrapper.load()
|
||||||
|
user_id = session.get(SESSION_KEY)
|
||||||
|
backend_id = session.get(BACKEND_SESSION_KEY)
|
||||||
|
if user_id and backend_id:
|
||||||
|
auth_backend = load_backend(backend_id)
|
||||||
|
user = auth_backend.get_user(user_id)
|
||||||
|
if user:
|
||||||
|
return user
|
||||||
|
return AnonymousUser()
|
||||||
|
|
||||||
|
|
||||||
|
def init_django():
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
current_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
django_app_path = os.path.abspath(os.path.join(current_path, os.pardir, os.pardir))
|
||||||
|
sys.path.insert(0, django_app_path)
|
||||||
|
os.environ['DJANGO_SETTINGS_MODULE'] = u'{0}.settings'.format(os.path.split(django_app_path)[1])
|
||||||
|
import django
|
||||||
|
django.setup()
|
||||||
|
|
@ -61,6 +61,13 @@ Traffic Legend:
|
||||||
|
|
||||||
if self.server.auth_plugin:
|
if self.server.auth_plugin:
|
||||||
try:
|
try:
|
||||||
|
if self.server.auth_host_port:
|
||||||
|
server_target_host, server_target_port = self.server.auth_plugin.authenticate(headers=self.headers,
|
||||||
|
target_host=self.server.target_host,
|
||||||
|
target_port=self.server.target_port)
|
||||||
|
self.server.target_host = server_target_host
|
||||||
|
self.server.target_port = server_target_port
|
||||||
|
else:
|
||||||
self.server.auth_plugin.authenticate(
|
self.server.auth_plugin.authenticate(
|
||||||
headers=self.headers, target_host=self.server.target_host,
|
headers=self.headers, target_host=self.server.target_host,
|
||||||
target_port=self.server.target_port)
|
target_port=self.server.target_port)
|
||||||
|
|
@ -241,6 +248,7 @@ class WebSocketProxy(websockifyserver.WebSockifyServer):
|
||||||
|
|
||||||
self.token_plugin = kwargs.pop('token_plugin', None)
|
self.token_plugin = kwargs.pop('token_plugin', None)
|
||||||
self.auth_plugin = kwargs.pop('auth_plugin', None)
|
self.auth_plugin = kwargs.pop('auth_plugin', None)
|
||||||
|
self.auth_host_port = kwargs.pop('auth_host_port', False)
|
||||||
|
|
||||||
# Last 3 timestamps command was run
|
# Last 3 timestamps command was run
|
||||||
self.wrap_times = [0, 0, 0]
|
self.wrap_times = [0, 0, 0]
|
||||||
|
|
@ -300,6 +308,9 @@ class WebSocketProxy(websockifyserver.WebSockifyServer):
|
||||||
if self.token_plugin:
|
if self.token_plugin:
|
||||||
msg = " - proxying from %s:%s to targets generated by %s" % (
|
msg = " - proxying from %s:%s to targets generated by %s" % (
|
||||||
self.listen_host, self.listen_port, type(self.token_plugin).__name__)
|
self.listen_host, self.listen_port, type(self.token_plugin).__name__)
|
||||||
|
elif self.auth_host_port:
|
||||||
|
msg = " - proxying from %s:%s to targets generated by %s" % (
|
||||||
|
self.listen_host, self.listen_port, type(self.auth_plugin).__name__)
|
||||||
else:
|
else:
|
||||||
msg = " - proxying from %s:%s to %s" % (
|
msg = " - proxying from %s:%s to %s" % (
|
||||||
self.listen_host, self.listen_port, dst_string)
|
self.listen_host, self.listen_port, dst_string)
|
||||||
|
|
@ -419,6 +430,8 @@ def websockify_init():
|
||||||
parser.add_option("--auth-source", default=None, metavar="ARG",
|
parser.add_option("--auth-source", default=None, metavar="ARG",
|
||||||
help="an argument to be passed to the auth plugin"
|
help="an argument to be passed to the auth plugin"
|
||||||
"on instantiation")
|
"on instantiation")
|
||||||
|
parser.add_option("--auth-host-port", action="store_true",
|
||||||
|
help="let the auth plugin set host and port")
|
||||||
parser.add_option("--auto-pong", action="store_true",
|
parser.add_option("--auto-pong", action="store_true",
|
||||||
help="Automatically respond to ping frames with a pong")
|
help="Automatically respond to ping frames with a pong")
|
||||||
parser.add_option("--heartbeat", type=int, default=0,
|
parser.add_option("--heartbeat", type=int, default=0,
|
||||||
|
|
@ -448,6 +461,8 @@ def websockify_init():
|
||||||
if opts.auth_source and not opts.auth_plugin:
|
if opts.auth_source and not opts.auth_plugin:
|
||||||
parser.error("You must use --auth-plugin to use --auth-source")
|
parser.error("You must use --auth-plugin to use --auth-source")
|
||||||
|
|
||||||
|
if opts.auth_host_port and not opts.auth_plugin:
|
||||||
|
parser.error("You must use --auth-plugin to use --auth-host-port")
|
||||||
|
|
||||||
# Transform to absolute path as daemon may chdir
|
# Transform to absolute path as daemon may chdir
|
||||||
if opts.target_cfg:
|
if opts.target_cfg:
|
||||||
|
|
@ -460,7 +475,7 @@ def websockify_init():
|
||||||
del opts.target_cfg
|
del opts.target_cfg
|
||||||
|
|
||||||
# Sanity checks
|
# Sanity checks
|
||||||
if len(args) < 2 and not (opts.token_plugin or opts.unix_target):
|
if len(args) < 2 and not (opts.token_plugin or opts.unix_target or opts.auth_host_port):
|
||||||
parser.error("Too few arguments")
|
parser.error("Too few arguments")
|
||||||
if sys.argv.count('--'):
|
if sys.argv.count('--'):
|
||||||
opts.wrap_cmd = args[1:]
|
opts.wrap_cmd = args[1:]
|
||||||
|
|
@ -485,7 +500,7 @@ def websockify_init():
|
||||||
try: opts.listen_port = int(opts.listen_port)
|
try: opts.listen_port = int(opts.listen_port)
|
||||||
except: parser.error("Error parsing listen port")
|
except: parser.error("Error parsing listen port")
|
||||||
|
|
||||||
if opts.wrap_cmd or opts.unix_target or opts.token_plugin:
|
if opts.wrap_cmd or opts.unix_target or opts.token_plugin or opts.auth_host_port:
|
||||||
opts.target_host = None
|
opts.target_host = None
|
||||||
opts.target_port = None
|
opts.target_port = None
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue