Permalink
Browse files

Add support for Flask authentication, and custom backends, fix #1

  • Loading branch information...
1 parent 2884b68 commit 624ae3a6f3fa56238701727454d65f6958b5d6f2 @nycholas nycholas committed Dec 16, 2012
Showing with 136 additions and 6 deletions.
  1. +37 −0 examples/auth/auth.py
  2. +62 −0 examples/authbackend/authbackend.py
  3. +8 −4 flask_jsonrpc/__init__.py
  4. +27 −0 flask_jsonrpc/helpers.py
  5. +2 −2 run.py
View
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (c) 2012, Cenobit Technologies, Inc. http://cenobit.es/
+# All rights reserved.
+import os
+import sys
+
+from flask import Flask
+
+PROJECT_DIR, PROJECT_MODULE_NAME = os.path.split(
+ os.path.dirname(os.path.realpath(__file__))
+)
+
+FLASK_JSONRPC_PROJECT_DIR = os.path.join(PROJECT_DIR, os.pardir)
+if os.path.exists(FLASK_JSONRPC_PROJECT_DIR) \
+ and not FLASK_JSONRPC_PROJECT_DIR in sys.path:
+ sys.path.append(FLASK_JSONRPC_PROJECT_DIR)
+
+from flask_jsonrpc import JSONRPC
+
+app = Flask(__name__)
+jsonrpc = JSONRPC(app, '/api')
+
+def check_auth(username, password):
+ return True
+
+@jsonrpc.method('app.index', authenticated=check_auth)
+def index():
+ return 'Welcome to Flask JSON-RPC'
+
+@jsonrpc.method('app.echo(name=str)', authenticated=check_auth)
+def echo(name=''):
+ return 'Hello {}'.format(name)
+
+
+if __name__ == '__main__':
+ app.run()
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (c) 2012, Cenobit Technologies, Inc. http://cenobit.es/
+# All rights reserved.
+import os
+import sys
+from functools import wraps
+
+from flask import Flask
+
+PROJECT_DIR, PROJECT_MODULE_NAME = os.path.split(
+ os.path.dirname(os.path.realpath(__file__))
+)
+
+FLASK_JSONRPC_PROJECT_DIR = os.path.join(PROJECT_DIR, os.pardir)
+if os.path.exists(FLASK_JSONRPC_PROJECT_DIR) \
+ and not FLASK_JSONRPC_PROJECT_DIR in sys.path:
+ sys.path.append(FLASK_JSONRPC_PROJECT_DIR)
+
+from flask_jsonrpc import JSONRPC
+
+app = Flask(__name__)
+
+def authenticate(f, f_check_auth):
+ @wraps(f)
+ def _f(*args, **kwargs):
+ is_auth = False
+ try:
+ creds = args[:2]
+ is_auth = f_check_auth(creds[0], creds[1])
+ if is_auth:
+ args = args[2:]
+ except IndexError:
+ if 'username' in kwargs and 'password' in kwargs:
+ is_auth = f_check_auth(kwargs['username'], kwargs['password'])
+ if is_auth:
+ kwargs.pop('username')
+ kwargs.pop('password')
+ else:
+ raise InvalidParamsError('Authenticated methods require at least '
+ '[username, password] or {username: password:} arguments')
+ if not is_auth:
+ raise InvalidCredentialsError()
+ return f(*args, **kwargs)
+ return _f
+
+jsonrpc = JSONRPC(app, '/api', auth_backend=authenticate)
+
+def check_auth(username, password):
+ return True
+
+@jsonrpc.method('app.index', authenticated=check_auth)
+def index():
+ return 'Welcome to Flask JSON-RPC'
+
+@jsonrpc.method('app.echo(name=str)', authenticated=check_auth)
+def echo(name=''):
+ return 'Hello {}'.format(name)
+
+
+if __name__ == '__main__':
+ app.run()
View
@@ -3,16 +3,16 @@
# All rights reserved.
import re
import StringIO
-from inspect import getargspec
from functools import wraps
+from inspect import getargspec
from collections import OrderedDict
from flask import current_app, request, jsonify
from flask_jsonrpc.site import jsonrpc_site
-from flask_jsonrpc.helpers import jsonify_status_code, extract_raw_data_request
from flask_jsonrpc.types import Object, Number, Boolean, String, Array, Nil, Any, Type
+from flask_jsonrpc.helpers import jsonify_status_code, extract_raw_data_request, authenticate
from flask_jsonrpc.exceptions import (Error, ParseError, InvalidRequestError,
MethodNotFoundError, InvalidParamsError,
ServerError, RequestPostError,
@@ -141,8 +141,9 @@ def _site_api(method=''):
class JSONRPC(object):
- def __init__(self, app=None, service_url='/api', site=default_site):
+ def __init__(self, app=None, service_url='/api', auth_backend=authenticate, site=default_site):
self.service_url = service_url
+ self.auth_backend = auth_backend
self.site = site
if app is not None:
self.app = app
@@ -163,7 +164,10 @@ def decorator(f):
arg_names = getargspec(f)[0][1:]
X = {'name': name, 'arg_names': arg_names}
if authenticated:
- raise Exception('Not implement')
+ # TODO: this is an assumption
+ X['arg_names'] = ['username', 'password'] + X['arg_names']
+ X['name'] = _inject_args(X['name'], ('String', 'String'))
+ _f = self.auth_backend(f, authenticated)
else:
_f = f
method, arg_types, return_type = _parse_sig(X['name'], X['arg_names'], validate)
View
@@ -1,8 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2012, Cenobit Technologies, Inc. http://cenobit.es/
# All rights reserved.
+from functools import wraps
+
from flask import current_app, request, jsonify
+from flask_jsonrpc.exceptions import InvalidCredentialsError, InvalidParamsError
+
def jsonify_status_code(status_code, *args, **kw):
"""Returns a jsonified response with the specified HTTP status code.
@@ -25,5 +29,28 @@ def extract_raw_data_request(request):
return request.form.to_dict().keys()[0]
return ''
+def authenticate(f, f_check_auth):
+ @wraps(f)
+ def _f(*args, **kwargs):
+ is_auth = False
+ try:
+ creds = args[:2]
+ is_auth = f_check_auth(creds[0], creds[1])
+ if is_auth:
+ args = args[2:]
+ except IndexError:
+ if 'username' in kwargs and 'password' in kwargs:
+ is_auth = f_check_auth(kwargs['username'], kwargs['password'])
+ if is_auth:
+ kwargs.pop('username')
+ kwargs.pop('password')
+ else:
+ raise InvalidParamsError('Authenticated methods require at least '
+ '[username, password] or {username: password:} arguments')
+ if not is_auth:
+ raise InvalidCredentialsError()
+ return f(*args, **kwargs)
+ return _f
+
def log_exception(sender, exception, **extra):
sender.logger.debug('Got exception during processing: %s', exception)
View
4 run.py
@@ -8,10 +8,10 @@
app = Flask(__name__)
jsonrpc = JSONRPC(app, '/api')
-@jsonrpc.method('App.index')
+@jsonrpc.method('app.index')
def index():
return 'Welcome to Flask JSON-RPC'
if __name__ == '__main__':
- app.run(host='0.0.0.0', debug=True)
+ app.run(host='0.0.0.0', debug=0)

0 comments on commit 624ae3a

Please sign in to comment.