Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows drive #1034

Merged
merged 35 commits into from
Sep 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
99ab957
Initial commit, adding in react page
May 13, 2021
bbbdb34
Adding remote file browser to smb page
May 13, 2021
a17aed7
Create smb.py
Mletter1 May 13, 2021
a8aac2d
adding authentication for smb drives
Mletter1 May 14, 2021
2c2a47a
correcting imports and adding it to docker
Mletter1 May 14, 2021
3f35222
Update DockerFile
Mletter1 May 20, 2021
138b9ab
finishing auth and browse for smb
Mletter1 May 21, 2021
bb8508c
Adding smb browse to UI
May 28, 2021
e274ed7
adding browse to the modal
Mletter1 May 28, 2021
1094649
Update handlers.py
Mletter1 Jun 3, 2021
28beb3a
added smb stub for param space
Mletter1 Jun 4, 2021
b31c8cc
Merge branch 'master' into windows-drive
Mletter1 Jun 17, 2021
b917e0e
Stubbing out authentication tab
Jun 17, 2021
4a0df00
Merge branch 'windows-drive' of https://github.com/sandialabs/slycat …
Jun 17, 2021
c14d931
adding share name to input list
Mletter1 Jun 17, 2021
c365096
Update SmbAuthentication.tsx
Mletter1 Jun 18, 2021
3256cf5
added login and browse
Mletter1 Jun 18, 2021
a1b9caa
Merge branch 'master' into windows-drive
Mletter1 Jul 1, 2021
39cce33
added xhr request based no path selection
Mletter1 Jul 1, 2021
a10f40c
Update handlers.py
Mletter1 Jul 1, 2021
b0988b2
Adding backend for getting smb files
Jul 1, 2021
9bbc598
fixed session cleanup
Mletter1 Jul 15, 2021
89a7a45
Merge branch 'master' into windows-drive
Mletter1 Jul 19, 2021
90cb33d
added check for smb file types
Mletter1 Jul 22, 2021
b02bf47
Adding smb login on hover
Spurs20 Jul 22, 2021
bc8548c
Merge branch 'master' into windows-drive
Mletter1 Jul 29, 2021
e089e15
Keep track of collab name for hovering
Spurs20 Jul 29, 2021
f0966bf
Not using local storage on hover
Spurs20 Jul 29, 2021
aeed4d4
fixing back button
Mletter1 Aug 5, 2021
01687a5
Merge branch 'master' into windows-drive
Mletter1 Aug 18, 2021
1fc0557
Merge branch 'master' into windows-drive
Mletter1 Aug 18, 2021
c791b91
fixed not loading on first hover smb
Mletter1 Aug 19, 2021
d7a2aa2
Updating smb connection
Spurs20 Aug 19, 2021
7604f20
Fixing smb bug
Spurs20 Aug 31, 2021
40c183f
Adding error handling to smb authentication
Spurs20 Sep 2, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docker/compose/slycat-compose/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ routes
scipy
npTDMS
pandas
pysmb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ error-log-count: 100
error-log-size: 10000000
module-name: " "
password-check: {"plugin": "slycat-identity-password-check"}
plugins: [ "plugins", "plugins/slycat-cca", "plugins/slycat-run-command", "plugins/slycat-column-wizard", "plugins/slycat-model-wizards", "plugins/slycat-parameter-image", "plugins/slycat-project-wizards", "plugins/slycat-remap-wizard", "plugins/slycat-timeseries-model", "plugins/slycat-video-swarm", "plugins/slycat-dac"]
plugins: [ "plugins", "plugins/slycat-smb", "plugins/slycat-cca", "plugins/slycat-run-command", "plugins/slycat-column-wizard", "plugins/slycat-model-wizards", "plugins/slycat-parameter-image", "plugins/slycat-project-wizards", "plugins/slycat-remap-wizard", "plugins/slycat-timeseries-model", "plugins/slycat-video-swarm", "plugins/slycat-dac"]
projects-redirect: "/projects"
remote-hosts: [{ "hostnames": ["localhost"], "agent.old": {"command":"/home/slycat/install/conda/bin/python /home/slycat/src/slycat/agent/slycat-docker-agent.py --json /home/slycat/src/slycat/agent/json"}}]
remote-authentication: {"method":"password", "port":22, "localhost":"sshd"}
Expand Down
8 changes: 1 addition & 7 deletions packages/slycat/web/server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,14 +764,8 @@ def decode_username_and_password():
# cherrypy.log.error("decoding username and password")
user_name = str(base64_decode(cherrypy.request.json["user_name"]).decode())
password = str(base64_decode(cherrypy.request.json["password"]).decode())

