I'm trying to resolve problem with Basic Authentication in flask using HTTPBasicAuth.
When I'm accessing using curl or web browser everything works well.
This are examples which works:
curl -u [access_token]:unused -i X GET http://127.0.0.1:5000/api/v1/token
or
http://[access_token]:unused#127.0.0.1:5000/api/v1/token
But when I'm using Authorization: Basic [token] or Authorization: Basic [token]:unused in header of request I get 500 error from server.
Verifying access token or email and password:
#auth.verify_password
def verify_password(email_or_token, password):
user = User.verify_auth_token(email_or_token)
if not user:
user = User.query.filter_by(email = email_or_token).first()
if not user or not user.verify_password(password):
return False
g.user = user
return True
User model:
class User(db.Model):
def generate_auth_token(self, expiration = 600):
s = Serializer(app.config['SECRET_KEY'], expires_in = expiration)
return s.dumps({ 'id': self.id })
#staticmethod
def verify_auth_token(token):
s = Serializer(app.config['SECRET_KEY'])
try:
data = s.loads(token)
except SignatureExpired:
return None # valid token, but expired
except BadSignature:
return None # invalid token
user = User.query.get(data['id'])
return user
I found that when I'm using token or email and password in header as Basic [token/email]:[password/unused], email_or_token and password properties are None.
Error: TypeError: argument of type 'NoneType' is not iterable
Why error occurs while using Authorization: Basic [token/email]:[password/unused] in header of request? What is solution for this?
You must Base64-encode the the credential portion of your Authorization header. This can be done with the command line base64 utility.
echo 'token:unused' | base64
From the example here, the username password combination of Aladdin:OpenSesame becomes:
Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l
The reason that you don't have to worry about this with curl or the browser, is that they will perform the encoding automatically for you.
Related
I have a django rest API end point login which takes username and password in form of json object as below.
{
username: email,
password: password,
}
and returns a json object containing a token
{
token : 0234jh324234j2hiy342
}
Now i want to write a test in behave. I have following feature file.
Feature: Login User
By providing different credentials we check if our login API end point is working as expected or not
Scenario: Login User by Providing Authentication Credentials
Given I provide user authentication credentials
Then I must get a reponse with status code 200 and a jSon object with token
and following is my auth.py file
from behave import *
import requests
import json
#given('I have user authentication credentials')
def set_impl(context):
url = 'https://example.com/v1/login'
headers = {'content-type': 'application/json'}
body = {
"username": "xyz#email.com",
"password": "abcdef123",
}
#when('I make an http post call')
def step_impl(context):
context.res = requests.post(url, data=json.dumps(body), headers=headers)
#then('I must get a reponse with status code 200 and a jSon object with token')
def step_impl(context):
assert context.res.status == 200
I am unable to access the url, header and body from #given decorator in #when decorator. And how can i check the json in response against my expected json.
Per #KlausD.'s suggestion, you should add your variables to the behave's context object. I've edited your code to add your variables as the context object's attributes.
from behave import *
import requests
import json
#given('I have user authentication credentials')
def set_impl(context):
context.url = 'https://example.com/v1/login'
context.headers = {'content-type': 'application/json'}
context.body = {
"username": "xyz#email.com",
"password": "abcdef123",
}
#when('I make an http post call')
def step_impl(context):
context.res = requests.post(context.url, data=json.dumps(context.body), headers=context.headers)
#then('I must get a reponse with status code 200 and a jSon object with token')
def step_impl(context):
assert context.res.status == 200
As for checking the JSON in your response against your expected JSON...
Check out the requests package's response object here to find out how to get the response object's attributes.
Open your own expected JSON file via open(), grab the value that corresponds to the token key, and do an assert expectedToken == responseToken, or something of that sort.
I am creating an app for use in our organization that will login users based on their Office 365 credentials using OAuth2.0. I am fetching an access token that I will store in a session variable. Here is an example of what I am doing:
#never_cache
def authorization(request):
microsoft = OAuth2Session(client_id,scope=scope,redirect_uri=redirect_uri)
token = ""
try:
users = 'https://graph.microsoft.com/v1.0/me' ##msgraph query url-
##This query is purelyjust used to
##authenticate user!
token = microsoft.fetch_token(token_url,client_secret=client_secret,code=request.GET.get('code', '')) ##Code is the authorization code present
##in request URL
header = {'Authorization': 'Bearer ' + token['access_token']}
response = requests.get(url = users, headers = header)
if int(response.status_code) != 200: ##if status code is not 200, then authentication failed. Redirect to login.
print ('Not validated. Return to login.')
request.session.flush()
return redirect('http://localhost:8000/login')
except Exception as e:
print ('User not does not have authentication rights')
request.session.flush()
return redirect('http://localhost:8000/login')
request.session['oauth_state'] = 'authorized'
response = HttpResponseRedirect('http://localhost:8000/search')
return response
I am then using this to check if 'oauth_state' is set to 'authorized'. However, I may change this so that the token is used to query the MS Graph API in each function in order to check if the user has proper permissions or not. Here's an example of what I am doing:
def search(request):
try:
if (str(request.session['oauth_state']) != 'authorized'):
print ('Not authorized')
request.session.flush()
return redirect('http://localhost:8000/login')
except Exception as e:
print ('Not authorized')
request.session.flush()
return redirect('http://localhost:8000/login')
<rest of code>
How insecure is this? Should I possibly be passing in the token to the response header? Or should I get rid of this method, and use django's standard auth and login system? I really appreciated the benefits of OAuth2.0, but if this method compromises our security, I might scrap it.
I have some problems.
I am new to python and flask.
I am building an API that makes queries to a database, a separate application front end and back end. But problems have come to rescue the search result with the Flask.
Example:
The Following 'curl' command registers a new user with username 'miguel' and password 'python':
$ Curl -X POST -H -i "Content-Type: application / json
'd' {"username":" miguel","password":"python"} 'http://127.0.0.1:5000/api/users
RETURN:
HTTP / 1.0 201 CREATED Content-Type: application / json
Content-Length: 27 Location: http://127.0.0.1:5000/api/users/1 Server:
Werkzeug / Python 0.9.4 / 2.7.3 Date: Thu, 28 Nov 2013 19:56:39 GMT {
"username": "miguel" }
Through doterminal we return the username, someone knows a way to retrieve and display the user's name on the front end.
Resaltar it should consider font end and back and running on different machines.
--------UPDATE-------
BACKEND
#app.route('/api/users', methods=['POST'])
def new_user():
username = request.json.get('username')
password = request.json.get('password')
if username is None or password is None:
abort(400) # missing arguments
if User.query.filter_by(username=username).first() is not None:
abort(400) # existing user
user = User(username=username)
user.hash_password(password)
db.session.add(user)
db.session.commit()
return (jsonify({'username': user.username}), 201,
{'Location': url_for('get_user', id=user.id, _external=True)})
FRONTEND
#home_blueprint.route('/cadastro', methods=['POST'])
def cadastro():
username = request.form['username']
password = request.form['password']
if username and password:
url = 'http://127.0.0.1:4000/api/users'
payload = {'username': username,'password':password}
headers = {'content-type': 'application/json'}
r = requests.post(url, data=json.dumps(payload), headers=headers)
else:
return "ERRO"
return "Create new user sucesso!"
(post my comment as an answer)
You could simply use r.text to get the requests.post's retun data, from the document:
When you make a request, Requests makes educated guesses about the encoding of the response based on the HTTP headers. The text encoding guessed by Requests is used when you access r.text.
So just replace
return "Create new user sucesso!"
with
return r.text
In this case, r.text is requests.post(url, data=json.dumps(payload), headers=headers) return data, was created by:
return (jsonify({'username': user.username}), 201,
{'Location': url_for('get_user', id=user.id, _external=True)})
I am trying to authenticate user using FIWARE.
It returns a 404. Thus fails at Step 1 itself. What is the access token url ? Any other pointers to check
I have tried variations with 'oauth/access_token', 'oauth/token' 'oauth2/token' 'oauth2/access_token' . All of them dont seem to work.
My Code is Below:
import oauth2 as oauth
# OAuth secret into your project's settings.
consumer = oauth2.Consumer(settings.FIWARE_CLIENT_ID,settings.FIWARE_CLIENT_SECRET)
client = oauth2.Client(consumer)
access_token_url = 'https://account.lab.fiware.org/oauth2/access_token'
# This is the slightly different URL used to authenticate/authorize.
authenticate_url = 'https://account.lab.fiware.org/oauth2/authorize'
def fiware_login(request):
# Step 1. Get a request token from FIWARE.
resp, content = client.request(access_token_url, "GET")
print resp
if resp['status'] != '200':
print content
raise Exception("Invalid response from FIWARE.")
# Step 2. Redirect the user to the authentication URL.
url = "%s?access_token=%s" % (authenticate_url,
resp['access_token'])
return HttpResponseRedirect(url)
Correct endpoint is "/oauth2/token".
Maybe you should use POST method instead of GET.
For more information see https://github.com/ging/fi-ware-idm/wiki/Using-the-FI-LAB-instance
I have a problem with using creepymap.py
I try to get it to authorize Twitter account.. but I get error message:
/usr/share/creepy $ python creepymap.py
Traceback (most recent call last):
File "creepymap.py", line 515, in button_authorize_twitter
url = self.oauth.get_authorization_url(True)
File "/usr/lib/python2.7/dist-packages/tweepy/auth.py", line 103, in get_authorization_url
raise TweepError(e)
tweepy.error.TweepError: HTTP Error 401: Unauthorized
Ive looked in auth.py and I try to follow the code with the comments for example:
def get_authorization_url(self, signin_with_twitter=False):
"""Get the authorization URL to redirect the user"""
try:
# get the request token
self.request_token = self._get_request_token()
# build auth request and return as url
if signin_with_twitter:
url = self._get_oauth_url('authenticate')
else:
url = self._get_oauth_url('authorize')
request = oauth.OAuthRequest.from_token_and_callback(
token=self.request_token, http_url=url
)
later on I read this:
def get_xauth_access_token(self, username, password):
"""
Get an access token from an username and password combination.
In order to get this working you need to create an app at
http://twitter.com/apps, after that send a mail to api#twitter.com
and request activation of xAuth for it.
"""
try:
url = self._get_oauth_url('access_token', secure=True) # must use HTTPS
request = oauth.OAuthRequest.from_consumer_and_token(
oauth_consumer=self._consumer,
http_method='POST', http_url=url,
parameters = {
'x_auth_mode': 'client_auth',
'x_auth_username': username,
'x_auth_password': password
}
)
is there anything I should change in the code?
P.S Sorry for my english. It is not my native language.
Thank you!
EDIT:
I just wanted to close thread with answering my own question after some more research..
And follow instructions here on how get xAuth: https://dev.twitter.com/docs/oauth/xauth