auth: simplify the double invoked auth classes used for permission checking
Also avoid storing request state in the Has Permission instances. The instances er temporary and only used once and there is thus not real problem, but it is simpler and cleaner this way.
controllers: avoid setting request state in controller instances - set it in the thread global request variable
In TurboGears, controllers are singletons and we should avoid using instance variables for any volatile data. Instead, use the "global thread local" request context.
With everything in request, some use of c is dropped.
Note: kallithea/controllers/api/__init__.py still use instance variables that will cause problems with TurboGears.
controllers: avoid setting constants as controller instance variables in __before__
Setting constants in __before__ is a weird pattern and we can do fine without doing it. That makes it more clear that there is no state in the controller instances.
Real constants can just be set at the module level.
Some values depend on configuration and can thus probably not be set as constants at module import time but could perhaps be set in __init__. But reading configuration directly when needed will probably be just as good.
This type of code examples are not present in other files. It is unclear whether this example is still accurate. And it is equally unclear whether they provide real value compared to 'real' code.
The markup in base.html is a bit misleading. The "quick login" drop down menu is not just the quick login box but also the "current user info" box.
When the user is logged in, the "real" quick login box isn't shown and the drop menu's aria-describedby="quick_login_h" thus becomes an invalid reference.
To fix the reference, also call the user info for quick_login_h - that is approximately correct.
hg: return 400 Bad Request for hg commands that not are commands
Avoid throwing bare Exceptions which requires framework specific testing. Instead, return a reasonable http error code and make the test more framework independent.
The "helpful" message will just be a description of the http exception and not sent to the client.
auth: add support for "Bearer" auth scheme (API key variant)
This allows the API key to be passed in a header instead of the query string, reducing the risk of accidental API key leaks:
Authorization: Bearer <api key>
The Bearer authorization scheme is standardized in RFC 6750, though used here outside the full OAuth 2.0 authorization framework. (Full OAuth can still be added later without breaking existing users.)
auth: track API key used for authentication in AuthUser
This allows us to define only once how an API key is passed to the app. We might e.g. allow API keys to be passed in an HTTP header; with this change, we only need to update the code in one place.
Also change the code to verify up front that the API key resolved to a valid and active user, so LoginRequired doesn't need to do that.
Also return plain 403 Forbidden for bad API keys instead of redirecting to the login form, which makes more sense for non-interactive clients (the typical users of API keys).
auth: add AuthUser.is_anonymous, along with some exposition
This reveals the name of the NotAnonymous decorator to be misleading, an unfortunate detail only documented here, but which must be properly resolved in a later changeset.
Note that NotAnonymous behaves as advertised as long as it is used together with LoginRequired, which is always the case in the current code, so there's no actual security issue here, the code is just weird, hard to read and fragile.
---
Some thoughts on cleaning this up in a future changeset: As it turns out, every controller (except the login page!) should be LoginRequired decorated (since it doesn't actually block anonymous users, as long as anonymous access is enabled in the Kallithea config). Thus the most obvious solution would be to move the LoginRequired functionality into BaseController (with an override for LoginController), and delete the decorator entirely. However, LoginRequired does one other thing: it carries information about whether API access is enabled for individual controller methods ("@LoginRequired(api_key=True)"), and also performs the check for this, something which is not easily moved into the base controller class, since the base controller doesn't know which method is about to be called. Possibly that can be determined by poking Pylons, but such code is likely to break with the upcoming TurboGears 2 move. Thus such cleanup is probably better revisited after the switch to TG2.
auth: perform basic HTTP security checks already in BaseController
There's no reason to postpone these to a LoginRequired decorated controller function. This way, they run unconditionally for all subclasses of BaseController (so everything except JSON-RPC and VCS controllers).
My recent changes broke it. Add some band aid to help it. The pull request page might not be a perfect fit for Bootstrap forms, but that is a better approximation than nothing.
tests: give test_pullrequests a test_context in addition to the usual app_fixture
test_pullrequests has unit-ish tests that invoke library functions directly ... but these happen to require localization initialized. For TG2 we only have localization initialized when we have a test_context. Thus, additionally wrap these tests in a test_context.
The M class is actually a wrapper around formencode.api.Validator.message, inserting a translator into the 'state' object. Setting a translator into the state object is indeed what is mentioned in the formencode docs.
But, if you work this way, the custom state should be set both for custom validators, as well as for validators that are simple wrappers around formencode's default validators (for example wrappers that just set a custom message string). And the latter is what Kallithea is currently _not_ doing.
Also, when using formencode.api.Validator.message correctly, you should not use the translator function _ on your validator strings manually.
Remove the inconsistency in Kallithea validators as follows: - remove M and StateObj classes - replace the usage of M by direct calls to self.message (which is now no longer in charge of translating but simply of mapping a keyword onto the right message) - translation will be done by explicit _ calls at Kallithea side, so that formencode directly receives translated strings.
forms: wrap LoginForm inside function like other forms
All forms except LoginForm are wrapped inside a function. The original purpose of this wrapping seems to be the ability to pass parameters to tweak the form.
But, this also has another desired effect: translation of strings wrapped with _ is no longer attempted when reading the class definition, but only when the function is instantiated. In the former case, it is not guaranteed that a translator is actually available because we are not running in standard application context.