feat: token based auth in frappeclient

This commit is contained in:
Rucha Mahabal 2019-08-13 20:25:06 +05:30
parent 68a3bd0a36
commit 3f415094e9
2 changed files with 29 additions and 10 deletions

View file

@ -164,23 +164,29 @@ def validate_auth_via_api_keys():
"""
try:
authorization_header = frappe.get_request_header("Authorization", None).split(" ") if frappe.get_request_header("Authorization") else None
authorization_source = frappe.get_request_header("Frappe-Authorization-Source", None)
if authorization_header and authorization_header[0] == 'Basic':
token = frappe.safe_decode(base64.b64decode(authorization_header[1])).split(":")
validate_api_key_secret(token[0], token[1])
elif authorization_header and authorization_header[0] == 'token':
token = authorization_header[1].split(":")
validate_api_key_secret(token[0], token[1])
if authorization_source:
validate_api_key_secret(token[0], token[1], authorization_source)
except Exception as e:
raise e
def validate_api_key_secret(api_key, api_secret):
user = frappe.db.get_value(
doctype="User",
def validate_api_key_secret(api_key, api_secret, frappe_authorization_source=None):
""" frappe_authorization_source to provide api key and secret for a doctype apart from User """
if not frappe_authorization_source:
frappe_authorization_source = 'User'
doc = frappe.db.get_value(
doctype=frappe_authorization_source,
filters={"api_key": api_key},
fieldname=['name']
fieldname=["name"]
)
form_dict = frappe.local.form_dict
user_secret = frappe.utils.password.get_decrypted_password ("User", user, fieldname='api_secret')
if api_secret == user_secret:
doc_secret = frappe.utils.password.get_decrypted_password(frappe_authorization_source, doc, fieldname="api_secret")
if api_secret == doc_secret:
user = frappe.db.get_value(frappe_authorization_source, doc, 'user')
frappe.set_user(user)
frappe.local.form_dict = form_dict
frappe.local.form_dict = form_dict

View file

@ -3,6 +3,7 @@ import requests
import json
import frappe
from six import iteritems, string_types
from base64 import b64encode
'''
FrappeClient is a library that helps you connect with other frappe systems
@ -18,7 +19,7 @@ class FrappeException(Exception):
pass
class FrappeClient(object):
def __init__(self, url, username=None, password=None, verify=True):
def __init__(self, url, username=None, password=None, verify=True, api_key=None, api_secret=None, frappe_authorization_source = None):
self.headers = dict(Accept='application/json')
self.verify = verify
self.session = requests.session()
@ -28,6 +29,10 @@ class FrappeClient(object):
if username and password:
self._login(username, password)
# token based authentication if api_key and api_secret provided
elif api_key and api_secret:
self.authenticate(api_key, api_secret, frappe_authorization_source)
def __enter__(self):
return self
@ -49,6 +54,14 @@ class FrappeClient(object):
raise SiteExpiredError
raise AuthError
def authenticate(self, api_key, api_secret, frappe_authorization_source=None):
token = b64encode('{}:{}'. format(api_key, api_secret))
auth_header = {'Authorization': 'Basic {}'.format(token)}
self.session.headers.update(auth_header)
if frappe_authorization_source:
auth_source = {'Frappe-Authorization-Source': frappe_authorization_source}
self.session.headers.update(auth_source)
def logout(self):
'''Logout session'''
self.session.get(self.url, params={