diff --git a/docs/oauth1.rst b/docs/oauth1.rst index a1b9f082..7d612bc9 100644 --- a/docs/oauth1.rst +++ b/docs/oauth1.rst @@ -438,7 +438,7 @@ Just like request token handler, you can add more data in access token. Protect Resource ---------------- -Protect the resource of a user with ``require_oauth`` decorator now:: +Protect a resource with ``require_oauth`` decorator now:: @app.route('/api/me') @oauth.require_oauth('email') @@ -451,9 +451,21 @@ Protect the resource of a user with ``require_oauth`` decorator now:: def user(username): user = User.query.filter_by(username=username).first() return jsonify(email=user.email, username=user.username) + + @app.route('/api/client') + @oauth.require_oauth(require_user=False) + def client(): + client = Client.query.filter_by(client_key=request.oauth.client_key).first() + return jsonify(client_key=client.client_key, + name=client.name, + description=client.description, + user_id=client.user_id) The decorator accepts a list of realms, only the clients with the given realms -can access the defined resources. +can access the defined resources. Additionally, the decorator supports a require_user +parameter that defaults to True. By setting this to false, this implements "0-legged" +oauth which allows an authorized client to make requests without the context of a user. + .. versionchanged:: 0.5.0 diff --git a/flask_oauthlib/provider/oauth1.py b/flask_oauthlib/provider/oauth1.py index 7886a6be..9736ee61 100644 --- a/flask_oauthlib/provider/oauth1.py +++ b/flask_oauthlib/provider/oauth1.py @@ -14,7 +14,7 @@ from flask import request, redirect, url_for from flask import make_response, abort from oauthlib.oauth1 import RequestValidator -from oauthlib.oauth1 import WebApplicationServer as Server +from oauthlib.oauth1 import WebApplicationServer, SignatureOnlyEndpoint from oauthlib.oauth1 import SIGNATURE_HMAC, SIGNATURE_RSA from oauthlib.common import to_unicode, add_params_to_uri, urlencode from oauthlib.oauth1.rfc5849 import errors @@ -27,6 +27,12 @@ log = logging.getLogger('flask_oauthlib') +class Server(WebApplicationServer, SignatureOnlyEndpoint): + def __init__(self, request_validator): + WebApplicationServer.__init__(self, request_validator) + SignatureOnlyEndpoint.__init__(self, request_validator) + + class OAuth1Provider(object): """Provide secure services using OAuth1. @@ -483,7 +489,7 @@ def decorated(*args, **kwargs): return _error_response(e) return decorated - def require_oauth(self, *realms, **kwargs): + def require_oauth(self, *realms, **oauth_kwargs): """Protect resource with specified scopes.""" def wrapper(f): @wraps(f) @@ -497,9 +503,15 @@ def decorated(*args, **kwargs): server = self.server uri, http_method, body, headers = extract_params() try: - valid, req = server.validate_protected_resource_request( - uri, http_method, body, headers, realms - ) + if oauth_kwargs.get("require_user", True): + valid, req = server.validate_protected_resource_request( + uri, http_method, body, headers, realms + ) + else: + valid, req = server.validate_request( + uri, http_method, body, headers + ) + except Exception as e: log.warn('Exception: %r', e) e.urlencoded = urlencode([('error', 'unknown')]) @@ -511,7 +523,8 @@ def decorated(*args, **kwargs): if not valid: return abort(401) # alias user for convenience - req.user = req.access_token.user + if oauth_kwargs.get("require_user", True): + req.user = req.access_token.user request.oauth = req return f(*args, **kwargs) return decorated