Unit testing with AWS Cognito and GraphQL - django

I'm currently writing tests for my software but got stuck at the point.
I try to get data from my db with a normal GraphQL Query but my endpoint is first checking, if the idToken within the header is valid.
For the user handling I'm using AWS Cognito but couldn't find a good way to mock the login to retrieve the valid token to query and mutate the data within various endpoints.
Any idea how to handle this case?
Here is my code from the graphene docs (https://docs.graphene-python.org/projects/django/en/latest/testing/):
# Create a fixture using the graphql_query helper and `client` fixture from `pytest-django`.
import json
import pytest
from graphene_django.utils.testing import graphql_query
# https://docs.graphene-python.org/projects/django/en/latest/testing/
#pytest.fixture
def client_query(client):
def func(*args, **kwargs):
return graphql_query(*args, **kwargs, client=client)
return func
# Test you query using the client_query fixture
def test_some_query(client_query):
response = client_query(
'''
query GetAllProjectConfig{
getAllProjectConfig{
project{
id
slug
name
}
config{
id
}
}
}
''',
)
content = json.loads(response.content)
assert 'errors' not in content

The answer was not so hard:
auth_data = {'USERNAME': username, 'PASSWORD': password}
# auth the user on cognito
def auth_cognito_user():
provider_client = boto3.client(
'cognito-idp', region_name=os.environ.get('region_name'))
resp = provider_client.admin_initiate_auth(
UserPoolId=userpool_id, AuthFlow='ADMIN_NO_SRP_AUTH', AuthParameters=auth_data, ClientId=client_id)
# print("RESPONSE COGNITO", resp['AuthenticationResult']['IdToken'])
return resp['AuthenticationResult']['IdToken']

Related

How to authenticate requests made to AWS AppSync in Python?

I have a website with a backend of AWS Amplify. For a post-payment function, I am creating a lambda function to update the database. I am trying to query certain fields with the help of AppSync and then run a mutation. This is my function code:
import json
import boto3
import os
import decimal
import requests
from requests_aws4auth import AWS4Auth
def lambda_handler(event, context):
dynamoDB = boto3.resource('dynamodb', region_name='ap-northeast-1')
// load event data (hidden)
userid = sentData.get("userid")
slots = sentData.get("slots")
url = os.environ.get("AWS_GRAPHQL_API_ENDPOINT")
api_key = os.environ.get("AWS_GRAPHQL_API_KEY")
session = requests.Session()
query = """
query MyQuery {
getUserPlan(id: "9ddf437a-55b1-445d-8ae6-254c77493c30") {
traits
traitCount
}
}
"""
credentials = boto3.session.Session().get_credentials()
session.auth = AWS4Auth(
credentials.access_key,
credentials.secret_key,
'ap-northeast-1',
'appsync',
session_token=credentials.token
)
# response = session.request(
# url=url,
# method="POST",
# json={"query": query},
# headers={"Authorization": api_key},
# )
# response = requests.post(
# url=url,
# json={"query": query},
# headers={"x-api-key": api_key}
# )
response = session.request(
url=url,
method="POST",
json={"query": query},
);
print(response.json())
return {
"statusCode": 200,
}
I get the following error when I execute the function:
{'data': {'getUserPlan': None}, 'errors': [{'path': ['getUserPlan'], 'data': None, 'errorType': 'Unauthorized', 'errorInfo': None, 'locations': [{'line': 3, 'column': 9, 'sourceName': None}], 'message': 'Not Authorized to access getUserPlan on type UserPlan'}]}
I have referred to this and this. I have tried their solutions but they haven't worked for me. I have confirmed that all the environment variables are working properly and even added the local aws-cli iam user to the custom-roles.json file for admin privileges by Amplify. When I was trying with the API Key, I made sure that it hadn't expired as well.
I figured out how to fix it. I had to create a function through the amplify-cli, give it access to the api, push the function and then add the name of the role to adminRoleNames in custom-roles.json

Mocking external API in Django

I am trying to mock external api in Django but not sure how to do it properly.
Basically, it must mock the json data from external API and then create a new object if all values are valid.
The program fetches the geolocation data based on given IP address and saves the object in database if response data includes all required fields. So, how I can mock this process to test a new object creation?
services.py
import os
import requests
from .exceptions import ExternalApiException
def get_location(ip):
url = f'http://api.ipstack.com/{ip}'
params = {'access_key': os.environ.get('ACCESS_KEY')}
try:
res = requests.get(url, params=params)
data = res.json()
return {
'ip':data['ip'],
'country_name':data['country_name'],
'region_code':data['region_code'],
'city':data['city'],
'latitude':data['latitude'],
'longitude':data['longitude'],
'zip_code':data['zip']
}
except requests.exceptions.ConnectionError:
raise ExternalApiException('Connection error occured during the fetch process')
except requests.exceptions.Timeout:
raise ExternalApiException("Connection timeout. Please check your internet connection and try again later")
except requests.exceptions.TooManyRedirects:
raise ExternalApiException("Too many redirects")
except requests.exceptions.RequestException:
raise SystemExit(e)
tests.py
#I am lost in this part
#patch('geolocation.services.get_location')
def test_create_basic_geolocation(self, mock_request):
"""Test creating geolocation data"""
payload = {
'ip': '',
}
res = self.client.post(LOCATIONS_URL, payload)
self.assertTrue(res.data['ip'])
Thanks for any help.
Just assign return_value on mocked instance like this
#patch('geolocation.services.get_location')
def test_create_basic_geolocation(self, mock_request):
"""Test creating geolocation data"""
mock_request.return_value = {"ip": "hello", "country_name": "test"}
payload = {
'ip': '',
}
res = self.client.post(LOCATIONS_URL, payload)
self.assertTrue(res.data['ip'])

POST on /oauth/token always use client_secret_basic

I'm trying to add oauth2 (server) on my flask app and I have some issues with the /oauth/token endpoint with client_secret_post.
My app does POST the following to it as a form:
client_id=XXX
client_secret=YYY
grant_type=client_credentials
token_endpoint_auth_method=client_secret_post
redirect_uri=http://localhost:8081/oauth-callback
And I get in the logs:
DEBUG:authlib.oauth2.rfc6749.authenticate_client:Authenticate None via "client_secret_basic" failed
127.0.0.1 - - [23/Jun/2019 18:05:26] "POST /oauth/token HTTP/1.0" 401 -
The token_endpoint_auth_method doesn't seems to change anything and it always returns {"error": "invalid_client"}.
I have tried adding TOKEN_ENDPOINT_AUTH_METHODS = ['client_secret_post'] to my class AuthorizationCodeGrant(grants.AuthorizationCodeGrant): without effects (also none of the loggers print anything).
What did I missed there ?
I have implemented things in my app more or less like the oauth2 flask example, here is some extracts:
app.py:
from app_oauth import config_oauth
...
def create_app(...):
...
config_oauth(app)
...
app_oauth.py:
from authlib.flask.oauth2 import AuthorizationServer, ResourceProtector
from authlib.flask.oauth2.sqla import (
create_query_client_func,
create_save_token_func,
create_revocation_endpoint,
create_bearer_token_validator,
)
from authlib.oauth2.rfc6749 import grants
from werkzeug.security import gen_salt
from models import db, User
from models import OAuth2Client, OAuth2AuthorizationCode, OAuth2Token
from flask import current_app
class AuthorizationCodeGrant(grants.AuthorizationCodeGrant):
def create_authorization_code(self, client, user, request):
current_app.logger.debug("create auth code")
code = gen_salt(48)
item = OAuth2AuthorizationCode(
code=code,
client_id=client.client_id,
redirect_uri=request.redirect_uri,
scope=request.scope,
user_id=user.get_user_id(),
)
db.session.add(item)
db.session.commit()
return code
def parse_authorization_code(self, code, client):
current_app.logger.debug("parse auth code")
item = OAuth2AuthorizationCode.query.filter_by(
code=code, client_id=client.client_id).first()
if item and not item.is_expired():
return item
def delete_authorization_code(self, authorization_code):
current_app.logger.debug("delete auth code")
db.session.delete(authorization_code)
db.session.commit()
def authenticate_user(self, authorization_code):
current_app.logger.debug("auth user")
return User.query.get(authorization_code.user_id)
class PasswordGrant(grants.ResourceOwnerPasswordCredentialsGrant):
def authenticate_user(self, username, password):
current_app.logger.debug("password grant auth user")
user = User.query.filter_by(name=username).first()
if user.check_password(password):
return user
class RefreshTokenGrant(grants.RefreshTokenGrant):
def authenticate_refresh_token(self, refresh_token):
current_app.logger.debug("refresh token grant")
token = OAuth2Token.query.filter_by(refresh_token=refresh_token).first()
if token and not token.revoked and not token.is_refresh_token_expired():
return token
def authenticate_user(self, credential):
current_app.logger.debug("auth user grant user")
return User.query.get(credential.user_id)
query_client = create_query_client_func(db.session, OAuth2Client)
save_token = create_save_token_func(db.session, OAuth2Token)
authorization = AuthorizationServer(
query_client=query_client,
save_token=save_token,
)
require_oauth = ResourceProtector()
def config_oauth(app):
authorization.init_app(app)
# support all grants
authorization.register_grant(grants.ImplicitGrant)
authorization.register_grant(grants.ClientCredentialsGrant)
authorization.register_grant(AuthorizationCodeGrant)
authorization.register_grant(PasswordGrant)
authorization.register_grant(RefreshTokenGrant)
# support revocation
revocation_cls = create_revocation_endpoint(db.session, OAuth2Token)
authorization.register_endpoint(revocation_cls)
# protect resource
bearer_cls = create_bearer_token_validator(db.session, OAuth2Token)
require_oauth.register_token_validator(bearer_cls())
and my blueprint:
from app_oauth import authorization
...
#bp_api_v1_auth.route("/oauth/token", methods=["POST"])
def oauth_token():
return authorization.create_token_response()
Edit: after digging it looks like it is handled by ClientCredentialsGrant which does only client_secret_basic by default, I then added:
class ClientCredentialsGrant(grants.ClientCredentialsGrant):
TOKEN_ENDPOINT_AUTH_METHODS = [
'client_secret_basic', 'client_secret_post'
]
...
authorization.register_grant(ClientCredentialsGrant)
Which now validates but respond with {"error": "unauthorized_client"}
Finally nailed it: my OAuth2Client entry in database had only authorization_code and password, client_credentials was needed to validate.

Zoho CRM Python SDK v2 initialization problem for Django

Im trying to integrate the Zoho CRM v2 SDK with my Django app.
On the Django runserver, im able to get access tokens and using the refresh method and store them in the zcrm_oauthtokens.pkl file. The sdk then automatically refreshes the access token using the refresh token, so no problem here. However on my production server (heroku) im getting this error message:
2019-01-16T11:07:22.314759+00:00 app[web.1]: 2019-01-16 11:07:22,314 - Client_Library_OAUTH - ERROR - Exception occured while fetching oauthtoken from db; Exception Message::'NoneType' object has no attribute 'accessToken'
It seems to me that the tokens are being saved to file, but when the sdk try to access them it is looking for them in a DB and not the file specified in the token_persistence_path.
In my settings.py I have this:
ZOHO_CLIENT_ID = config('ZOHO_CLIENT_ID')
ZOHO_CLIENT_SECRET = config('ZOHO_CLIENT_SECRET')
ZOHO_REDIRECT_URI = config('ZOHO_REDIRECT_URI')
ZOHO_CURRENT_USER_EMAIL = 'jamesalexander#mylastwill.co.uk'
ZOHO_PATH = os.path.join(BASE_DIR, 'wills_online', 'zoho')
zoho_config = {'apiBaseUrl': "https://www.zohoapis.com",
'currentUserEmail': ZOHO_CURRENT_USER_EMAIL,
'client_id': ZOHO_CLIENT_ID,
'client_secret': ZOHO_CLIENT_SECRET,
'redirect_uri': ZOHO_REDIRECT_URI,
'token_persistence_path': ZOHO_PATH}
and in a views file I have this:
from zcrmsdk import *
import logging
from django.shortcuts import HttpResponse
from wills.models import PersonalDetails, ZoHoRecord, WillDocument
from wills_online.decorators import start_new_thread
from wills_online.settings import zoho_config
logger = logging.getLogger(__name__)
class ZohoRunOnce:
def __init__(self):
self.already_run = False
def run_once(self):
if not self.already_run:
print('zoho init run once')
ZCRMRestClient.initialize(zoho_config)
self.already_run = True
zoho_init = ZohoRunOnce()
zoho_init.run_once()
print(zoho_config['token_persistence_path'])
def zoho_callback():
return HttpResponse(200)
#start_new_thread
def zoho_personal_details(request):
""" updates or create a user account on zoho on profile completion """
personal_details_ob = PersonalDetails.objects.get(user=request.user)
zoho_ob = ZoHoRecord.objects.get(user=request.user)
try:
if zoho_ob.account:
record = ZCRMRecord.get_instance('Accounts', zoho_ob.account)
record.set_field_value('Account_Name', request.user.email)
record.set_field_value('Name', personal_details_ob.full_name)
record.set_field_value('Email', request.user.email)
record.set_field_value('Address_Line_1', personal_details_ob.address_line_1)
record.set_field_value('Address_Line_2', personal_details_ob.address_line_2)
record.set_field_value('Post_Town', personal_details_ob.post_town)
record.set_field_value('Post_Code', personal_details_ob.post_code)
record.set_field_value('Dob_Day', personal_details_ob.dob_day)
record.set_field_value('Dob_Month', personal_details_ob.dob_month)
record.set_field_value('Dob_Year', personal_details_ob.dob_year)
record.set_field_value('Gender', personal_details_ob.sex)
record.set_field_value('Marital_Status', personal_details_ob.marital_status)
record.set_field_value('Partner_Name', personal_details_ob.partner_full_name)
record.set_field_value('Partner_Gender', personal_details_ob.partner_gender)
record.set_field_value('Partner_Email', personal_details_ob.partner_email)
record.set_field_value('Children', personal_details_ob.children)
record.set_field_value('Pets', personal_details_ob.pets)
record.update()
else:
user = ZCRMUser.get_instance(name='James Alexander')
record = ZCRMRecord.get_instance('Accounts')
record.set_field_value('Account_Owner', user)
record.set_field_value('Account_Name', request.user.email)
record.set_field_value('Name', personal_details_ob.full_name)
record.set_field_value('Email', request.user.email)
record.set_field_value('Address_Line_1', personal_details_ob.address_line_1)
record.set_field_value('Address_Line_2', personal_details_ob.address_line_2)
record.set_field_value('Post_Town', personal_details_ob.post_town)
record.set_field_value('Post_Code', personal_details_ob.post_code)
record.set_field_value('Dob_Day', personal_details_ob.dob_day)
record.set_field_value('Dob_Month', personal_details_ob.dob_month)
record.set_field_value('Dob_Year', personal_details_ob.dob_year)
record.set_field_value('Gender', personal_details_ob.sex)
record.set_field_value('Marital_Status', personal_details_ob.marital_status)
record.set_field_value('Partner_Name', personal_details_ob.partner_full_name)
record.set_field_value('Partner_Gender', personal_details_ob.partner_gender)
record.set_field_value('Partner_Email', personal_details_ob.partner_email)
record.set_field_value('Children', personal_details_ob.children)
record.set_field_value('Pets', personal_details_ob.pets)
response = record.create()
# save account id to db for future updates
zoho_ob.account = response.details['id']
zoho_ob.save()
except ZCRMException as ex:
logger.log(1, ex.status_code)
logger.log(1, ex.error_message)
logger.log(1, ex.error_details)
logger.log(1, ex.error_content)
print(ex.status_code)
print(ex.error_message)
print(ex.error_content)
print(ex.error_details)
Ive tried running ZCRMRestClient.initialize(zoho_config) in settings.py, with no luck.
My method for getting the access token and refresh token, which seems to work is:
import os
import pprint
from sys import argv
import django
import requests
import zcrmsdk
from django.conf import settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'wills_online.settings')
django.setup()
def zoho_refresh_token(code):
""" supply a self client token from the zoho api credentials from web site """
zoho_config = {"apiBaseUrl": "https://www.zohoapis.com",
"currentUserEmail": settings.ZOHO_CURRENT_USER_EMAIL,
"client_id": settings.ZOHO_CLIENT_ID,
"client_secret": settings.ZOHO_CLIENT_SECRET,
"redirect_uri": settings.ZOHO_REDIRECT_URI,
"token_persistence_path": settings.ZOHO_PATH}
pprint.pprint(zoho_config)
print('working')
address = f'https://accounts.zoho.com/oauth/v2/token?code={code}&redirect_uri={settings.ZOHO_REDIRECT_URI}&client_id={settings.ZOHO_CLIENT_ID}&client_secret={settings.ZOHO_CLIENT_SECRET}&grant_type=authorization_code'
response = requests.post(address)
data = response.json()
pprint.pprint(data)
zcrmsdk.ZCRMRestClient.initialize(zoho_config)
oauth_client = zcrmsdk.ZohoOAuth.get_client_instance()
refresh_token = data['refresh_token']
print(type(refresh_token))
oauth_client.generate_access_token_from_refresh_token(refresh_token, settings.ZOHO_CURRENT_USER_EMAIL)
print(refresh_token)
print('finished')
if name == 'main':
zoho_refresh_token(argv[1])
This is driving me mad. Help would be greatly appreciated. This is my first post so go easy, lol.
For future reference, you will need to define persistence_handler_class and persistence_handler_path in your configuration dictionary. You will also need a handler class and a user-defined model to store the results. Sample code follows:
# settings.py
import zcrmsdk
configuration_dictionary = {
'apiBaseUrl': 'https://www.zohoapis.com',
'apiVersion': 'v2',
'currentUserEmail': ZOHO_CURRENT_USER_EMAIL,
'sandbox': 'False',
'applicationLogFilePath': '',
'client_id': ZOHO_CLIENT_ID,
'client_secret': ZOHO_CLIENT_SECRET,
'redirect_uri': ZOHO_REDIRECT_URI,
'accounts_url': 'https://accounts.zoho.com',
'access_type': 'online',
'persistence_handler_class': ZOHO_HANDLER_CLASS,
'persistence_handler_path': ZOHO_HANDLER_PATH,
}
zcrmsdk.ZCRMRestClient.initialize(configuration_dictionary)
# zoho.models.py
from django.db import models
from zcrmsdk.OAuthClient import ZohoOAuthTokens
class ZohoOAuthHandler:
#staticmethod
def get_oauthtokens(email_address):
oauth_model_instance = ZohoOAuth.objects.get(user_email=email_address)
return ZohoOAuthTokens(oauth_model_instance.refresh_token,
oauth_model_instance.access_token,
oauth_model_instance.expiry_time,
user_email=oauth_model_instance.user_email)
#staticmethod
def save_oauthtokens(oauth_token):
defaults = {
'refresh_token': oauth_token.refreshToken,
'access_token': oauth_token.accessToken,
'expiry_time': oauth_token.expiryTime,
}
ZohoOAuth.objects.update_or_create(user_email=oauth_token.userEmail, defaults=defaults)
class ZohoOAuth(models.Model):
refresh_token = models.CharField(max_length=250)
access_token = models.CharField(max_length=250)
expiry_time = models.BigIntegerField()
user_email = models.EmailField()
In this example ZOHO_HANDLER_CLASS = 'ZohoOAuthHandler' and ZOHO_HANDLER_PATH = 'zoho.models'
The first time you go to use this you will need a grant_token from https://accounts.zoho.com/developerconsole. For the scope use aaaserver.profile.READ,ZohoCRM.modules.ALL to start (see https://www.zoho.com/crm/developer/docs/api/oauth-overview.html#scopes)
Before you can use the api you'll need to run the code below in a django shell. This uses a grant token to generate your initial access and refresh tokens. Afterwards, the api should handle refreshing your access token.
grant_token = GRANT_TOKEN
import zcrmsdk
oauth_client = zcrmsdk.ZohoOAuth.get_client_instance()
oauth_tokens = oauth_client.generate_access_token(grant_token)

