I'm running Django 2.2.24 and Locust 2.1.0 for load testing. When I run some Locust test logging in as a the Django admin user, there are no issues - all my GETs work as expected.
Now I am actually logging in as a specific user. From a web interface, Django passes a CSRFtoken and a sessionid token with no problem. From the Locust client however, the sessionid does not show up at all. Not only that, but when I look in the django_session table (where the web tokens do exist), there are no tokens for the Locust client.
I think this is more related to Django session management than to locust - hence the post in this forum.
My locust file looks like this:
def on_start(self):
'''
The start script for each user - this order is important
'''
# Below 3 lines work fine - we get the csrftoken and put it in the header successfully
response = self.client.get("/accounts/login")
self.csrftoken = response.cookies['csrftoken']
self.headers = {'X-CSRFToken': self.csrftoken}
# Now login with username and password as POST
r1 = self.login()
return r1
def login(self):
# admin login and retrieving it's access token
udata = {'username': self.username, 'password': self.password}
cookies=self.client.cookies.get_dict())
#csrftoken cookie does exist, sessionid does not yet.
log.info("Current cookies in Login:" + str(self.client.cookies))
# This next line should come back with a sessionid
# from Django - but it does not.
response = self.client.post("/accounts/login/",
data=json.dumps(udata),
headers=self.headers)
log.info("Response from client.post="+str(response)) #OK
log.info("Response status code:" + str(response.status_code))
log.info("Response text=" + response.text)
# Next line does not contain sessionid or Set-Cookie
log.info("Headers from post/accts/login = " + str(response.headers))
Thanks for any assistance.
Change
response = self.client.post("/accounts/login/",
data=json.dumps(udata),
headers=self.headers)
to
response = self.client.post("/accounts/login/",
json=udata,
headers=self.headers)
… to get the appropriate json headers. Or use:
response = self.client.post("/accounts/login/",
data=udata,
headers=self.headers)
in order to send it as form-encoded data instead of json.
Related
I am integrating google calendar with my web application which is a django app. when i am doing it on localhost server, its working fine. Google authentication page opens in client browser, but when i am uploading that code to the server and integrating google calendar, then Google authentication page opens in terminal where i run my django server.
This is the page that opens for authentication in terminal
I want to provide this auth through client web browser.
`
def get_credentials(request):
creds = None
# If there are no (valid) credentials available, let the user log in.
if os.path.exists('token.pickle_' + request.GET.get('bot_id')):
with open('token.pickle_' + request.GET.get('bot_id'), 'rb') as token:
creds = pickle.load(token)
print(creds)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
CLIENT_SECRET_FILE, SCOPES)
creds = flow.run_local_server()
# Save the credentials for the next run
with open('token.pickle_' + request.GET.get('bot_id'), 'wb') as token:
pickle.dump(creds, token)
serializer = CalenderIntegrationSerializer(data={'bot_id': int(request.GET.get('bot_id')), 'status': True})
if serializer.is_valid():
serializer.save()
if os.path.exists('token.pickle_' + request.GET.get('bot_id')):
context = {'signin_url': creds}
return JsonResponse({'status': 200, 'data': 'Integration done!', 'is_integrated': True})
`
And this is my reference google calendar code python
This code is specifically for local development:
https://developers.google.com/api-client-library/python/auth/installed-app
The code gives you a hint on how to construct the URL, which you then need to send back to your user as a temporary redirect; e.g. using the redirect function. Then you need to have a django handler which accepts the redirect and executes the second half of the function. So:
Split your code into two functions.
Build a url, send a redirect with your endpoint as the callback
Google will redirect back to your endpoint after the user completes the flow.
Parse the results
Execute your code.
I'm trying to build a serverless Flask APP. To login users, I use auth0.com.
After the user logs in I get an access token, I send a post request with it to my flask backend and there I exchange the token for the user info doing this:
#app.route('/callback', methods=['POST'])
#cross_origin()
def callback_handling():
resp = request.get_json()
url = 'https://' + AUTH0_DOMAIN + '/userinfo'
headers = {'authorization': 'Bearer ' + resp['access_token']}
r = requests.get(url, headers=headers)
userinfo = r.json()
# Store the tue user information in flask session.
session['jwt_payload'] = userinfo
session['profile'] = {
'user_id': userinfo['sub'],
'name': userinfo['name'],
'picture': userinfo['picture']
}
Once I've done this I redirect the user to their dashboard. There I send a second post request to fetch the user profile, something like this:
#app.route('/profile', methods=['POST'])
#cross_origin()
def user_profile():
if 'profile' in session:
return jsonify({'profile':session['profile']})
else:
return jsonify({'profile':"Not logged in"})
This second function returns always {'profile':"Not logged in"}.
So I'm wondering what's the best way to do this. Should I always send back the auth0 token, send a request to them to ask who is the user and then return his data? It seems like an overkill to send always a request to auth0 everytime I need to return some data. Is there a better method?
I developed a webserver using BaseHttpServer module.
in that i created a login page.html and getting the username and password details and sending to the request = requests.session()
s= request.get(username, password)
print s.text #which is session cookie
I logged in successfully and doing the get, post operations.
The problem is when other user trying to hit the url after the login page he is accessing my session cookie and doing all operations.
how to restrict that and is there any method of handling multiple user sessions at a time to login to the SSO page which i am calling that url in get method
import json
import getpass
import requests
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
port = 8000
returns
class S(BaseHTTPRequestHandler):
Page = '''\
# Myloginpage code in html
'''
get = '''\
#My Get login page html Details Form
'''
def _set_headers(self):
self.send_response(200)
self.send_header("Content-Type","text/html")
self.end_headers()
def do_Get(self):
if self.path =='/':
self.wfile.write(self.Page) #My login page
# Get operations which is working
def do_POST(self):
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)
post_data_tmp = post_data.split('&')
for querystring in post_data_tmp:
if 'uname' in querystring:
username= querystring.split('=')[1]
if 'psw' in querysting:
password = querystring.split('=')[1]
ssosession = xyz.sso.session(username, password)
s = ssosession.get('xyzurl',verify = False)
S.cookie = requests.utils.dict_from_cookiejar(ssosession)
# I am passing this cookie to connect to the api and get the details
def run(server_class=HTTPServer, handler_class = S, port = port)
server_address = ('',port)
httpd = server_class(server_address,handler_class)
print 'starting httpd...'
httpd.serve_forever()
if __name__="__main__":
from sys import argv
if len(argv) = =2:
run(port = int(argv[1])
else:
run()
when the webbrowser starts i opened the url http://xyz:8080/ then the login page opens which i created in html . after I submit the username and password , those will be stored and send to the SSo login page to get the cookie . with that session i am successfully can play with the browser.
the issue here is when other user hits the url, he is not authenticating and he is able to do the operations with my session.
could anyone suggest me how to create a session for each http request to authenticate.
if second user clicks the login page , he will be logged in . if suppose if he clicks the other page part of this project he is able to access with my session
I am trying to get social authentication working for my mobile app (an Ionic app on Android). Django rest framework backend with rest_framework_jwt, social_django, and rest_social_auth.
On my Ionic app I was using satellizer.js, however, I can't use InAppBrowser so now I am trying to do the following with cordova-plugin-googleplus:
Step#1 (On client/app)
if (provider == 'google') {
// Use Google API Natively to get tokens and user info
window.plugins.googleplus.login(
{
// TODO Get the WebClient from App settings
'webClientId': '[*.myclientid]', // optional clientId of your Web application from Credentials settings of your project - On Android, this MUST be included to get an idToken. On iOS, it is not required.
'offline': true, // optional, but requires the webClientId - if set to true the plugin will also return a serverAuthCode, which can be used to grant offline access to a non-Google server
}) ................
Result: This gets me a valid response with both a idToken, serverAuthCode, and a userId.
Step#2
I am not sure what the next step is. Originally, I was going to try using Django rest_social_auth to do the following from my client/app:
POST /api/login/social/
with data (json)
provider=google&code=ASLKDJASLDKJASLD
Which was supposed to return a JWT token (from my understanding of the docs), however, it is not passing the JWTAuthMixin as there is no value returned from a call to get_authorization_header(request).split() in that Mixin. These means that nothing is returned to my client/app except a 400 error.
Am I supposed to be adding a header to my Ionic app POST when passing my idToken or serverAuthCode? Or am I on the wrong side of the tracks...
Are there any implementation recommendations for this auth flow?
So far I did the following and it works.
1. On app/client
(The client uses satellizer.js and the cordova-plugin-googleplus)
if (provider == 'google') {
// Use Google API Natively to get tokens and user info
window.plugins.googleplus.login(
{
// TODO Get the WebClient from App settings
'webClientId': '*[googleclientid]*.apps.googleusercontent.com',
'offline': true
},
function (obj) {
$http.post(SERVER.url + '[MY BACKEND URL]' + '/google-oauth2/', {code: obj.idToken, servAuthCode: obj.serverAuthCode})
.success(function(data){
$auth.setToken(data.jwt_token);
/.. Do something ../
})
.error(function(data){
console.log("There was an error" + JSON.stringify(data));
});
},
function (msg) {
// TODO Set Error states
console.error('error: ' + msg);
}
);
}
Summary
The app calls the Google plus API googleplus.login method (sending my webClientId)
I post the resulting idToken and serverAuthCode obtained from google after login to my Django backend.
2. My backend methods
URL
My app/client hits the url(r'^[MY BACKEND URL]/(?P<backend>[\w-]+)/$', ObtainAuthToken.as_view(), ),
View
This calls the following view and functions:
class ObtainAuthToken(APIView):
permission_classes = (AllowAny,)
def post(self, request, backend):
data = request.data
user_tokenID = data['code']
server_auth_code = data['servAuthCode']
if user_tokenID and server_auth_code and verify_google_user_token_ID(user_tokenID):
# Get Google OAuth credentials for the verified GOOGLE user.
credentials = settings.GOOGLE_FLOW.step2_exchange(server_auth_code)
# Here we call PSA to authenticate like we would if we used PSA on server side.
user = register_by_access_token(request, backend, token=credentials.access_token)
# If user is active we get or create the REST token and send it back with user data
if user and user.is_active:
# Generate JWT token for user and pass back to client
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return JsonResponse({'id': user.id, 'name': user.username, 'jwt_token': token})
return JsonResponse({'status':'false','error':'Bad Credentials, check the Access Token and/or the UID'},
status=403)
def verify_google_user_token_ID(user_tokenID):
try:
google_http_request = google.auth.transport.requests.Request()
idinfo = verify_token(user_tokenID, request=google_http_request,
audience=settings.SOCIAL_AUTH_GOOGLE_OAUTH2_FULL_KEY)
# Or, if multiple clients access the backend server:
if idinfo['aud'] not in [settings.GOOGLE_APP_ID_ANDROID, settings.GOOGLE_APP_ID_WEB]:
raise crypt.AppIdentityError("Unrecognized client.")
if idinfo['iss'] not in ['accounts.google.com', 'https://accounts.google.com']:
raise crypt.AppIdentityError("Wrong issuer.")
return True
except crypt.AppIdentityError as e:
# Invalid token
return False
#psa('social:complete')
def register_by_access_token(request, backend, token):
backend = social_core.backends.google.GoogleOAuth2()
user = backend.do_auth(access_token=token, backend=backend)
if user:
return user
else:
return None
3. Back on the client
My client then looks at the response and takes the returned JWT and loads it to memory with $auth.setToken(data.jwt_token);
I think this works for now, but I still have to deal with token refresh and revocation etc.
I am trying to use locust for login to my web application. I am at very beginning of using locust.
I am using the following code for login to application.
post_data = {'username': username, 'password': password,'Submit':'Login' }
with self.client.post('/mylogin-url/', post_data,
catch_response=True) as response:
print response.code
print response.content
This part always returns status code 200 but the login is not succesful, as the response content of source is not the same as the actual source after login
My web application creates cookies and redirect to an URL based on cookie after login. I am trying to understand whether the login operation does this cookie creation automatically from locust or do I need to add that part of cookie creation logic n the script itself.
Any help regarding this is greatly appreciated.
Thanks
You may need to look at this.
In your with block, you can parse the response and check if you get the correct response.
Suppose you should get cookie field in your response cookies if you login success, then you can do like this:
post_data = {'username': username, 'password': password,'Submit':'Login' }
with self.client.post('/mylogin-url/', post_data, \
catch_response=True) as response:
if 'cookie' not in respone.cookies:
response.failure('login failed')
It seems that the response in the html content tells that user hasn't logged in. In that case you can check if response text contains failure message
post_data = {'username': username, 'password': password,'Submit':'Login' }
with self.client.post('/mylogin-url/', post_data,
catch_response=True) as response:
if response.text.contains("Login failed"):
response.failure('login failed')