cannot create flask login test function - python-3.x

I have a login function with user and pass parameters that returns a token. I'am using flask.
Now i need a test case to test my function, i am lost here.
Neve done testing and i can't come up with the solution.
I need a test case that verifies a token was created when the login is made.
Any help?
def login():
user = request.form['user']
passwd = request.form['passwd']
test = ldap.bind_user(user, passwd)
if test is None or passwd == '':
response = jsonify(message='Invalid Credentials')
return response ,401
access_token = create_access_token(identity=user)
return jsonify(access_token=access_token), 200```

After 2 days i finally manage to come up with the solution.
I checked if access_token was in the response.data
def test_token_sent(self):
tester = app.test_client(self)
response = tester.post(
'/login',
data =dict(user="hermes", passwd ="hermes"),
follow_redirects=True)
self.assertIn(b'access_token', response.data)```

Related

Error while creating middleware in Django to authenticate a user from different microservice

Building Microservices With Django and pyJWT
Let me explain this in summarised manor, maybe someone can help me out been at this for too long
I have three microservices i.e.
Authentication : Which creates the User and makes the token for a user using RS256 algorithm
Student : which is basically a user type that needs to be verified using JWT
Investor : which is also a user type that needs to be verified using JWT
[I have tried to make a generic create token function in authentication service something like]
data = {"id": user.uuid.hex, "type": user.user_type}
encoded = jwt.encode(data, private_key, algorithm="RS256")
return encoded
It is generating a correct token i have verified using JWT.io
In my student service i have created a middleware something like this
class JWTAuthenticationMiddleware(object):
#Simple JWT token based authentication.
#Clients should authenticate by passing the token key in the "Authorization"
#HTTP header, prepended with the string "Bearer ". For example:
# Authorization: Bearer <UNIQUE_TOKEN>
keyword = "Bearer"
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
auth = request.META.get("AUTHORIZATION", None)
splitted = auth.split() if auth else []
if len(splitted) == 2 and splitted[0] == self.keyword:
if not splitted or splitted[0].lower() != self.keyword.lower().encode():
return None
if len(splitted) == 0:
msg = _("Invalid token header. No credentials provided.")
raise exceptions.AuthenticationFailed(msg)
elif len(splitted) > 2:
msg = _("Invalid token header. Token string should not contain spaces.")
raise exceptions.AuthenticationFailed(msg)
user = get_user(request)
decoded = verify_token(auth)
try:
student = Student.objects.get(user_id=decoded.get("id"))
except Student.DoesNotExist:
student = Student.objects.update(user_id=decoded.get("id"))
response = self.get_response(request)
return response
My verify_token function looks like
def verify_token(token):
decoded = jwt.decode(token, JWT_AUTH["PUBLIC_KEY"], algorithms=["RS256"])
return decoded
I have also added my middleware in my settings just below authentication middleware
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"corsheaders.middleware.CorsMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"config.middleware.authentication.JWTAuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.common.BrokenLinkEmailsMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
I am just not able to decode my token and assign the payload to respective user type, Can someone help me out where i am going wrong? I have also tried using Authentication backend something like this, it doesn't works, have implemented simple_jwt_djangorestframework package but it doesn't decode my payload on student service and says invalid token so i don't want to add it for increasing unnecessary code too.
My viewset looks like this
class StudentViewset(viewsets.ViewSet):
queryset = Student.objects.filter(is_active=True)
serializer_class = StudentSerializer
lookup_field = "uuid"
permission_classes = [IsAuthenticated]
My error is always saying when i am using isAuthenticated as permission class
"message": "Authentication credentials were not provided.",
Maybe validating raw token should work :
decoded = verify_token(splitted[1])
Actually you don't have to implement it. There is simple jwt package for it. Install the package by its documentation and if it wouldn't work provide errors to help you.
To answer this question myself for future references
class JWTAuthenticationMiddleware(object):
#Simple JWT token based authentication.
#Clients should authenticate by passing the token key in the "Authorization"
#HTTP header, prepended with the string "Bearer ". For example:
# Authorization: Bearer <UNIQUE_TOKEN>
keyword = "Bearer"
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
auth = request.META.get("AUTHORIZATION", None)
splitted = auth.split() if auth else []
if len(splitted) == 2 and splitted[0] == self.keyword:
if not splitted or splitted[0].lower() != self.keyword.lower().encode():
return None
if len(splitted) == 0:
msg = _("Invalid token header. No credentials provided.")
return JsonResponse(data=msg, status=403, safe=False)
elif len(splitted) > 2:
msg = _("Invalid token header. Token string should not contain spaces.")
return JsonResponse(data=msg, status=403, safe=False)
user = get_user(request)
decoded = verify_token(auth)
try:
student = Student.objects.get(user_id=decoded.get("id"))
return self.get_response(request)
except Student.DoesNotExist:
msg = _("Invalid User Not found")
return JsonResponse(data=msg, status=403, safe=False)
couple of things that i was doing wrong was not passing a response when i found a student that's why middleware was not bypassed at that time, also exceptions cannot be used at middleware level middleware only returns HTTPResponses, thus i thought of using JsonResponse.

