Skip to content

Commit

Permalink
successfully working custom auth #549
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthew Letter committed Jan 6, 2016
1 parent 872da69 commit d119d2c
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 117 deletions.
23 changes: 17 additions & 6 deletions packages/slycat/web/server/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,16 @@ def login():
and determins with the user can be authenticated with slycat
:return: authentication status
"""
cherrypy.response.status = "404 no auth found!!!"

if "slycatauth" in cherrypy.request.cookie:
try:
sid = cherrypy.request.cookie["slycatauth"].value
couchdb = slycat.web.server.database.couchdb.connect()
session = couchdb.get("session", sid)
if session is not None:
couchdb.delete(session)
except:
pass

# try and decode the username and password
try:
Expand Down Expand Up @@ -711,15 +720,18 @@ def login():
sid = uuid.uuid4().hex
session = {"created": datetime.datetime.utcnow(), "creator": user_name}
database = slycat.web.server.database.couchdb.connect()
#database.save({"_id": sid, "type": "session", "created": session["created"].isoformat(), "creator": session["creator"]})
database.save({"_id": sid, "type": "session", "created": session["created"].isoformat(), "creator": session["creator"]})

login.sessions[sid] = session

cherrypy.response.cookie["slycatauth"] = sid
cherrypy.response.cookie["slycatauth"]["path"] = "/"
cherrypy.response.cookie["slycatauth"]["secure"] = 1
cherrypy.response.cookie["slycatauth"]["httponly"] = 1
#cherrypy.request.login = user_name
cherrypy.response.status = "200 OK"
cherrypy.request.login = user_name
else:
cherrypy.response.status = "404 no auth found!!!"
return {'session': 'stuff','sid' : sid, 'user_name': user_name, 'password': password, 'success': success, 'groups': groups, 'ip': remote_ip}


Expand All @@ -738,8 +750,8 @@ def logout():
sid = cherrypy.request.cookie["slycatauth"].value

# expire the old cookie
# cherrypy.response.cookie["slycatauth"] = sid
# cherrypy.response.cookie["slycatauth"]['expires'] = 0
cherrypy.response.cookie["slycatauth"] = sid
cherrypy.response.cookie["slycatauth"]['expires'] = 0

couchdb = slycat.web.server.database.couchdb.connect()
session = couchdb.get("session", sid)
Expand All @@ -751,7 +763,6 @@ def logout():
cherrypy.response.status = "403 Forbidden"
except Exception as e:
raise cherrypy.HTTPError("400 Bad Request")
#TODO: log the exception

@cherrypy.tools.json_in(on = True)
def put_model_inputs(mid):
Expand Down
151 changes: 40 additions & 111 deletions web-server/plugins/slycat-standard-authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,119 +34,48 @@ def authenticate(realm, rules=None):
session = None
try:
session = couchdb.get("session", sid)
started = session["created"]
if datetime.datetime.utcnow() - datetime.datetime.strptime(unicode(started), '%Y-%m-%dT%H:%M:%S.%f') > cherrypy.request.app.config["slycat"]["session-timeout"]:
couchdb.delete(session)
# expire the old cookie
cherrypy.response.cookie["slycatauth"] = sid
cherrypy.response.cookie["slycatauth"]['expires'] = 0
session = None
except Exception as e:
cherrypy.log.error("@%s: could not get db session." % (e))
# cherrypy.response.headers["www-authenticate"] = "Basic realm=\"%s\"" % realm
# raise cherrypy.HTTPError(401, "Authentication required.")
# TODO: add redirect

if sid in authenticate.sessions:
started = authenticate.sessions[sid]["created"]
if datetime.datetime.utcnow() - started > cherrypy.request.app.config["slycat"]["session-timeout"]:
del authenticate.sessions[sid]
elif session is None:
cherrypy.log.error("@%s: deleting local session." % (remote_ip))
del authenticate.sessions[sid]
cherrypy.response.headers["www-authenticate"] = "Basic realm=\"%s\"" % realm
raise cherrypy.HTTPError(401, "Authentication required.")
else:
# Ensure that the user is logged correctly ...
cherrypy.request.login = authenticate.sessions[sid]["creator"]
return
else:
# Expired or forged cookie
cherrypy.log.error("@%s: expired/unknown session." % (remote_ip))

# If the client hasn't authenticated, tell them to do so.
authorization = cherrypy.request.headers.get("authorization")
if authorization is None:
#raise cherrypy.HTTPRedirect("/login.html", 307)
cherrypy.response.headers["www-authenticate"] = "Basic realm=\"%s\"" % realm
raise cherrypy.HTTPError(401, "Authentication required.")

# Parse the client's authentication response.
try:
scheme, params = authorization.split(" ", 1)
except:
slycat.email.send_error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 400")
raise cherrypy.HTTPError(400)
if scheme.lower() != "basic":
slycat.email.send_error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 400")
raise cherrypy.HTTPError(400)
try:
username, password = base64_decode(params).split(":", 1)
except:
slycat.email.send_error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 400")
raise cherrypy.HTTPError(400)

cherrypy.log.error("%s@%s: Checking password." % (username, remote_ip))

if authenticate.password_check is None:
if "password-check" not in cherrypy.request.app.config["slycat-web-server"]:
raise cherrypy.HTTPError("500 No password check configured.")
plugin = cherrypy.request.app.config["slycat-web-server"]["password-check"]["plugin"]
args = cherrypy.request.app.config["slycat-web-server"]["password-check"].get("args", [])
kwargs = cherrypy.request.app.config["slycat-web-server"]["password-check"].get("kwargs", {})
if plugin not in slycat.web.server.plugin.manager.password_checks.keys():
slycat.email.send_error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 500 no password check plugin found.")
raise cherrypy.HTTPError("500 No password check plugin found.")
authenticate.password_check = functools.partial(slycat.web.server.plugin.manager.password_checks[plugin], *args, **kwargs)

success, groups = authenticate.password_check(realm, username, password)
if success:
# Apply (optional) authentication rules.
if rules is not None:
deny = None
for operation, category, members in rules:
if operation not in ["allow", "deny"]:
slycat.email.send_error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 500 unknown operation: %s." % operation)
raise cherrypy.HTTPError("500 Unknown operation: %s." % operation)
if category not in ["users", "groups"]:
slycat.email.send_error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 500 unknown category: %s." % category)
raise cherrypy.HTTPError("500 Unknown category: %s." % category)

operation_default = True if operation == "allow" else False
operation_deny = False if operation == "allow" else True

if deny is None:
deny = operation_default
if category == "users":
if username in members:
deny = operation_deny
elif category == "groups":
for group in groups:
if group in members:
deny = operation_deny
break

if deny:
raise cherrypy.HTTPError("403 User denied by authentication rules.")

# Successful authentication, create a session and return.
cherrypy.log.error("%s@%s: Password check succeeded." % (username, remote_ip))

sid = uuid.uuid4().hex
session = {"created": datetime.datetime.utcnow(), "creator": username}
database = slycat.web.server.database.couchdb.connect()
database.save({"_id": sid, "type": "session", "created": session["created"].isoformat(), "creator": session["creator"]})

authenticate.sessions[sid] = session

cherrypy.response.cookie["slycatauth"] = sid
cherrypy.response.cookie["slycatauth"]["path"] = "/"
cherrypy.response.cookie["slycatauth"]["secure"] = 1
cherrypy.response.cookie["slycatauth"]["httponly"] = 1
cherrypy.request.login = username
return # successful authentication

# Authentication failed, tell the client to try again.
cherrypy.log.error("%s@%s: Password check failed." % (username, remote_ip))
cherrypy.response.headers["www-authenticate"] = "Basic realm=\"%s\"" % realm
slycat.email.send_error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 401 authentication failed for user %s." % username)
raise cherrypy.HTTPError(401, "Authentication required.")

authenticate.password_check = None
authenticate.sessions = {}
authenticate.session_cleanup = None
# there was no session time to authenticate
if session is None:
raise cherrypy.HTTPRedirect("/login/slycat-login.html", 307)
return
# # Apply (optional) authentication rules.
# if rules is not None:
# deny = None
# for operation, category, members in rules:
# if operation not in ["allow", "deny"]:
# slycat.email.send_error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 500 unknown operation: %s." % operation)
# raise cherrypy.HTTPError("500 Unknown operation: %s." % operation)
# if category not in ["users", "groups"]:
# slycat.email.send_error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 500 unknown category: %s." % category)
# raise cherrypy.HTTPError("500 Unknown category: %s." % category)
#
# operation_default = True if operation == "allow" else False
# operation_deny = False if operation == "allow" else True
#
# if deny is None:
# deny = operation_default
# if category == "users":
# if username in members:
# deny = operation_deny
# elif category == "groups":
# for group in groups:
# if group in members:
# deny = operation_deny
# break
#
# if deny:
# raise cherrypy.HTTPError("403 User denied by authentication rules.")
#
# # Successful authentication, create a session and return.

context.register_tool("slycat-standard-authentication", "on_start_resource", authenticate)

0 comments on commit d119d2c

Please sign in to comment.