|
@@ -6,16 +6,13 @@ from passlib.context import CryptContext
|
|
|
import os
|
|
|
import jwt
|
|
|
import json
|
|
|
-import pickle
|
|
|
-import marshal
|
|
|
from werkzeug.wrappers import Response
|
|
|
|
|
|
-CRYPT_CONTEXT = CryptContext(
|
|
|
- ['pbkdf2_sha512', 'md5_crypt'],
|
|
|
- deprecated=['md5_crypt'],
|
|
|
-)
|
|
|
-
|
|
|
RESOURCES_MAP = None
|
|
|
+JWT_SECRET_KEY = '@MjSk$2016?'
|
|
|
+JWT_HEADER = 'Authorization'
|
|
|
+JWT_HEADER_PREFIX = 'JWT'
|
|
|
+CRYPT_CONTEXT = CryptContext(['pbkdf2_sha512', 'md5_crypt'], deprecated=['md5_crypt'])
|
|
|
|
|
|
with open(os.path.dirname(__file__) + '/resources.json') as resources:
|
|
|
RESOURCES_MAP = json.load(resources)
|
|
@@ -24,7 +21,6 @@ with open(os.path.dirname(__file__) + '/resources.json') as resources:
|
|
|
Class for manage authentication
|
|
|
'''
|
|
|
class Auth(http.Controller):
|
|
|
- JWT_SECRET_KEY = '@MjSk$2016?'
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
|
# Generate JWT token based on username and password field
|
|
@@ -34,21 +30,24 @@ class Auth(http.Controller):
|
|
|
try:
|
|
|
user = request.env['res.users'].sudo().search([('login', '=', args['username']), ('active', '=', True)])
|
|
|
|
|
|
- if len(user) != 0 and self.get_crypt_context().verify(args['password'], user.password_crypt):
|
|
|
- payload = {
|
|
|
- 'uid': user.id,
|
|
|
- 'password': args['password']
|
|
|
- }
|
|
|
+ if not user:
|
|
|
+ return self.make_response({'error': 'invalid user'}) # bad request
|
|
|
+
|
|
|
+ if not self.get_crypt_context().verify(args['password'], user.password_crypt):
|
|
|
+ return self.make_response({'error': 'invalid password'}, status = 400) # bad request
|
|
|
|
|
|
- encoded = jwt.encode(payload, self.JWT_SECRET_KEY, algorithm = 'HS256')
|
|
|
+ payload = {
|
|
|
+ 'uid': user.id,
|
|
|
+ 'password': args['password']
|
|
|
+ }
|
|
|
|
|
|
- user.write({'jwt_token': encoded})
|
|
|
+ encoded = jwt.encode(payload, JWT_SECRET_KEY, algorithm = 'HS256')
|
|
|
|
|
|
- return json.dumps({'token': encoded})
|
|
|
- else:
|
|
|
- return json.dumps({'error': 'invalid user or password'})
|
|
|
+ user.write({'jwt_token': encoded})
|
|
|
+
|
|
|
+ return self.make_response({'token': encoded})
|
|
|
except Exception, e:
|
|
|
- return json.dumps({'error': 'fields required'})
|
|
|
+ return self.make_response({'error': 'fields required'}, status = 400) # bad request
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
|
# Check JWT token auth
|
|
@@ -58,15 +57,17 @@ class Auth(http.Controller):
|
|
|
try:
|
|
|
user = request.env['res.users'].sudo().search([('jwt_token', '=', args['token'])])
|
|
|
|
|
|
- if len(user) != 0:
|
|
|
- decoded = jwt.decode(args['token'], self.JWT_SECRET_KEY, algorithms = ['HS256'])
|
|
|
+ if not user:
|
|
|
+ return self.make_response({'error' : 'invalid token'}, status = 400) # bad request
|
|
|
+
|
|
|
+ decoded = jwt.decode(args['token'], JWT_SECRET_KEY, algorithms = ['HS256'])
|
|
|
|
|
|
- if self.get_crypt_context().verify(decoded['password'], user.password_crypt):
|
|
|
- return json.dumps({'token': 'valid'})
|
|
|
+ if not self.get_crypt_context().verify(decoded['password'], user.password_crypt):
|
|
|
+ return self.make_response({'error' : 'invalid token'}, status = 400) # bad request
|
|
|
|
|
|
- return json.dumps({'token': 'invalid'})
|
|
|
+ return self.make_response({'token': 'valid'})
|
|
|
except Exception, e:
|
|
|
- return json.dumps({'error': 'token required'})
|
|
|
+ return self.make_response({'error': 'token required'}, status = 400) # bad request
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
|
# Get context for encryption
|
|
@@ -74,14 +75,17 @@ class Auth(http.Controller):
|
|
|
def get_crypt_context(self):
|
|
|
return CRYPT_CONTEXT
|
|
|
|
|
|
+ # --------------------------------------------------------------------------
|
|
|
+ # Make JSON response
|
|
|
+ # --------------------------------------------------------------------------
|
|
|
+ def make_response(self, data, status = 200):
|
|
|
+ return Response(json.dumps(data), status = status, mimetype = 'application/json')
|
|
|
+
|
|
|
|
|
|
'''
|
|
|
Class for manage rest api interaction
|
|
|
'''
|
|
|
class ApiManager(http.Controller):
|
|
|
- RESOURCES_MAP = [
|
|
|
- {'customers': 'res.partner'}
|
|
|
- ]
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
|
# Restify your request
|
|
@@ -94,8 +98,11 @@ class ApiManager(http.Controller):
|
|
|
auth = 'none',
|
|
|
cors = '*')
|
|
|
def restify(self, resource, uid = None):
|
|
|
+ if not self.valid_token():
|
|
|
+ return self.make_response({'error': 'denied resource'}, status = 403) # access denied
|
|
|
+
|
|
|
if not self.resource_exists(resource):
|
|
|
- return self.make_response({'error': 'resource not available'})
|
|
|
+ return self.make_response({'error': 'resource not available'}, status = 404) # not found
|
|
|
|
|
|
http_verb = request.httprequest.method
|
|
|
|
|
@@ -111,7 +118,7 @@ class ApiManager(http.Controller):
|
|
|
if http_verb == 'DELETE':
|
|
|
return self.http_delete(resource, uid)
|
|
|
|
|
|
- return json.dumps({'error': 'method not allowed'})
|
|
|
+ return self.make_response({'error': 'method not allowed'}, status = 405) # method not allowed
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
|
# Manage GET request
|
|
@@ -149,11 +156,11 @@ class ApiManager(http.Controller):
|
|
|
# --------------------------------------------------------------------------
|
|
|
# Make JSON response
|
|
|
# --------------------------------------------------------------------------
|
|
|
- def make_response(self, data):
|
|
|
- return Response(json.dumps(data), mimetype = 'application/json')
|
|
|
+ def make_response(self, data, status = 200):
|
|
|
+ return Response(json.dumps(data), status = status, mimetype = 'application/json')
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
|
- # Manage JWT token validity
|
|
|
+ # Check if resource is available
|
|
|
# --------------------------------------------------------------------------
|
|
|
def resource_exists(self, resource):
|
|
|
try:
|
|
@@ -169,8 +176,32 @@ class ApiManager(http.Controller):
|
|
|
# --------------------------------------------------------------------------
|
|
|
# Manage JWT token validity
|
|
|
# --------------------------------------------------------------------------
|
|
|
- def check_token(self, token):
|
|
|
- pass
|
|
|
+ def valid_token(self):
|
|
|
+ try:
|
|
|
+ auth_header = request.httprequest.headers[JWT_HEADER]
|
|
|
+
|
|
|
+ if not auth_header.startswith(JWT_HEADER_PREFIX):
|
|
|
+ return False
|
|
|
+
|
|
|
+ jwt_token = auth_header[4:]
|
|
|
+
|
|
|
+ if not jwt_token:
|
|
|
+ return False
|
|
|
+
|
|
|
+ user = request.env['res.users'].sudo().search([('jwt_token', '=', jwt_token)])
|
|
|
+
|
|
|
+ if not user:
|
|
|
+ return False
|
|
|
+
|
|
|
+ decoded = jwt.decode(jwt_token, JWT_SECRET_KEY, algorithms = ['HS256'])
|
|
|
+
|
|
|
+ if not self.get_crypt_context().verify(decoded['password'], user.password_crypt):
|
|
|
+ return False
|
|
|
+
|
|
|
+ return True
|
|
|
+ except Exception, e:
|
|
|
+ print e
|
|
|
+ return False
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
|
# Manage GET request
|
|
@@ -186,3 +217,9 @@ class ApiManager(http.Controller):
|
|
|
return (model, filters)
|
|
|
except Exception, e:
|
|
|
return (None, None)
|
|
|
+
|
|
|
+ # --------------------------------------------------------------------------
|
|
|
+ # Get context for encryption
|
|
|
+ # --------------------------------------------------------------------------
|
|
|
+ def get_crypt_context(self):
|
|
|
+ return CRYPT_CONTEXT
|