Class for API call: how to correctly handle token

So far, I was using API methods with functions
But now I am trying to build a class with every methods that have an API.
My main concern is about handling correctly the generation of the token. This is a basic authentification with a user/password i send in an xml with the /token resquest.
Once I generate an object, I want to get a token and refresh it when it expires. I want to avoid to get a token to each request I will make.
In the constructor, I put the user, password and root url of the API.
I also put self.token_access = get_token(self) with get_token the method to request a token.
If I put a refresh token before each request (one method by request), it will work. However, it will refresh the token (add time to the expiration date) but it would like to do so, only if the token is dead.
How would be the most elegant way to do so ?
Thank you a lot for your help
Please find some details of what I did so far below. This class is working, however, when I will build an API object,if the token expire, it won't manage the refresh of the token...
class API:
def __init__(self,host,user,password):
self.host = host
self.user = user
self.password = password
self.token = self.get_token()
def get_token(self):
xml = "<userCredentials><login>" +self.user+ "</login><password>" +self.password+ "</password></userCredentials>"
Response = requests.post(self.host + "tokens", data=xml, headers={"Content-Type": "application/xml"})
if Response.ok:
print(Response.content)
root = et.fromstring(Response.content)
token_session = root.find('tokenId').text
return token_session
else:
Response.raise_for_status()
def refresh_token(self):
try:
requests.put(self.host + "tokens" + "/" + self.token_access, data=xml, headers={"Content-Type": "application/xml"})
return self.token_access
except:
return self.get_token()
def methodap1_1(self):
...

how can repeat signup aws cognito [solve]

solve is here gist
when sign up in our app, sign up with aws cognito and send verify email with code.
if user close app not input verify, user have to re sign up. (saved in cognito userpool state UNCONFIRM)
and it occur two problem.
password may be changed (when re sign up)
renew verify code
my code is here python3 and warrant
#app.route('/signup/', methods=['POST'])
def signup():
u = Cognito(os.getenv('COGNITO_USER_POOL_ID'), os.getenv('COGNITO_CLIENT_ID'),
user_pool_region=os.getenv('COGNITO_REGION'))
u.add_base_attributes(name=user_name, email=user_email)
u.register(user_email, user_password)
return redirect(url_for('lobby'))
err code
botocore.errorfactory.UsernameExistsException: An error occurred (UsernameExistsException) when calling the SignUp operation: An account with the given email already exists.
how to re signup with renew password, and send new verify email
Thanks
oh, i solve
#app.route('/signup/', methods=['POST'])
def signup():
idp_client = boto3.client('cognito-idp')
'''
resp = idp_client.sign_up(ClientId=app_client_id,
Username=user_email,
Password=user_password,
UserAttributes=[{'Name': 'email', 'Value': user_email}])
'''
resp = idp_client.resend_confirmation_code(ClientId=os.getenv('COGNITO_CLIENT_ID'),
Username=user_email)
print(resp) #check result
return redirect(url_for('lobby'))
use boto3 i want (resend not acquire password)

Unexpected AssertionError: single test not using logged in user from previous step