# try and get the redirect path for after successful login
try:
location = cherrypy.request.json["location"]
except Exception as e:
location = None
# cherrypy.log.error("no location provided moving on")
except Exception as e:
cherrypy.log.error(str(e))
# cherrypy.log.error("username and password could not be decoded")
cherrypy.log.error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 400")
raise cherrypy.HTTPError(400)
Expand Down
4 changes: 3 additions & 1 deletion packages/slycat/web/server/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,11 @@ def abspath(path):
dispatcher.connect("post-log", "/log", slycat.web.server.handlers.post_log, conditions={"method" : ["POST"]})
dispatcher.connect("post-projects", "/projects", slycat.web.server.handlers.post_projects, conditions={"method" : ["POST"]})

#TODO: scrub sid
dispatcher.connect("post-remote-browse", "/remotes/:hostname/browse{path:.*}", slycat.web.server.handlers.post_remote_browse, conditions={"method" : ["POST"]})
dispatcher.connect("post-remotes", "/remotes", slycat.web.server.handlers.post_remotes, conditions={"method" : ["POST"]})
dispatcher.connect("post-remotes-smb", "/remotes/smb", slycat.web.server.handlers.post_remotes_smb, conditions={"method" : ["POST"]})
dispatcher.connect("post-smb-browse", "/smb/remotes/:hostname/browse{path:.*}", slycat.web.server.handlers.post_smb_browse, conditions={"method" : ["POST"]})



dispatcher.connect("put-model-arrayset-array", "/models/:mid/arraysets/:aid/arrays/:array", slycat.web.server.handlers.put_model_arrayset_array, conditions={"method" : ["PUT"]})
Expand Down
153 changes: 119 additions & 34 deletions packages/slycat/web/server/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import slycat.web.server.hdf5
import slycat.web.server.plugin
import slycat.web.server.remote
import slycat.web.server.smb
import slycat.web.server.streaming
import slycat.web.server.upload
import stat
Expand Down Expand Up @@ -68,19 +69,26 @@ def get_sid(hostname):
for index, host_session in enumerate(session["sessions"]):
if host_session["hostname"] == hostname:
sid = host_session["sid"]
if(not slycat.web.server.remote.check_session(sid)):
session_type = host_session["session_type"]
if(host_session["session_type"] == "ssh" and not slycat.web.server.remote.check_session(sid)):
cherrypy.log.error("error %s SID:%s Keys %s" % (slycat.web.server.remote.check_session(sid), sid, list(slycat.web.server.remote.session_cache.keys())))
slycat.web.server.remote.delete_session(sid)
del session["sessions"][index]
database.save(session)
raise cherrypy.HTTPError("404")
elif(host_session["session_type"] == "smb" and not slycat.web.server.smb.check_session(sid)):
cherrypy.log.error("error %s SID:%s Keys %s" % (slycat.web.server.smb.check_session(sid), sid, list(slycat.web.server.smb.session_cache.keys())))
slycat.web.server.smb.delete_session(sid)
del session["sessions"][index]
database.save(session)
raise cherrypy.HTTPError("404")
break
except Exception as e:
cherrypy.log.error("could not retrieve host session for remotes %s" % e)
raise cherrypy.HTTPError("404")
if sid is None:
raise cherrypy.HTTPError("400 session is None value")
return sid
return sid, session_type


