def authbasic(checkpassword, authmethod=""): """Filter used to restrict access to resource via HTTP basic auth.""" # Check if logged-in. if cherrypy.session.get("username"): # @UndefinedVariable # page passes credentials; allow to be processed return False # Proceed with basic authentication. request = cherrypy.serving.request auth_header = request.headers.get('authorization') if auth_header is not None: try: scheme, params = auth_header.split(' ', 1) if scheme.lower() == 'basic': username, password = base64_decode(params).split(':', 1) error_msg = checkpassword(username, password) if error_msg: logger.info('basic auth fail for %s: %s' % (username, error_msg)) else: logger.info('basic auth succeeded for %s' % (username)) request.login = username return # successful authentication # split() error, base64.decodestring() error except (ValueError, binascii.Error): raise cherrypy.HTTPError(400, 'Bad Request') # Respond with 401 status and a WWW-Authenticate header cherrypy.serving.response.headers['www-authenticate'] = 'Basic realm="rdiffweb"' raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
def authbasic(checkpassword): """Filter used to restrict access to resource via HTTP basic auth.""" # Check if logged-in. if cherrypy.session.get("user"): # @UndefinedVariable # page passes credentials; allow to be processed return False # Proceed with basic authentication. request = cherrypy.serving.request auth_header = request.headers.get('authorization') if auth_header is not None: try: scheme, params = auth_header.split(' ', 1) if scheme.lower() == 'basic': username, password = base64_decode(params).split(':', 1) error_msg = checkpassword(username, password) if error_msg: logger.info('basic auth fail for %s: %s', username, error_msg) else: logger.info('basic auth succeeded for %s', username) request.login = username return # successful authentication # split() error, base64.decodestring() error except (ValueError, binascii.Error): raise cherrypy.HTTPError(400, 'Bad Request') # Respond with 401 status and a WWW-Authenticate header cherrypy.serving.response.headers[ 'www-authenticate'] = 'Basic realm="rdiffweb"' raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
def decode_username_and_password(): """ decode the url from the json that was passed to us :return: decoded url and password as a tuple """ try: # cherrypy.log.error("decoding username and password") user_name = base64_decode(cherrypy.request.json["user_name"]) password = base64_decode(cherrypy.request.json["password"]) # 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("username and password could not be decoded") slycat.email.send_error( "slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 400") raise cherrypy.HTTPError(400) return user_name, password
def basic_auth(realm, checkpassword, debug=False): """A CherryPy tool which hooks at before_handler to perform HTTP Basic Access Authentication, as specified in :rfc:`2617`. If the request has an 'authorization' header with a 'Basic' scheme, this tool attempts to authenticate the credentials supplied in that header. If the request has no 'authorization' header, or if it does but the scheme is not 'Basic', or if authentication fails, the tool sends a 401 response with a 'WWW-Authenticate' Basic header. realm A string containing the authentication realm. checkpassword A callable which checks the authentication credentials. Its signature is checkpassword(realm, username, password). where username and password are the values obtained from the request's 'authorization' header. If authentication succeeds, checkpassword returns True, else it returns False. """ if '"' in realm: raise ValueError('Realm cannot contain the " (quote) character.') request = cherrypy.serving.request auth_header = request.headers.get('authorization') if auth_header is not None: try: scheme, params = auth_header.split(' ', 1) if scheme.lower() == 'basic': username, password = base64_decode(params).split(':', 1) if checkpassword(realm, username, password): if debug: cherrypy.log('Auth succeeded', 'TOOLS.AUTH_BASIC') request.login = username return # successful authentication except (ValueError, binascii.Error): # split() error, base64.decodestring() error raise cherrypy.HTTPError(400, 'Bad Request') # Respond with 401 status and a WWW-Authenticate header cherrypy.serving.response.headers[ 'www-authenticate'] = 'Basic realm="%s"' % realm raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
def basic_auth(realm, checkpassword, debug=False): """A CherryPy tool which hooks at before_handler to perform HTTP Basic Access Authentication, as specified in :rfc:`2617`. If the request has an 'authorization' header with a 'Basic' scheme, this tool attempts to authenticate the credentials supplied in that header. If the request has no 'authorization' header, or if it does but the scheme is not 'Basic', or if authentication fails, the tool sends a 401 response with a 'WWW-Authenticate' Basic header. realm A string containing the authentication realm. checkpassword A callable which checks the authentication credentials. Its signature is checkpassword(realm, username, password). where username and password are the values obtained from the request's 'authorization' header. If authentication succeeds, checkpassword returns True, else it returns False. """ if '"' in realm: raise ValueError('Realm cannot contain the " (quote) character.') request = cherrypy.serving.request auth_header = request.headers.get('authorization') if auth_header is not None: try: scheme, params = auth_header.split(' ', 1) if scheme.lower() == 'basic': username, password = base64_decode(params).split(':', 1) if checkpassword(realm, username, password): if debug: cherrypy.log('Auth succeeded', 'TOOLS.AUTH_BASIC') request.login = username return # successful authentication # split() error, base64.decodestring() error except (ValueError, binascii.Error): raise cherrypy.HTTPError(400, 'Bad Request') # Respond with 401 status and a WWW-Authenticate header cherrypy.serving.response.headers[ 'www-authenticate'] = 'Basic realm="%s"' % realm raise cherrypy.HTTPError( 401, "You are not authorized to access that resource")
def basic_auth(realm, checkpassword, debug = False): if '"' in realm: raise ValueError('Realm cannot contain the " (quote) character.') request = cherrypy.serving.request auth_header = request.headers.get('authorization') if auth_header is not None: try: scheme, params = auth_header.split(' ', 1) if scheme.lower() == 'basic': username, password = base64_decode(params).split(':', 1) if checkpassword(realm, username, password): if debug: cherrypy.log('Auth succeeded', 'TOOLS.AUTH_BASIC') request.login = username return except (ValueError, binascii.Error): raise cherrypy.HTTPError(400, 'Bad Request') cherrypy.serving.response.headers['www-authenticate'] = 'Basic realm="%s"' % realm raise cherrypy.HTTPError(401, 'You are not authorized to access that resource')
def _parseBasicAuthorization(auth_params): username, password = base64_decode(auth_params).split(':', 1) return {'username': username, 'password': password}
def _parseBasicAuthorization(auth_params): username, password = base64_decode(auth_params).split(":", 1) return {"username": username, "password": password}
def basic_auth(realm, checkpassword, debug=False): """A CherryPy tool which hooks at before_handler to perform HTTP Basic Access Authentication, as specified in :rfc:`2617`. If the request has an 'authorization' header with a 'Basic' scheme, this tool attempts to authenticate the credentials supplied in that header. If the request has no 'authorization' header, or if it does but the scheme is not 'Basic', or if authentication fails, the tool sends a 401 response with a 'WWW-Authenticate' Basic header. realm A string containing the authentication realm. checkpassword A callable which checks the authentication credentials. Its signature is checkpassword(realm, username, password). where username and password are the values obtained from the request's 'authorization' header. If authentication succeeds, checkpassword returns True, else it returns False. """ if '"' in realm: raise ValueError('Realm cannot contain the " (quote) character.') request = cherrypy.serving.request auth_header = request.headers.get('authorization') if auth_header is not None: # split() error, base64.decodestring() error msg = 'Bad Request' with cherrypy.HTTPError.handle((ValueError, binascii.Error), 400, msg): scheme, params = auth_header.split(' ', 1) if scheme.lower() == 'basic': username, password = base64_decode(params).split(':', 1) # Attempt to decode as utf-8. This will either convert password *and* username or # none of them. try: username, password = decode_utf8(username), decode_utf8(password) except UnicodeDecodeError: pass if checkpassword(realm, username, password): if debug: cherrypy.log('Auth succeeded', 'TOOLS.AUTH_BASIC') request.login = username return # successful authentication # Respond with 401 status and a WWW-Authenticate header cherrypy.serving.response.headers[ 'www-authenticate'] = 'Basic realm="%s"' % realm # Attempt to bring the browser to switch charset in conformance with RFC-7617 # https://tools.ietf.org/html/rfc7617 # # As of 2018-01-02: Firefox 57.0.2 (32-Bit), curl 7.56.1, Google-Chrome 63.0.3239.108, # Internet Explorer 11.786.15063.0 and Edge 40.15063.674.0 will ignore it. # cherrypy.serving.response.headers[ # 'www-authenticate'] = 'Basic realm="%s", charset="UTF-8"' % realm raise cherrypy.HTTPError( 401, 'You are not authorized to access that resource')
def authenticate(realm, rules=None): # Sanity-check our inputs. if '"' in realm: slycat.email.send_error( "slycat-standard-authentication.py authenticate", "Realm cannot contain the \" (quote) character.") raise ValueError("Realm cannot contain the \" (quote) character.") # Require a secure connection. if not (cherrypy.request.scheme == "https" or cherrypy.request.headers.get("x-forwarded-proto") == "https"): slycat.email.send_error( "slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 403 secure connection required.") raise cherrypy.HTTPError("403 Secure connection required.") # Get the client ip, which might be forwarded by a proxy. remote_ip = cherrypy.request.headers.get( "x-forwarded-for" ) if "x-forwarded-for" in cherrypy.request.headers else cherrypy.request.rem # See if the client already has a valid session. if "slycatauth" in cherrypy.request.cookie: sid = cherrypy.request.cookie["slycatauth"].value 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] 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: cherrypy.response.headers[ "www-authenticate"] = "Basic realm=\"%s\"" % realm # Not sure if email should be sent for this error: it is generated everytime a new user hit the homepage... # slycat.email.send_error("slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 401 authentication required.") 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 required.") raise cherrypy.HTTPError(401, "Authentication required.")
def authenticate(realm, rules=None): # Sanity-check our inputs. if '"' in realm: slycat.email.send_error( "slycat-standard-authentication.py authenticate", 'Realm cannot contain the " (quote) character.' ) raise ValueError('Realm cannot contain the " (quote) character.') # Require a secure connection. if not (cherrypy.request.scheme == "https" or cherrypy.request.headers.get("x-forwarded-proto") == "https"): slycat.email.send_error( "slycat-standard-authentication.py authenticate", "cherrypy.HTTPError 403 secure connection required." ) raise cherrypy.HTTPError("403 Secure connection required.") # Get the client ip, which might be forwarded by a proxy. remote_ip = ( cherrypy.request.headers.get("x-forwarded-for") if "x-forwarded-for" in cherrypy.request.headers else cherrypy.request.rem ) # See if the client already has a valid session. if "slycatauth" in cherrypy.request.cookie: sid = cherrypy.request.cookie["slycatauth"].value 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] 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: 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.")
def _parseBasicAuthorization (auth_params): username, password = base64_decode(auth_params).split(":", 1) return {"username": username, "password": password}
def basic_auth(realm, checkpassword, debug=False, accept_charset='utf-8'): """A CherryPy tool which hooks at before_handler to perform HTTP Basic Access Authentication, as specified in :rfc:`2617` and :rfc:`7617`. If the request has an 'authorization' header with a 'Basic' scheme, this tool attempts to authenticate the credentials supplied in that header. If the request has no 'authorization' header, or if it does but the scheme is not 'Basic', or if authentication fails, the tool sends a 401 response with a 'WWW-Authenticate' Basic header. realm A string containing the authentication realm. checkpassword A callable which checks the authentication credentials. Its signature is checkpassword(realm, username, password). where username and password are the values obtained from the request's 'authorization' header. If authentication succeeds, checkpassword returns True, else it returns False. """ fallback_charset = 'ISO-8859-1' if '"' in realm: raise ValueError('Realm cannot contain the " (quote) character.') request = cherrypy.serving.request auth_header = request.headers.get('authorization') if auth_header is not None: # split() error, base64.decodestring() error msg = 'Bad Request' with cherrypy.HTTPError.handle((ValueError, binascii.Error), 400, msg): scheme, params = auth_header.split(' ', 1) if scheme.lower() == 'basic': decoded_params = base64_decode(params) decoded_params = ntob(decoded_params) last_err = None for charset in (accept_charset, fallback_charset): try: decoded_params = tonative(decoded_params, charset) break except ValueError as ve: last_err = ve else: raise last_err decoded_params = ntou(decoded_params) decoded_params = unicodedata.normalize('NFC', decoded_params) decoded_params = tonative(decoded_params) username, password = decoded_params.split(':', 1) if checkpassword(realm, username, password): if debug: cherrypy.log('Auth succeeded', 'TOOLS.AUTH_BASIC') request.login = username return # successful authentication charset = accept_charset.upper() charset_declaration = ((', charset="%s"' % charset) if charset != fallback_charset else '') # Respond with 401 status and a WWW-Authenticate header cherrypy.serving.response.headers['www-authenticate'] = ( 'Basic realm="%s"%s' % (realm, charset_declaration)) raise cherrypy.HTTPError(401, 'You are not authorized to access that resource')