python - Flask test_client() doesn't have request.authorization with pytest

I have problem when testing my flask app with pytest.
App is required basic auth which is parameters of request.authorization in flask.
But with pytest, flask.test_client() doesn't have request.authorization.
Here's a code of fixture:
#pytest.yield_fixture(scope='session')
def app()
app = create_app()
# some setup code
ctx = app.app_context()
ctx.push()
yield app
ctx.pop()
# some teadown code
#pytest.fixture
def test_client(app)
return app.test_client()
Here's a code of test:
def test_index(test_client):
res = test_client.get("/", headers={"Authorization": "Basic {user}".format(user=b64encode(b"test_user"))})
assert res.status_code == 200
When I run this test, I got this error:
E assert 401 == 200
E + where 401 = <Response streamed [401 UNAUTHORIZED]>.status_code
Not only auth failure, but also request.authorization doesn't have any value(None).
Why this happen? Is there any solution?
Thanks.
The credentials for HTTP Basic authentication must have a username and a password separated by a colon. If you're still using python 2, try this:
def test_index(test_client):
credentials = b64encode(b"test_user:test_password")
res = test_client.get("/", headers={"Authorization": "Basic {}".format(credentials)})
assert res.status_code == 200
Python 3 is a little stricter about data sanity, so you have to make sure that the bytes are properly decoded before sending them to the server:
def test_index(test_client):
credentials = b64encode(b"test_user:test_password").decode('utf-8')
res = test_client.get("/", headers={"Authorization": f"Basic {credentials}"})
assert res.status_code == 200
I found this solution. Maybe it can help someone:
from requests.auth import _basic_auth_str
headers = {
'Authorization': _basic_auth_str(username, password),
}
You just have to use the library 'requests'
from requests.auth import _basic_auth_str
headers = {
'Authorization': _basic_auth_str(username, password)
}
This works for me on both python 3.6 and 2.7 whereas the following only works for me on 2.7:
res = test_client.get("/", headers={"Authorization": "Basic {user}".format(user=b64encode(b"test_user:test_password"))})
If you are using new version of python (in my case 3.7) you should decode base64 string. It returns bytes and after stringify it looks like
b'basestring' which is not correct.
>>> base64.b64encode(b"user:password")
b'dXNlcjpwYXNzd29yZA=='
>>> base64.b64encode(b"user:password").decode()
'dXNlcjpwYXNzd29yZA=='
So, now my tests look like
class TestServer(unittest.TestCase):
def setUp(self) -> None:
self.client = app.test_client()
user_credentials = base64.b64encode(b"user:password").decode()
self.headers = {"Authorization": "Basic {}".format(user_credentials)}
Here is how I have wrote unit tests for API's that require authentication with custom token.
###### In your conftest.py file have the below methods
from connexion import FlaskApp
logging.basicConfig(level=logging.DEBUG)
API_FOLDER = pathlib.Path(__file__).parent / '..'
#pytest.fixture(scope="session")
def insecure_client(): # This is used for route tests that DO NOT require authorization.
cxn_app = FlaskApp(__name__,
port=5001,
specification_dir=API_FOLDER,
debug=True,
options={"debug": True, "swagger_ui": False})
cxn_app.add_api('your_api.yaml', resolver=RestyPlusResolver('api.routes'))
cxn_app._spec_file = 'your_api.yaml'
# connection stores the Flask app at app
cxn_app.app.config['SOME_KEY'] = config.CONFIG['SOME_KEY']
flask_jwt.JWT(cxn_app.app, None, None)
flask_cors.CORS(cxn_app.app)
cxn_app.app.app_context()
return cxn_app.app.test_client()
#pytest.fixture(scope="session")
def secure_client(): # This is used for route tests that REQUIRE authorization.
cxn_app = FlaskApp(__name__,
port=5001,
specification_dir=API_FOLDER,
debug=True,
options={"debug": True, "swagger_ui": False})
cxn_app.add_api('open_api.yaml', resolver=RestyPlusResolver('api.routes'))
cxn_app._spec_file = 'openapi.yaml'
# connection stores the Flask app at app
cxn_app.app.config['SOME_KEY'] = config.CONFIG['SOME_KEY']
flask_jwt.JWT(cxn_app.app, None, None)
flask_cors.CORS(cxn_app.app)
cxn_app.app.app_context()
client = cxn_app.app.test_client()
json_dict = {'user': 'your_username', 'password': 'your_pwd'}
# call the auth to get a token which can be used for API calls that require authentication.
# see below on how this is used in pytest of a route.
response = client.post('/auth', data=json.dumps(json_dict), content_type='application/json')
data = json_of_response(response)
setattr(client, '__token', data['token'])
return client
def post_json(client, url, json_dict):
"""Send dictionary json_dict as a json to the specified url """
return client.post(url, data=json.dumps(json_dict), content_type='application/json')
def json_of_response(response):
"""Decode json from response"""
return json.loads(response.data.decode('utf8'))
### Example Pytest of API that requires authentication.
def test_my_post(mocker, secure_client):
json_dict = {'id': 'TEST_01', 'phone': 'PHONE_02'}
mocker.patch('yourapi.services.User.create_user', return_value=("Success", 201))
response = secure_client.post('/user', data=json.dumps(json_dict), content_type='application/json', headers={'X-Auth':secure_client.__token})
data = json_of_response(response)
assert response.status_code == 201
assert data == "Success"