aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatěj Cepl <mcepl@cepl.eu>2017-10-27 09:23:17 +0000
committerMatěj Cepl <mcepl@cepl.eu>2017-10-27 09:23:17 +0000
commit4db24aa71fa2dded9e2c26fcacd3a8659eb62b7f (patch)
tree3d94896d1a6e0d4b76668890e55ebed094207c20
parent6f03fbb005da75cd022e4a0d7eed1df1070b3974 (diff)
parent4d88ff5b6cd8b97ad296a8cc47fd054692354a38 (diff)
downloadbugseverywhere-4db24aa71fa2dded9e2c26fcacd3a8659eb62b7f.tar.gz
Merge branch '23f5287a-6c5e-4484-be6f-bb7f38a48180' into 'master'
Remove --auth option from server commands Closes #7 See merge request bugseverywhere/bugseverywhere!8
-rw-r--r--.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/comments/784d4a1c-cef7-40b5-b88f-cbe44ce33978/body1
-rw-r--r--.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/comments/784d4a1c-cef7-40b5-b88f-cbe44ce33978/values29
-rw-r--r--.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/values2
-rw-r--r--libbe/command/html.py2
-rw-r--r--libbe/command/serve_commands.py15
-rw-r--r--libbe/command/serve_storage.py20
-rw-r--r--libbe/util/wsgi.py213
7 files changed, 34 insertions, 248 deletions
diff --git a/.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/comments/784d4a1c-cef7-40b5-b88f-cbe44ce33978/body b/.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/comments/784d4a1c-cef7-40b5-b88f-cbe44ce33978/body
new file mode 100644
index 0000000..231d153
--- /dev/null
+++ b/.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/comments/784d4a1c-cef7-40b5-b88f-cbe44ce33978/body
@@ -0,0 +1 @@
+Closing this as WONTFIX now that --auth has been removed.
diff --git a/.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/comments/784d4a1c-cef7-40b5-b88f-cbe44ce33978/values b/.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/comments/784d4a1c-cef7-40b5-b88f-cbe44ce33978/values
new file mode 100644
index 0000000..34e3951
--- /dev/null
+++ b/.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/comments/784d4a1c-cef7-40b5-b88f-cbe44ce33978/values
@@ -0,0 +1,29 @@
+{
+
+
+
+
+
+
+ "Author": "Matthew Fernandez <matthew.fernandez@gmail.com>",
+
+
+
+
+
+
+ "Content-type": "text/plain",
+
+
+
+
+
+
+ "Date": "Fri, 27 Oct 2017 03:33:18 +0000"
+
+
+
+
+
+
+}
diff --git a/.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/values b/.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/values
index 557e093..fc8855b 100644
--- a/.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/values
+++ b/.be/bea86499-824e-4e77-b085-2d581fa9ccab/bugs/c1b76442-eab6-4796-9517-8454425d7757/values
@@ -26,7 +26,7 @@
- "status": "open",
+ "status": "wontfix",
diff --git a/libbe/command/html.py b/libbe/command/html.py
index 5186417..3dfeb75 100644
--- a/libbe/command/html.py
+++ b/libbe/command/html.py
@@ -794,7 +794,6 @@ class HTML (libbe.util.wsgi.ServerCommand):
if option.name not in [
'read-only',
'notify',
- 'auth',
]]
self.options.extend([
@@ -854,7 +853,6 @@ class HTML (libbe.util.wsgi.ServerCommand):
# provide defaults for the dropped options
params['read-only'] = True
params['notify'] = None
- params['auth'] = None
return super(HTML, self)._run(**params)
def _get_app(self, logger, storage, index_file='', generation_time=None,
diff --git a/libbe/command/serve_commands.py b/libbe/command/serve_commands.py
index 30b4a69..c2a1be8 100644
--- a/libbe/command/serve_commands.py
+++ b/libbe/command/serve_commands.py
@@ -80,7 +80,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
# handlers
def run(self, environ, start_response):
- self.check_login(environ)
data = self.post_data(environ)
source = 'post'
try:
@@ -113,15 +112,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
def _parse_post(self, post):
return libbe.storage.util.mapfile.parse(post)
- def check_login(self, environ):
- user = environ.get('be-auth.user', None)
- if user is not None: # we're running under AuthenticationApp
- if environ['REQUEST_METHOD'] == 'POST':
- # TODO: better detection of commands requiring writes
- if user == 'guest' or self.storage.is_writeable() == False:
- raise _Unauthorized() # only non-guests allowed to write
- # allow read-only commands for all users
-
def _notify(self, environ, command, id, params):
message = self._format_notification(environ, command, id, params)
self._submit_notification(message)
@@ -179,9 +169,8 @@ And in another terminal (or after backgrounding the server)::
$ be --server http://localhost:8000/ list
If you bind your server to a public interface, take a look at the
-``--read-only`` option or the combined ``--ssl --auth FILE``
-options so other people can't mess with your repository. If you do use
-authentication, you'll need to send in your username and password::
+``--read-only`` option so other people can't mess with your
+repository.
$ be --server http://username:password@localhost:8000/ list
"""
diff --git a/libbe/command/serve_storage.py b/libbe/command/serve_storage.py
index 086cb84..e32c5bc 100644
--- a/libbe/command/serve_storage.py
+++ b/libbe/command/serve_storage.py
@@ -95,7 +95,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
# handlers
def add(self, environ, start_response):
- self.check_login(environ)
data = self.post_data(environ)
source = 'post'
id = self.data_get_id(data, source=source)
@@ -110,7 +109,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
return self.ok_response(environ, start_response, None)
def exists(self, environ, start_response):
- self.check_login(environ)
data = self.query_data(environ)
source = 'query'
id = self.data_get_id(data, source=source)
@@ -120,7 +118,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
return self.ok_response(environ, start_response, content)
def remove(self, environ, start_response):
- self.check_login(environ)
data = self.post_data(environ)
source = 'post'
id = self.data_get_id(data, source=source)
@@ -135,7 +132,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
return self.ok_response(environ, start_response, None)
def ancestors(self, environ, start_response):
- self.check_login(environ)
data = self.query_data(environ)
source = 'query'
id = self.data_get_id(data, source=source)
@@ -145,7 +141,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
return self.ok_response(environ, start_response, content)
def children(self, environ, start_response):
- self.check_login(environ)
data = self.query_data(environ)
source = 'query'
id = self.data_get_id(data, default=None, source=source)
@@ -155,7 +150,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
return self.ok_response(environ, start_response, content)
def get(self, environ, start_response):
- self.check_login(environ)
data = self.query_data(environ)
source = 'query'
try:
@@ -170,7 +164,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
headers=[('X-BE-Version', be_version)])
def set(self, environ, start_response):
- self.check_login(environ)
data = self.post_data(environ)
try:
id = environ['be-server.url_args'][0]
@@ -185,7 +178,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
return self.ok_response(environ, start_response, None)
def commit(self, environ, start_response):
- self.check_login(environ)
data = self.post_data(environ)
if not 'summary' in data:
raise libbe.util.wsgi.HandlerError(
@@ -211,7 +203,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
return self.ok_response(environ, start_response, revision)
def revision_id(self, environ, start_response):
- self.check_login(environ)
data = self.query_data(environ)
source = 'query'
index = int(self.data_get_string(
@@ -221,7 +212,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
return self.ok_response(environ, start_response, content)
def changed(self, environ, start_response):
- self.check_login(environ)
data = self.query_data(environ)
source = 'query'
revision = self.data_get_string(
@@ -231,7 +221,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
return self.ok_response(environ, start_response, content)
def version(self, environ, start_response):
- self.check_login(environ)
data = self.query_data(environ)
source = 'query'
revision = self.data_get_string(
@@ -239,15 +228,6 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
content = self.storage.storage_version(revision)
return self.ok_response(environ, start_response, content)
- # handler utility functions
- def check_login(self, environ):
- user = environ.get('be-auth.user', None)
- if user is not None: # we're running under AuthenticationApp
- if environ['REQUEST_METHOD'] == 'POST':
- if user == 'guest' or self.storage.is_writeable() == False:
- raise _Unauthorized() # only non-guests allowed to write
- # allow read-only commands for all users
-
def _notify(self, environ, command, id, params):
message = self._format_notification(environ, command, id, params)
self._submit_notification(message)
diff --git a/libbe/util/wsgi.py b/libbe/util/wsgi.py
index dcddcf3..2e97941 100644
--- a/libbe/util/wsgi.py
+++ b/libbe/util/wsgi.py
@@ -353,81 +353,6 @@ class UppercaseHeaderApp (WSGI_Middleware):
return self.app(environ, start_response)
-class AuthenticationApp (WSGI_Middleware):
- """WSGI middleware for handling user authentication.
- """
- def __init__(self, realm, setting='be-auth', users=None, *args, **kwargs):
- super(AuthenticationApp, self).__init__(*args, **kwargs)
- self.realm = realm
- self.setting = setting
- self.users = users
-
- def _call(self, environ, start_response):
- environ['{}.realm'.format(self.setting)] = self.realm
- try:
- username = self.authenticate(environ)
- environ['{}.user'.format(self.setting)] = username
- environ['{}.user.name'.format(self.setting)] = self.users[username].name
- return self.app(environ, start_response)
- except Unauthorized, e:
- return self.error(environ, start_response,
- e.code, e.msg, e.headers)
-
- def authenticate(self, environ):
- """Handle user-authentication sent in the "Authorization" header.
-
- This function implements ``Basic`` authentication as described in
- HTTP/1.0 specification [1]_ . Do not use this module unless you
- are using SSL, as it transmits unencrypted passwords.
-
- .. [1] http://www.w3.org/Protocols/HTTP/1.0/draft-ietf-http-spec.html#BasicAA
-
- Examples
- --------
-
- >>> users = Users()
- >>> users.add_user(User('Aladdin', 'Big Al', password='open sesame'))
- >>> app = AuthenticationApp(app=None, realm='Dummy Realm', users=users)
- >>> app.authenticate({'HTTP_AUTHORIZATION':'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='})
- 'Aladdin'
- >>> app.authenticate({'HTTP_AUTHORIZATION':'Basic AAAAAAAAAAAAAAAAAAAAAAAAAA=='})
-
- Notes
- -----
-
- Code based on authkit/authenticate/basic.py
- (c) 2005 Clark C. Evans.
- Released under the MIT License:
- http://www.opensource.org/licenses/mit-license.php
- """
- authorization = environ.get('HTTP_AUTHORIZATION', None)
- if authorization is None:
- raise Unauthorized('Authorization required')
- try:
- authmeth,auth = authorization.split(' ', 1)
- except ValueError:
- return None
- if 'basic' != authmeth.lower():
- return None # non-basic HTTP authorization not implemented
- auth = auth.strip().decode('base64')
- try:
- username,password = auth.split(':', 1)
- except ValueError:
- return None
- if self.authfunc(environ, username, password):
- return username
-
- def authfunc(self, environ, username, password):
- if not username in self.users:
- return False
- if self.users[username].valid_login(password):
- if self.logger is not None:
- self.logger.log(self.log_level,
- 'Authenticated {}'.format(self.users[username].name))
- return True
- return False
-
-
class WSGI_DataObject (WSGI_Object):
"""Useful WSGI utilities for handling data (POST, QUERY) and
returning responses.
@@ -544,41 +469,6 @@ class WSGI_AppObject (WSGI_Object):
return self.default_handler(environ, start_response)
-class AdminApp (WSGI_AppObject, WSGI_DataObject, WSGI_Middleware):
- """WSGI middleware for managing users
-
- Changing passwords, usernames, etc.
- """
- def __init__(self, users=None, setting='be-auth', *args, **kwargs):
- handler = ('^admin/?', self.admin)
- if 'urls' not in kwargs:
- kwargs['urls'] = [handler]
- else:
- kwargs.urls.append(handler)
- super(AdminApp, self).__init__(*args, **kwargs)
- self.users = users
- self.setting = setting
-
- def admin(self, environ, start_response):
- if not '{}.user'.format(self.setting) in environ:
- realm = envirion.get('{}.realm'.format(self.setting))
- raise Unauthenticated(realm=realm)
- uname = environ.get('{}.user'.format(self.setting))
- user = self.users[uname]
- data = self.post_data(environ)
- source = 'post'
- name = self.data_get_string(
- data, 'name', default=None, source=source)
- if name is not None:
- self.users[uname].set_name(name)
- password = self.data_get_string(
- data, 'password', default=None, source=source)
- if password is not None:
- self.users[uname].set_password(password)
- self.users.save()
- return self.ok_response(environ, start_response, None)
-
-
class SilentRequestHandler (wsgiref.simple_server.WSGIRequestHandler):
def log_message(self, format, *args):
pass
@@ -631,15 +521,6 @@ class ServerCommand (libbe.command.base.Command):
name='notify', metavar='EMAIL-COMMAND', default=None)),
libbe.command.Option(name='ssl', short_name='s',
help='Use CherryPy to serve HTTPS (HTTP over SSL/TLS)'),
- libbe.command.Option(name='auth', short_name='a',
- help=('Require authentication. FILE should be a file '
- 'containing colon-separated '
- 'UNAME:USER:sha1(PASSWORD) lines, for example: '
- '"jdoe:John Doe <jdoe@example.com>:'
- 'd99f8e5a4b02dc25f49da2ea67c0034f61779e72"'),
- arg=libbe.command.Argument(
- name='auth', metavar='FILE', default=None,
- completion_callback=libbe.command.util.complete_path)),
])
def _run(self, **params):
@@ -655,15 +536,9 @@ class ServerCommand (libbe.command.base.Command):
if params['read-only']:
writeable = storage.writeable
storage.writeable = False
- if params['auth']:
- self._check_restricted_access(storage, params['auth'])
- users = Users(params['auth'])
+ users = Users()
users.load()
app = self._get_app(logger=self.logger, storage=storage, **params)
- if params['auth']:
- app = AdminApp(app, users=users, logger=self.logger)
- app = AuthenticationApp(app, realm=storage.repo,
- users=users, logger=self.logger)
app = UppercaseHeaderApp(app, logger=self.logger)
server,details = self._get_server(params, app)
details['repo'] = storage.repo
@@ -954,92 +829,6 @@ if libbe.TESTING:
self.failUnless('child_app' in log, log)
self.failUnless('ValueError: Dummy Error' in log, log)
-
- class AdminAppTestCase (WSGITestCase):
- def setUp(self):
- WSGITestCase.setUp(self)
- self.users = Users()
- self.users.add_user(
- User('Aladdin', 'Big Al', password='open sesame'))
- self.users.add_user(
- User('guest', 'Guest', password='guestpass'))
- def child_app(environ, start_response):
- pass
- app = AdminApp(
- app=child_app, users=self.users, logger=self.logger)
- app = AuthenticationApp(
- app=app, realm='Dummy Realm', users=self.users,
- logger=self.logger)
- self.app = UppercaseHeaderApp(app=app, logger=self.logger)
-
- def basic_auth(self, uname, password):
- """HTTP basic authorization string"""
- return 'Basic {}'.format(
- '{}:{}'.format(uname, password).encode('base64'))
-
- def test_new_name(self):
- self.getURL(
- self.app, '/admin/', method='POST',
- data_dict={'name':'Prince Al'},
- environ={'HTTP_Authorization':
- self.basic_auth('Aladdin', 'open sesame')})
- self.failUnless(self.status == '200 OK', self.status)
- self.failUnless(self.response_headers == [],
- self.response_headers)
- self.failUnless(self.exc_info == None, self.exc_info)
- self.failUnless(self.users['Aladdin'].name == 'Prince Al',
- self.users['Aladdin'].name)
- self.failUnless(self.users.changed == True,
- self.users.changed)
-
- def test_new_password(self):
- self.getURL(
- self.app, '/admin/', method='POST',
- data_dict={'password':'New Pass'},
- environ={'HTTP_Authorization':
- self.basic_auth('Aladdin', 'open sesame')})
- self.failUnless(self.status == '200 OK', self.status)
- self.failUnless(self.response_headers == [],
- self.response_headers)
- self.failUnless(self.exc_info == None, self.exc_info)
- self.failUnless((self.users['Aladdin'].passhash ==
- self.users['Aladdin'].hash('New Pass')),
- self.users['Aladdin'].passhash)
- self.failUnless(self.users.changed == True,
- self.users.changed)
-
- def test_guest_name(self):
- self.getURL(
- self.app, '/admin/', method='POST',
- data_dict={'name':'SPAM'},
- environ={'HTTP_Authorization':
- self.basic_auth('guest', 'guestpass')})
- self.failUnless(self.status.startswith('403 '), self.status)
- self.failUnless(self.response_headers == [
- ('Content-Type', 'text/plain')],
- self.response_headers)
- self.failUnless(self.exc_info == None, self.exc_info)
- self.failUnless(self.users['guest'].name == 'Guest',
- self.users['guest'].name)
- self.failUnless(self.users.changed == False,
- self.users.changed)
-
- def test_guest_password(self):
- self.getURL(
- self.app, '/admin/', method='POST',
- data_dict={'password':'SPAM'},
- environ={'HTTP_Authorization':
- self.basic_auth('guest', 'guestpass')})
- self.failUnless(self.status.startswith('403 '), self.status)
- self.failUnless(self.response_headers == [
- ('Content-Type', 'text/plain')],
- self.response_headers)
- self.failUnless(self.exc_info == None, self.exc_info)
- self.failUnless(self.users['guest'].name == 'Guest',
- self.users['guest'].name)
- self.failUnless(self.users.changed == False,
- self.users.changed)
-
unitsuite =unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()])