# -*- coding: utf-8 -*- from openerp import http from openerp.http import request 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 with open(os.path.dirname(__file__) + '/resources.json') as resources: RESOURCES_MAP = json.load(resources) ''' Class for manage authentication ''' class Auth(http.Controller): JWT_SECRET_KEY = '@MjSk$2016?' # -------------------------------------------------------------------------- # Generate JWT token based on username and password field # -------------------------------------------------------------------------- @http.route(['/api/jwt'], type = 'http', auth = 'none', methods = ['POST'], cors = '*') def get_jwt(self, **args): 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'] } encoded = jwt.encode(payload, self.JWT_SECRET_KEY, algorithm = 'HS256') user.write({'jwt_token': encoded}) return json.dumps({'token': encoded}) else: return json.dumps({'error': 'invalid user or password'}) except Exception, e: return json.dumps({'error': 'fields required'}) # -------------------------------------------------------------------------- # Check JWT token auth # -------------------------------------------------------------------------- @http.route(['/api/check'], type = 'http', auth = 'none', methods = ['POST'], cors = '*') def check_token(self, **args): 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 self.get_crypt_context().verify(decoded['password'], user.password_crypt): return json.dumps({'token': 'valid'}) return json.dumps({'token': 'invalid'}) except Exception, e: return json.dumps({'error': 'token required'}) # -------------------------------------------------------------------------- # Get context for encryption # -------------------------------------------------------------------------- def get_crypt_context(self): return CRYPT_CONTEXT ''' Class for manage rest api interaction ''' class ApiManager(http.Controller): RESOURCES_MAP = [ {'customers': 'res.partner'} ] # -------------------------------------------------------------------------- # Restify your request # -------------------------------------------------------------------------- @http.route([ '/api/', '/api//' ], type = 'http', auth = 'none', cors = '*') def restify(self, resource, uid = None): if not self.resource_exists(resource): return self.make_response({'error': 'resource not available'}) http_verb = request.httprequest.method if http_verb == 'GET': return self.http_get(resource, uid) if http_verb == 'POST': return json.dumps({'verb': 'POST'}, sort_keys = True) if http_verb == 'PUT' or http_verb == 'PATCH': return json.dumps({'verb': 'PUT OR PATCH'}) if http_verb == 'DELETE': return self.http_delete(resource, uid) return json.dumps({'error': 'method not allowed'}) # -------------------------------------------------------------------------- # Manage GET request # -------------------------------------------------------------------------- def http_get(self, resource, uid): model, filters = self.resource_inflater(resource) data = [] if uid != None: filters.append(('id', '=', uid)) result = request.env[model].sudo().search(filters) for item in result: data.append(item.dump()) return self.make_response(data); # -------------------------------------------------------------------------- # Manage DELETE request # -------------------------------------------------------------------------- def http_delete(self, resource, uid): if uid == None: return self.make_response({'error': 'uid not provided'}) model, filters = self.resource_inflater(resource) result = request.env[model].sudo().browse(uid) if not result.exists(): return self.make_response({'error': 'cannot be deleted'}) return self.make_response({'response': result.unlink()}) # -------------------------------------------------------------------------- # Make JSON response # -------------------------------------------------------------------------- def make_response(self, data): return Response(json.dumps(data), mimetype = 'application/json') # -------------------------------------------------------------------------- # Manage JWT token validity # -------------------------------------------------------------------------- def resource_exists(self, resource): try: model = RESOURCES_MAP[resource]['module'] module_name = model.replace('.', '_') module = request.env['ir.module.module'].sudo().search([('name', '=', module_name)]) return True if module.state == 'installed' and len(module) != 0 else False except Exception, e: return False; # -------------------------------------------------------------------------- # Manage JWT token validity # -------------------------------------------------------------------------- def check_token(self, token): pass # -------------------------------------------------------------------------- # Manage GET request # -------------------------------------------------------------------------- def resource_inflater(self, resource): try: model = RESOURCES_MAP[resource]['model'] filters = [] for i in range(len(RESOURCES_MAP[resource]['filters'])): filters.append(tuple(RESOURCES_MAP[resource]['filters'][i])) return (model, filters) except Exception, e: return (None, None)