Merge 6f520ae63a into 6ba82d371b
This commit is contained in:
commit
ae14c74b37
|
|
@ -86,6 +86,9 @@ and websockify as a browser telnet client (`wstelnet.html`).
|
|||
|
||||
These are not necessary for the basic operation.
|
||||
|
||||
* Muliti-vncserver: Use path in URL to pass VNC server address:port for
|
||||
connecting different VNC servers.
|
||||
|
||||
* Daemonizing: When the `-D` option is specified, websockify runs
|
||||
in the background as a daemon process.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
#!/usr/bin/env python
|
||||
'''The program encode and decode the string with base64 and hash to validate the integrality.
|
||||
'''
|
||||
import sys
|
||||
import hashlib
|
||||
import base64
|
||||
import datetime
|
||||
import group
|
||||
# Please change the salt for your own project.
|
||||
#SALT = "Some salt for security. liqun@ncl.sg"
|
||||
SALT = "Some salt for security. Please change it in your project. liqun@ncl.sg"
|
||||
def qencode(str, create_date=datetime.date.today(), salt=SALT):
|
||||
''' The func encode str, hash it and base64 it.'''
|
||||
alg = hashlib.sha256()
|
||||
tstr = create_date.strftime("%Y%m%d")
|
||||
alg.update(tstr)
|
||||
alg.update(':')
|
||||
alg.update(str)
|
||||
alg.update(salt)
|
||||
hash = alg.hexdigest()
|
||||
return base64.urlsafe_b64encode(hash+tstr+':'+str)
|
||||
def qdecode(str, valid_daynum=3, salt=SALT):
|
||||
''' The func decode str, validate with hash and base64.decode it.
|
||||
If valid_daynum =0, only today is valid.'''
|
||||
if str[-1] == '/':
|
||||
str1 = base64.urlsafe_b64decode(str[0:-1])
|
||||
else:
|
||||
str1 = base64.urlsafe_b64decode(str)
|
||||
pos = str1.find(':')
|
||||
if pos == -1:
|
||||
return '','Err:not find :'
|
||||
hash = str1[0:pos-8]
|
||||
tstr = str1[pos-8:pos]
|
||||
url_date = datetime.date(int(str1[pos-8:pos-4]), int(str1[pos-4:pos-2]), int(str1[pos-2:pos]))
|
||||
today = datetime.date.today()
|
||||
if (today - url_date) > datetime.timedelta(valid_daynum):
|
||||
return '', 'Err: Timeout'
|
||||
alg = hashlib.sha256()
|
||||
alg.update(str1[pos-8:])
|
||||
alg.update(salt)
|
||||
hash1 = alg.hexdigest()
|
||||
if hash != hash1:
|
||||
return '', 'Err: Wrong hash'
|
||||
return str1[pos+1:], ''
|
||||
def get_server_from_path(path, is_encoded, valid_daynum=3, salt=SALT, gpolicy=group.gpolicy):
|
||||
'''The func decode host port from path parameter.
|
||||
path looks like [/qencode(n1.soc.cloud.ncl.sg:5901)]
|
||||
'''
|
||||
phost = ''
|
||||
if path[-1] == '/':
|
||||
path = path[0:-1]
|
||||
|
||||
try:
|
||||
pos = path.rfind('/')
|
||||
if pos == -1:
|
||||
return '', 0
|
||||
if is_encoded:
|
||||
(str,err) = qdecode(path[pos+1:], valid_daynum, salt)
|
||||
if err != '':
|
||||
phost = err
|
||||
else:
|
||||
str = path[pos+1:]
|
||||
if str == '':
|
||||
return phost, 0
|
||||
part_list = str.split(':')
|
||||
phost = part_list[0]
|
||||
pport = int(part_list[1])
|
||||
if len(part_list) > 2:
|
||||
username = part_list[2]
|
||||
# check the access ability.
|
||||
if not group.can_access(username, phost, gpolicy):
|
||||
return 'Err: group policy block', 0
|
||||
except:
|
||||
raise
|
||||
#return phost, 0
|
||||
return phost, pport
|
||||
|
||||
def test_basic():
|
||||
'''The func test some basic func.'''
|
||||
assert get_server_from_path('/n1.soc.cloud.ncl.sg:5901', False) == ('n1.soc.cloud.ncl.sg', 5901)
|
||||
|
||||
str = "n1.soc.cloud.ncl.sg:5901"
|
||||
enc = qencode(str)
|
||||
print enc
|
||||
print base64.urlsafe_b64decode(enc)
|
||||
(dec,err) = qdecode(enc)
|
||||
assert str == dec
|
||||
assert get_server_from_path('/'+enc, True) == ('n1.soc.cloud.ncl.sg', 5901)
|
||||
enc = qencode(str, datetime.date(2018, 2, 24))
|
||||
assert (get_server_from_path('/'+enc, True)) == ('Err: Timeout', 0)
|
||||
enc = qencode(str, datetime.date.today(), 'test salt')
|
||||
(dec,err) = qdecode(enc, 3, 'test salt')
|
||||
assert str == dec
|
||||
(dec,err) = qdecode(enc, 3, 'test salt1')
|
||||
assert dec == ''
|
||||
str = "n1.soc.cloud.ncl.sg:5901:ntechni3"
|
||||
enc = qencode(str)
|
||||
print enc
|
||||
print base64.urlsafe_b64decode(enc)
|
||||
(dec,err) = qdecode(enc)
|
||||
assert str == dec
|
||||
assert get_server_from_path('/'+enc, True) == ('n1.soc.cloud.ncl.sg', 5901)
|
||||
(dec,err) = qdecode(enc + '/')
|
||||
assert str == dec
|
||||
gpolicy = {
|
||||
"ExperimentDomainName":"soc.cloud.ncl.sg",
|
||||
'Groups':[{
|
||||
'Name':'Red',
|
||||
'Users': ["user1", "ntechni3"],
|
||||
'Hosts': ["n1"]
|
||||
},
|
||||
{
|
||||
'Name':'Blue',
|
||||
'Users': ['user1'],
|
||||
'Hosts': ['n2','n3']
|
||||
}]
|
||||
}
|
||||
str = "n1.soc.cloud.ncl.sg:5901:ntechni3"
|
||||
enc = qencode(str)
|
||||
assert get_server_from_path('/'+enc, True, 3, SALT, gpolicy) == ('n1.soc.cloud.ncl.sg', 5901)
|
||||
str = "n2.soc.cloud.ncl.sg:5901:ntechni3"
|
||||
enc = qencode(str)
|
||||
assert get_server_from_path('/'+enc, True, 3, SALT, gpolicy) == ('Err: group policy block', 0)
|
||||
|
||||
def main():
|
||||
'''The func is the main func.'''
|
||||
import sys
|
||||
if (len(sys.argv) == 2) and (sys.argv[1] == "test"):
|
||||
test_basic()
|
||||
print "Pass all test"
|
||||
exit()
|
||||
elif (len(sys.argv) == 2):
|
||||
print qencode(sys.argv[1])
|
||||
elif (len(sys.argv) == 3) and (sys.argv[1] == "decode"):
|
||||
print get_server_from_path(sys.argv[2], True)
|
||||
#print qdecode(sys.argv[2])
|
||||
elif (len(sys.argv) == 5) and (sys.argv[1] == "decode"):
|
||||
print qdecode(sys.argv[2],int(sys.argv[3]),sys.argv[4])
|
||||
elif (len(sys.argv) == 5) and (sys.argv[1] == "encode"):
|
||||
print qencode(sys.argv[2],int(sys.argv[3]),sys.argv[4])
|
||||
elif (len(sys.argv) == 3) and (sys.argv[1] == "debase"):
|
||||
str1 = base64.urlsafe_b64decode(sys.argv[2])
|
||||
print str1
|
||||
else:
|
||||
print '''%s [content to encode] [valid day number:3] [salt to encrypt]
|
||||
decode [content to decode] [valid day number:3] [salt to encrypt]
|
||||
test''' % sys.argv[0]
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
#!/usr/bin/env python
|
||||
import subprocess
|
||||
|
||||
gpolicy = { }
|
||||
|
||||
def group(users, hosts, ousers, ohosts):
|
||||
'''The func handle group policy for one group. Users can access hosts.'''
|
||||
pass
|
||||
def get_users_hosts(gpolicy):
|
||||
'''The func Get the all user list, hosts, hosts_access'''
|
||||
users = set()
|
||||
hosts = {}
|
||||
hosts_access = {}
|
||||
# Get the all user list, hosts, hosts_access
|
||||
for group in gpolicy['Groups']:
|
||||
if not group.has_key('Name'):
|
||||
print "The group do not have key [Name]"
|
||||
continue;
|
||||
for user in group['Users']:
|
||||
users.add(user)
|
||||
if not hosts_access.has_key(user):
|
||||
hosts_access[user] = set()
|
||||
if group.has_key('Hosts'):
|
||||
hosts_access[user] = hosts_access[user].union(group['Hosts'])
|
||||
# get all host list.
|
||||
if group.has_key('Hosts'):
|
||||
for host in group['Hosts']:
|
||||
hosts[host] = ''
|
||||
return users, hosts, hosts_access
|
||||
def get_super_users(gpolicy, users, hosts_access):
|
||||
'''The func Get all super user list. User in super user list need be
|
||||
deleted in user list and hosts_access.'''
|
||||
super_users = set()
|
||||
# Get all super user list.
|
||||
for group in gpolicy['Groups']:
|
||||
if not group.has_key('Name'):
|
||||
print "The group do not have key [Name]"
|
||||
continue;
|
||||
if not group.has_key('Hosts'):
|
||||
for user in group['Users']:
|
||||
# Delete super user from normal user list.
|
||||
if user in users:
|
||||
users.remove(user)
|
||||
del hosts_access[user]
|
||||
super_users.add(user)
|
||||
return (super_users, users, hosts_access)
|
||||
def get_unaccess_hosts(hosts_access, hosts):
|
||||
hosts_unaccess = {}
|
||||
for user in hosts_access.keys():
|
||||
hosts_unaccess[user] = set()
|
||||
for host in hosts:
|
||||
if host not in hosts_access[user]:
|
||||
hosts_unaccess[user].add(host)
|
||||
return hosts_unaccess
|
||||
def can_access(username, node_url, gpolicy):
|
||||
'''The func return true or False, based on gpolicy allowing username to node_url or not.'''
|
||||
if not gpolicy.has_key('ExperimentDomainName'):
|
||||
print 'Err: no ExperimentDomainName'
|
||||
return True
|
||||
ename = gpolicy['ExperimentDomainName']
|
||||
exp_name = ename
|
||||
dnode = node_url[:node_url.find('.')]
|
||||
dexp = node_url[node_url.find('.')+1:]
|
||||
if dexp != exp_name :
|
||||
# not the experience group return true.
|
||||
return True
|
||||
for group in gpolicy['Groups']:
|
||||
find_host = False
|
||||
find_user = False
|
||||
if not group.has_key('Name'):
|
||||
print "The group do not have key [Name]"
|
||||
continue;
|
||||
if group.has_key('Hosts'):
|
||||
for host in group['Hosts']:
|
||||
if host == dnode:
|
||||
find_host = True
|
||||
else:
|
||||
#super user group, can access all nodes.
|
||||
find_host = True
|
||||
if group.has_key('Users'):
|
||||
for user in group['Users']:
|
||||
if username == user:
|
||||
find_user = True
|
||||
if find_host and find_user :
|
||||
return True
|
||||
return False
|
||||
|
||||
def group_exp(gpolicy):
|
||||
ename = gpolicy['ExperimentDomainName']
|
||||
users = ()
|
||||
super_users = ()
|
||||
hosts = {}
|
||||
hosts_access = {}
|
||||
hosts_unaccess = {}
|
||||
# Get the all user list, hosts, hosts_access
|
||||
(users, hosts, hosts_access) = get_users_hosts(gpolicy)
|
||||
# Get all super user list.
|
||||
(super_users, users, hosts_access) = get_super_users(gpolicy, users, hosts_access)
|
||||
# produce unaccess hosts for every user.
|
||||
hosts_unaccess = get_unaccess_hosts(hosts_access, hosts)
|
||||
|
||||
# For every normal user, get all accessable host list and give access right, other give no right.
|
||||
for user in users:
|
||||
for host in hosts_access[user]:
|
||||
hosts[host] += 'sudo usermod -e "" %s\n' % user
|
||||
for user in users:
|
||||
for host in hosts_unaccess[user]:
|
||||
hosts[host] += 'sudo usermod -e 1 %s\n' % user
|
||||
# For every super user, give all access.
|
||||
for user in super_users:
|
||||
for host in hosts.keys():
|
||||
hosts[host] += 'sudo usermod -e "" %s\n' % user
|
||||
return hosts
|
||||
def test():
|
||||
gpolicy = {
|
||||
"ExperimentDomainName":"EnterpriseNetwork.NYPSOC.ncl.sg",
|
||||
'Groups':[]
|
||||
}
|
||||
assert get_users_hosts(gpolicy) == (set([]), {}, {})
|
||||
|
||||
gpolicy = {
|
||||
"ExperimentDomainName":"EnterpriseNetwork.NYPSOC.ncl.sg",
|
||||
'Groups':[{
|
||||
'Name':'Red',
|
||||
'Users': ["user1", "user2"],
|
||||
'Hosts': ["n1"]
|
||||
},
|
||||
{
|
||||
'Name':'Blue',
|
||||
'Users': ['user3'],
|
||||
'Hosts': ['n2','n3']
|
||||
},
|
||||
{
|
||||
'Name':'Grey',
|
||||
'Users': ['user4'],
|
||||
'Hosts': []
|
||||
},
|
||||
{
|
||||
'Name':'Super',
|
||||
'Users': ['user3']
|
||||
}]
|
||||
}
|
||||
(users, hosts, hosts_access) = get_users_hosts(gpolicy)
|
||||
assert (users, hosts, hosts_access) == (set(['user4', 'user2', 'user3', 'user1']),\
|
||||
{'n1': '', 'n2': '', 'n3': ''}, \
|
||||
{'user4': set([]), 'user2': set(['n1']), 'user3': set(['n2', 'n3']), 'user1': set(['n1'])})
|
||||
assert get_unaccess_hosts(hosts_access, hosts) == {
|
||||
'user4': set(['n1', 'n2', 'n3']), 'user2': set(['n2', 'n3']),
|
||||
'user3': set(['n1']), 'user1': set(['n2', 'n3'])}
|
||||
(super_users, users, hosts_access) = get_super_users(gpolicy, users, hosts_access)
|
||||
assert (super_users, users, hosts_access) == (set(['user3']),
|
||||
set(['user4', 'user2', 'user1']), \
|
||||
{'user4': set([]), 'user2': set(['n1']), 'user1': set(['n1'])})
|
||||
assert get_unaccess_hosts(hosts_access, hosts) == {
|
||||
'user4': set(['n1', 'n2', 'n3']), 'user2': set(['n2', 'n3']),
|
||||
'user1': set(['n2', 'n3'])}
|
||||
print group_exp(gpolicy)
|
||||
group_exp(gpolicy) == {'n1': 'sudo usermod -e "" user2\nsudo usermod -e "" user1\nsudo usermod -e 1 user4\nsudo usermod -e "" user3\n', 'n2': 'sudo usermod -e 1 user4\nsudo usermod -e 1 user2\nsudo usermod -e 1 user1\nsudo usermod -e "" user3\n', 'n3': 'sudo usermod -e 1 user4\nsudo usermod -e 1 user2\nsudo usermod -e 1 user1\nsudo usermod -e "" user3\n'}
|
||||
|
||||
assert get_unaccess_hosts({'user1': set(['n1'])}, {'n1': ''}) == {'user1': set([])}
|
||||
assert get_unaccess_hosts({'user1': set([])}, {'n1': ''}) == {'user1': set(['n1'])}
|
||||
assert get_unaccess_hosts({'user1': set(['n1', 'n2'])}, {'n1': '', 'n2': ''}) == {'user1': set([])}
|
||||
|
||||
gpolicy = {
|
||||
"ExperimentDomainName":"EnterpriseNetwork.NYPSOC.ncl.sg",
|
||||
'Groups':[{
|
||||
'Name':'Red',
|
||||
'Users': ["user1", "user2"],
|
||||
'Hosts': ["n1"]
|
||||
},
|
||||
{
|
||||
'Name':'Blue',
|
||||
'Users': ['user1'],
|
||||
'Hosts': ['n2','n3']
|
||||
} ]
|
||||
}
|
||||
(users, hosts, hosts_access) = get_users_hosts(gpolicy)
|
||||
#print (users, hosts, hosts_access)
|
||||
assert (users, hosts, hosts_access) == (set(['user2', 'user1']), \
|
||||
{'n1': '', 'n2': '', 'n3': ''}, {'user2': set(['n1']), 'user1': set(['n1', 'n2', 'n3'])})
|
||||
gpolicy = {
|
||||
"ExperimentDomainName":"EnterpriseNetwork.NYPSOC.ncl.sg",
|
||||
'Groups':[{
|
||||
'Name':'Red',
|
||||
'Users': ["user1", "user2"],
|
||||
'Hosts': ["n1"]
|
||||
},
|
||||
{
|
||||
'Name':'Blue',
|
||||
'Users': ['user1'],
|
||||
'Hosts': ['n2','n3']
|
||||
},
|
||||
{ 'Name':'superusers', 'Users':['suser']}
|
||||
]
|
||||
}
|
||||
assert can_access('user1', 'n1.EnterpriseNetwork.NYPSOC.ncl.sg', gpolicy) == True
|
||||
assert can_access('user1', 'n1.another.NYPSOC.ncl.sg', gpolicy) == True
|
||||
assert can_access('user1', 'n2.EnterpriseNetwork.NYPSOC.ncl.sg', gpolicy) == True
|
||||
assert can_access('user2', 'n2.EnterpriseNetwork.NYPSOC.ncl.sg', gpolicy) == False
|
||||
assert can_access('user3', 'n2.EnterpriseNetwork.NYPSOC.ncl.sg', gpolicy) == False
|
||||
assert can_access('suser', 'n2.EnterpriseNetwork.NYPSOC.ncl.sg', gpolicy) == True
|
||||
|
||||
|
||||
def main():
|
||||
'''The func is the main func.'''
|
||||
import sys
|
||||
if (len(sys.argv) == 2) and (sys.argv[1] == "test"):
|
||||
test()
|
||||
print "Pass all test"
|
||||
exit()
|
||||
if (len(sys.argv) == 2) and (sys.argv[1] == "do"):
|
||||
gp1 = { }
|
||||
node_cmd_list = group_exp(gp1)
|
||||
ename = gp1['ExperimentDomainName']
|
||||
|
||||
for (node, cmd) in node_cmd_list.items():
|
||||
cmdline = "echo '%s' | ssh %s.%s" % (cmd, node, ename)
|
||||
subprocess.call(cmdline, shell = True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -30,6 +30,15 @@ try:
|
|||
except ImportError:
|
||||
from cgi import parse_qs
|
||||
from urlparse import urlparse
|
||||
# Switch to open function let URL path define path.
|
||||
# &path=vncserver.domain.name:port
|
||||
URL_PATH_DEF_VNCSERVER = True
|
||||
# Whether is URL path encoded
|
||||
URL_PATH_ENCODED = False
|
||||
# URL valid day number after creating.
|
||||
URL_VALID_DAYNUM = 1
|
||||
# Salt used to valide the hash of the URL.
|
||||
URL_SALT = "Some salt for security. Please change it in your project. liqun@ncl.sg"
|
||||
|
||||
class ProxyRequestHandler(websockifyserver.WebSockifyRequestHandler):
|
||||
|
||||
|
|
@ -104,6 +113,15 @@ Traffic Legend:
|
|||
msg = "connecting to command: '%s' (port %s)" % (" ".join(self.server.wrap_cmd), self.server.target_port)
|
||||
elif self.server.unix_target:
|
||||
msg = "connecting to unix socket: %s" % self.server.unix_target
|
||||
elif URL_PATH_DEF_VNCSERVER:
|
||||
import encode_url
|
||||
(ptarget_host, ptarget_port) = encode_url.get_server_from_path(\
|
||||
self.path, URL_PATH_ENCODED, URL_VALID_DAYNUM, URL_SALT)
|
||||
if ptarget_port == 0:
|
||||
print 'Error: URL encode error[%s]' % ptarget_host
|
||||
return
|
||||
#raise self.server.EClose('Cannot decode path.')
|
||||
msg = "connecting to: %s:%s" % (ptarget_host, ptarget_port)
|
||||
else:
|
||||
msg = "connecting to: %s:%s" % (
|
||||
self.server.target_host, self.server.target_port)
|
||||
|
|
@ -112,7 +130,14 @@ Traffic Legend:
|
|||
msg += " (using SSL)"
|
||||
self.log_message(msg)
|
||||
|
||||
tsock = websockifyserver.WebSockifyServer.socket(self.server.target_host,
|
||||
if URL_PATH_DEF_VNCSERVER:
|
||||
tsock = websockifyserver.WebSockifyServer.socket(ptarget_host,
|
||||
ptarget_port,
|
||||
connect=True,
|
||||
use_ssl=self.server.ssl_target,
|
||||
unix_socket=self.server.unix_target)
|
||||
else:
|
||||
tsock = websockifyserver.WebSockifyServer.socket(self.server.target_host,
|
||||
self.server.target_port,
|
||||
connect=True,
|
||||
use_ssl=self.server.ssl_target,
|
||||
|
|
|
|||
Loading…
Reference in New Issue