def require_json_parameter(name):
Expand Down Expand Up @@ -1012,14 +1020,18 @@ def put_upload_file_part(uid, fid, pid, file=None, hostname=None, path=None):
data = file.file.read()

elif file is None and hostname is not None and path is not None:
sid = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
filename = "%s@%s:%s" % (session.username, session.hostname, path)
if stat.S_ISDIR(session.sftp.stat(path).st_mode):
cherrypy.log.error("slycat.web.server.handlers.py put_upload_file_part",
"cherrypy.HTTPError 400 cannot load directory %s." % filename)
raise cherrypy.HTTPError("400 Cannot load directory %s." % filename)
data = session.sftp.file(path).read()
sid, session_type = get_sid(hostname)
if session_type == "ssh":
with slycat.web.server.remote.get_session(sid) as session:
filename = "%s@%s:%s" % (session.username, session.hostname, path)
if stat.S_ISDIR(session.sftp.stat(path).st_mode):
cherrypy.log.error("slycat.web.server.handlers.py put_upload_file_part",
"cherrypy.HTTPError 400 cannot load directory %s." % filename)
raise cherrypy.HTTPError("400 Cannot load directory %s." % filename)
data = session.sftp.file(path).read()
elif session_type == "smb":
with slycat.web.server.smb.get_session(sid) as session:
data = session.get_file(path=path)
else:
cherrypy.log.error("slycat.web.server.handlers.py put_upload_file_part",
"cherrypy.HTTPError 400 must supply file parameter, or sid and path parameters.")
Expand Down Expand Up @@ -1208,7 +1220,7 @@ def clear_ssh_sessions():
sid = cherrypy.request.cookie["slycatauth"].value
couchdb = slycat.web.server.database.couchdb.connect()
session = couchdb.get("session", sid)
cherrypy.log.error("ssh sessions cleared for user session: %s" % session)
cherrypy.log.error("ssh and smb sessions cleared for user session: %s" % session)
cherrypy.response.status = "200"
if session is not None:
for ssh_session in session["sessions"]:
Expand Down Expand Up @@ -1899,18 +1911,16 @@ def validate_table_columns(columns):
columns = [(int(spec[0]), int(spec[1]) if len(spec) == 2 else int(spec[0]) + 1) for spec in columns]
columns = numpy.concatenate([numpy.arange(begin, end) for begin, end in columns])
columns = columns[columns >= 0]
return columns
except:
except Exception as e:
cherrypy.log.error(str(e))
cherrypy.log.error("slycat.web.server.handlers.py validate_table_columns",
"cherrypy.HTTPError 400 malformed columns argument must be a comma separated collection of column indices or half-open index ranges.")
raise cherrypy.HTTPError(
"400 Malformed columns argument must be a comma separated collection of column indices or half-open index ranges.")

if numpy.any(columns < 0):
cherrypy.log.error("slycat.web.server.handlers.py validate_table_columns",
"cherrypy.HTTPError 400 column values must be non-negative.")
raise cherrypy.HTTPError("400 Column values must be non-negative.")

return columns


Expand Down Expand Up @@ -2473,13 +2483,73 @@ def post_remotes():
if("sid" in session["sessions"][i] and session["sessions"][i]["sid"] is not None):
slycat.web.server.remote.delete_session(session["sessions"][i]["sid"])
del session["sessions"][i]
session["sessions"].append({"sid": sid, "hostname": hostname, "username": username})
session["sessions"].append({"sid": sid, "hostname": hostname, "username": username, "session_type": "ssh"})
database.save(session)
except Exception as e:
cherrypy.log.error("login could not save session for remotes %s" % e)
msg = "login could not save session for remote host"
return {"sid": sid, "status": True, "msg": msg}


