Browse Source

se ha agregado verificación de token en las peticiones

robert2206 8 years ago
parent
commit
7bdc953b72
2 changed files with 72 additions and 35 deletions
  1. 72 35
      controllers/http_handler.py
  2. BIN
      controllers/http_handler.pyc

+ 72 - 35
controllers/http_handler.py

@@ -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

BIN
controllers/http_handler.pyc