I am following the tutorial by http://www.patricksoftwareblog.com/flask-tutorial/, which I believe is based on https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world. Great stuff for a beginner.
I am getting different results when testing my code through frontend manually (which works fine) v.s. through pytest.
My test tries to show the "groups" endpoint which requires a login (standard #login_required decorator).
I initially test the user getting a login page ("Knock knock") when trying to get the endpoint without a login. This works manually and through pytest.
I login a user. If I inspect the response from the login I can clearly see a "Welcome back Pete!" success message.
My second assert receives a response from URL /login?next=%2Fgroups indicating the /groups endpoint is called without a login/authentication preceding it and the assert fails. Testing this manually works as expected. Why is that single test not using the same user/session combination in the next step(s)?
Test with the problem is the first snippet below:
def test_groups(app):
assert b'Knock knock' in get(app, "/groups").data
login(app, "pete#testmail.com", "pete123")
assert b'Test group 1' in get(app, "/groups").data
My "get" function for reference:
def get(app, endpoint: str):
return app.test_client().get(endpoint, follow_redirects=True)
My "login" function for reference:
def login(app, email="testuser#testmail.com", password="testing"):
return app.test_client().post('/login', data=dict(email=email, password=password), follow_redirects=True)
The app (from a conftest fixture imported in the test module by #pytest.mark.usefixtures('app')) for reference:
#pytest.fixture
def app():
"""An application for the tests."""
_app = create_app(DevConfig)
ctx = _app.test_request_context()
ctx.push()
yield _app
ctx.pop()
The login route for reference:
#app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm(request.form)
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user is not None and user.is_correct_password(form.password.data):
user.authenticated = True
user.last_login = user.current_login
user.current_login = datetime.now()
user.insert_user()
login_user(user)
flash(f'Welcome back {user.name}!', 'success')
return redirect(url_for('our_awesome_group.index'))
else:
flash('Incorrect credentials! Did you already register?', 'error')
else:
flash_errors(form)
return render_template('login.html', form=form)
The groups route for reference:
#app.route('/groups')
#login_required
def groups():
groups_and_users = dict()
my_group_uuids = Membership.list_groups_per_user(current_user)
my_groups = [Group.query.filter_by(uuid=group).first() for group in my_group_uuids]
for group in my_groups:
user_uuids_in_group = Membership.list_users_per_group(group)
users_in_group = [User.query.filter_by(uuid=user).first() for user in user_uuids_in_group]
groups_and_users[group] = users_in_group
return render_template('groups.html', groups_and_users=groups_and_users)
Im going to sum up the comments I made that gave the answer on how to solve this issue.
When creating a test app using Pytest and Flask there are a few different ways to go about it.
The suggested way to create a test client with proper app context is to use something like:
#pytest.fixture
def client():
""" Creates the app from testconfig, activates test client and context then makes the db and allows the test client
to be used """
app = create_app(TestConfig)
client = app.test_client()
ctx = app.app_context()
ctx.push()
db.create_all()
yield client
db.session.close()
db.drop_all()
ctx.pop()
That creates the client while pushing the app context so you can register things like your database and create the tables to the test client.
The second way is show in OP's question where use app.test_request context
#pytest.fixture
def app():
"""An application for the tests."""
_app = create_app(DevConfig)
ctx = _app.test_request_context()
ctx.push()
yield _app
ctx.pop()
and then create the test client in another pytest fixture
#pytest.fixture
def client(app):
return app.test_client()
Creating a test client allows you to use various testing features and gives access to flask requests with the proper app context.

How to logout in Python Bottle?

I have the following test snippet:
def check(username, password):
if username == "b" and password == "password":
return True
return False
#route('/logout')
#route('/logout', method="POST")
def logout():
# template with a logout button
# this does redirect successfully, but this shouldn't happen
redirect('/after-login')
#route('/after-login')
#auth_basic(check)
def after_login():
return "hello"
#route('/login')
#route('/login', method="POST")
def login():
return template("views/login/login_page")
username = post_get('username')
password = post_get('password')
I'm attempting to log out of the system, but I haven't been able to find any resources on how to do this. Basically, I tried dir(response) and dir(request) and haven't found any functions that appears to set the session off (mostly attempting to reset cookies), unless I close the browser.
Issued the same problem. Well, The decision I found in docs and used is response.delete_cookie('<cookiename>')
So every time I enter the page with setting any cookies, first I delete all possibble to change cookies.
You want to log out of HTTP Basic Auth, which is not really what it was designed for. But there does seem to be a way: return an HTTP 401.
from bottle import abort
#route('/logout', method=["GET", "POST"])
def logout():
abort(401, "You're no longer logged in")
Does this work?

Resources