@cherrypy.tools.json_in(on=True)
@cherrypy.tools.json_out(on=True)
def post_remotes_smb():
"""
Given username, hostname, password as a json payload
establishes a session with the remote host and attaches
it to the users session
:return: {"sid":sid, "status":boolean, msg:""}
user_name password

encode with in js

b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
"""
# try and decode the username and password
username, password = slycat.web.server.decode_username_and_password()
server = cherrypy.request.json["server"]
share = cherrypy.request.json["share"]
cherrypy.log.error("username:%s server:%s share:%s" % (username, server , share))
if username == None:
username = cherrypy.request.login
msg = ""
sid = slycat.web.server.smb.create_session(username,password,server,share)
'''
save sid to user session
the session will be stored as follows in the users session
{sessions:[{{"sid": sid,"hostname": hostname, "username": username}},...]}
'''
try:
database = slycat.web.server.database.couchdb.connect()
cherrypy.log.error("got the database")
session = database.get("session", cherrypy.request.cookie["slycatauth"].value)
for i in range(len(session["sessions"])):
if session["sessions"][i]["hostname"] == server:
if("sid" in session["sessions"][i] and session["sessions"][i]["sid"] is not None):
slycat.web.server.remote.delete_session(session["sessions"][i]["sid"])
del session["sessions"][i]
cherrypy.log.error("adding session")
session["sessions"].append({"sid": sid, "hostname": server, "username": username, "session_type": "smb"})
cherrypy.log.error("saving")
database.save(session)
cherrypy.log.error("saved")
except Exception as e:
cherrypy.log.error("login could not save session for remotes %s" % e)
msg = "login could not save session for remote host"
return {"sid": sid, "status": True, "msg": msg}

@cherrypy.tools.json_in(on=True)
@cherrypy.tools.json_out(on=True)
def post_smb_browse(hostname, path):
cherrypy.log.error("path:%s hostname:%s" % (path, hostname))
sid, session_type = get_sid(hostname)
cherrypy.log.error("sid:%s path:%s hostname:%s" % (sid, path, hostname))
with slycat.web.server.smb.get_session(sid) as session:
return session.browse(path=path)

@cherrypy.tools.json_out(on=True)
def get_remotes(hostname):
Expand All @@ -2496,12 +2566,16 @@ def get_remotes(hostname):
session = database.get("session", cherrypy.request.cookie["slycatauth"].value)
for h_session in session["sessions"]:
if h_session["hostname"] == hostname:
if slycat.web.server.remote.check_session(h_session["sid"]):
if h_session["session_type"] == "ssh" and slycat.web.server.remote.check_session(h_session["sid"]):
status = True
msg = "hostname session was found"
elif h_session["session_type"] == "smb" and slycat.web.server.smb.check_session(h_session["sid"]):
status = True
msg = "hostname session was found"
else:
session["sessions"][:] = [tup for tup in session["sessions"] if tup["hostname"] != hostname]
database.save(session)

except Exception as e:
cherrypy.log.error("status could not save session for remotes %s" % e)
return {"status": status, "msg": msg, "hostName": hostname}
Expand Down Expand Up @@ -2539,15 +2613,15 @@ def delete_remote(sid):

@cherrypy.tools.json_out(on=True)
def get_session_status(hostname):
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
return "success"


@cherrypy.tools.json_in(on=True)
@cherrypy.tools.json_out(on=True)
def post_remote_launch(hostname):
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
command = cherrypy.request.json["command"]
with slycat.web.server.remote.get_session(sid) as session:
return session.launch(command)
Expand All @@ -2556,36 +2630,36 @@ def post_remote_launch(hostname):
@cherrypy.tools.json_in(on=True)
@cherrypy.tools.json_out(on=True)
def post_submit_batch(hostname):
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
filename = cherrypy.request.json["filename"]
with slycat.web.server.remote.get_session(sid) as session:
return session.submit_batch(filename)


