Authentication for developer-oriented tools¶
- Title:
Developer Auth
- Author:
Ian Bicking <ianb@colorstudy.com>
- Discussions-To:
Python Web-SIG <web-sig@python.org>
- Status:
Proposed
- Created:
31-Mar-2008
Abstract¶
Many tools can be written for a WSGI stack which should only accessible to developers. For example, an interactive debugger in response to sessions. Or a template system might display the underlying filenames that created a page. Or profiling data. In some cases there are security implications to exposing this data, in other cases it is harmless but undesirable to show this information to normal users. This specification offers a single, simple way to detect if a user should be presented with this information.
Rationale¶
So far these tools have been controlled by configuration, e.g.,
debug = True
, or --debug
on the command line. This
works but can be dangerous, as a deployer or developer can forget to
turn off tools. Or, if it is controlled through Python code, it can
be difficult to enable on a site that wasn’t intended to have the tool
on, e.g., if you want to debug a live site because you can’t reproduce
a problem in development. Also, configuration doesn’t allow some
people to see these development tools while hiding them from other
people. A per-request and secure authentication method is more
desirable.
This could be implemented using application-specific authentication methods and permission levels. This is undesirable because often debugging is orthogonal to users – you may want to debug a problem only present when a low-permission or anonymous user is visiting the site. Also it is difficult to keep application and debugging permissions coherent, which is probably why this technique is not used by any tools.
Specification¶
Debugging tools should look for a key
x-wsgiorg.developer_user
. This will contain some kind of
user name. If it is empty or not present, then debugging tools should
not activate themselves, or should not expose any information in the
browser.
The user name can be used in logging, but all users are considered to
have the same permission level (total access). The username must be a
str
, but its contents are not constrained (an IP address, for
example, would be acceptable, or a name and email, with an embedded
space).
If a URL is protected except for developers, applications should
simply return 403 Forbidden
. Seamless login is not part of this
specification or its goals. Some systems may be IP-controlled, for
example, and no login is possible.
Example¶
This is a simple exception catcher that uses the key:
import sys, traceback
class CatchExceptions(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
if not environ.get('x-wsgiorg.developer_user'):
return self.app(environ, start_response)
try:
return self.app(environ, start_response)
except:
start_response('500 Server Error', [('content-type', 'text/plain')],
sys.exc_info())
return [traceback.format_exc()]
Here is a IP-restricted middleware that sets the key:
class IPDeveloper(object):
def __init__(self, app, ips=('127.0.0.1',)):
self.app = app
self.ips = ips
def __call__(self, environ, start_response):
if environ.get('REMOTE_ADDR') in self.ips:
environ['x-wsgiorg.developer_user'] = environ['REMOTE_ADDR']
return self.app(environ, start_response)
Problems¶
With security by obscurity in mind, it might be best if login methods weren’t clear. With ease of use in mind, easy logins are best.
There’s no levels of access. Everyone is assumed to have complete access. (You could add another custom key if you want to share extra information between the authentication and application layer.)
This encourages people to do production deployments with debugging tools enabled.
Other Possibilities¶
Configuration
Conditional middleware composition
Application login systems
Some other generalized authentication system (AuthKit, etc).
Open Issues¶
Should
401 Authorization Required
be returned? Potentially withWWW-Authenticate: x-wsgiorg.developer_user
. This would signal to the middleware that a login should occur, which it may or may not ignore (it could translate that to403 Forbidden
). This would make, for example, HTTP Basic authentication doable (since that authentication is per-request, and so you can’t detect if a user already has logged in). But HTTP Basic would probably be inappropriate for many systems, where a page is filtered by authentication, it isn’t blocked.
Implementations¶
DevAuth implements the authentication portion of this system. Deliverance and Cabochon both use DevAuth for access to backend logging and controls.
DevAuth implements a login form (which uses a cookie) and IP restrictions. This allows developers from selected IP addresses to login. No links are provided to the login form, instead developers must know the location, or it should be documented in applications using DevAuth. Similarly there’s no way for applications to reject a request and suggest a login; when a user accesses something they are not allowed to access the applications simply generate 403 Forbidden. This is unlike user-oriented login forms which helpful; this is distinctly unhelpful.