@cherrypy.tools.json_out(on=True)
def get_checkjob(hostname, jid):
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
return session.checkjob(jid)


@cherrypy.tools.json_out(on=True)
def delete_job(hostname, jid):
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
return session.cancel_job(jid)


@cherrypy.tools.json_out(on=True)
def get_job_output(hostname, jid, path):
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
return session.get_job_output(jid, path)


@cherrypy.tools.json_out(on=True)
def get_user_config(hostname):
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
return session.get_user_config()

Expand Down Expand Up @@ -2615,7 +2689,7 @@ def job_time(nodes, tasks, size):
@cherrypy.tools.json_out(on=True)
def set_user_config(hostname):
# TODO add user config mapping
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
config = cherrypy.request.json["config"]
cherrypy.log.error("user_config %s" % config)
with slycat.web.server.remote.get_session(sid) as session:
Expand Down Expand Up @@ -2657,23 +2731,23 @@ def post_remote_command(hostname):
type: string
field type eg string, int...
"""
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
command = cherrypy.request.json["command"]
with slycat.web.server.remote.get_session(sid) as session:
return session.run_remote_command(command)


@cherrypy.tools.json_out(on=True)
def get_remote_job_status(hostname, jid):
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
return session.get_remote_job_status(jid)


@cherrypy.tools.json_in(on=True)
@cherrypy.tools.json_out(on=True)
def post_remote_browse(hostname, path):
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
file_reject = re.compile(
cherrypy.request.json.get("file-reject")) if "file-reject" in cherrypy.request.json else None
file_allow = re.compile(cherrypy.request.json.get("file-allow")) if "file-allow" in cherrypy.request.json else None
Expand Down Expand Up @@ -2727,9 +2801,20 @@ def get_remote_file(hostname, path, **kwargs):
“Access denied” The session user doesn’t have permissions to access the file.
"""

sid = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
return session.get_file(path, **kwargs)
sid, session_type = get_sid(hostname)
if session_type == 'smb':
with slycat.web.server.smb.get_session(sid) as session:
split_list = path.split('/')
del split_list[1]
del split_list[0]
content_type, encoding = slycat.mime_type.guess_type(path)
if content_type is None:
content_type = "application/octet-stream"
cherrypy.response.headers["content-type"] = content_type
return session.get_file(path='/{0}'.format('/'.join(split_list)))
else:
with slycat.web.server.remote.get_session(sid) as session:
return session.get_file(path, **kwargs)


def get_remote_image(hostname, path, **kwargs):
Expand All @@ -2741,7 +2826,7 @@ def get_remote_image(hostname, path, **kwargs):
:param kwargs:
:return: image
"""
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
return session.get_image(path, **kwargs)

Expand All @@ -2755,7 +2840,7 @@ def get_time_series_names(hostname, path, **kwargs):
:param kwargs:
:return: json object of column names
"""
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
csv_file = str(session.get_file(path, **kwargs))
csv_file = csv_file.replace("\\r\\n","\r\n")
Expand Down Expand Up @@ -2802,7 +2887,7 @@ def get_remote_video(hostname, vsid):
:param vsid: video uuid
:return: video
"""
sid = get_sid(hostname)
sid, session_type = get_sid(hostname)
with slycat.web.server.remote.get_session(sid) as session:
return session.get_video(vsid)

Expand Down
8 changes: 0 additions & 8 deletions packages/slycat/web/server/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -1113,17 +1113,9 @@ def check_session(sid):
-------
boolean :
"""
# client = cherrypy.request.headers.get("x-forwarded-for")

with session_cache_lock:
_expire_session(sid)
response = True
if sid in session_cache:
session = session_cache[sid]
# Only the originating client can access a session.
# if client != session.client:
# response = False

if sid not in session_cache:
response = False
if response:
Expand Down