when I try to return but I got an error in 2nd return signup_result & return login_result
https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportUndefinedVariable
"return" can be used only within a functionPylance
here is utils.py
class CognitoResponse(object):
def __init__(self, access_token, refresh_token, cognito_user_id=None):
self.access_token = access_token
self.refresh_token = refresh_token
self.cognito_user_id = cognito_user_id
def cognito_signup(username: str, password: str):
return signup_result
# In order to get the ID and authenticate, use AWS Cognito
client = boto3.client('cognito-idp', region_name=os.environ.get('COGNITO_REGION_NAME'))
try:
response = client.sign_up(
ClientId=os.environ.get('COGNITO_USER_CLIENT_ID'),
Username=username,
Password=password
)
except Exception as e: # Generally, will trigger upon non-unique email
raise HTTPException(status_code=400, detail=f"{e}")
user_sub = response['UserSub']
# This will confirm user registration as an admin without a confirmation code
client.admin_confirm_sign_up(
UserPoolId=os.environ.get('USER_POOL_ID'),
Username=username,
)
# Now authenticate the user and return the tokens
auth_response = client.initiate_auth(
ClientId=os.environ.get('COGNITO_USER_CLIENT_ID'),
AuthFlow='USER_PASSWORD_AUTH',
AuthParameters={
'USERNAME': username,
'PASSWORD': password
}
)
access_token = auth_response['AuthenticationResult']['AccessToken']
refresh_token = auth_response['AuthenticationResult']['RefreshToken']
signup_result = utils.CognitoResponse(
access_token=access_token,
refresh_token=refresh_token,
cognito_user_id=user_sub
)
return signup_result
def cognito_login(username: str, password: str):
return login_result
client = boto3.client('cognito-idp', region_name=os.environ.get('COGNITO_REGION_NAME'))
# Authenticate the user and return the tokens
try:
auth_response = client.initiate_auth(
ClientId=os.environ.get('COGNITO_USER_CLIENT_ID'),
AuthFlow='USER_PASSWORD_AUTH',
AuthParameters={
'USERNAME': username,
'PASSWORD': password
}
)
except Exception as e: # Generally, will trigger upon wrong email/password
raise HTTPException(status_code=400, detail=f"{e}")
access_token = auth_response['AuthenticationResult']['AccessToken']
refresh_token = auth_response['AuthenticationResult']['RefreshToken']
login_result = utils.CognitoResponse(
access_token=access_token,
refresh_token=refresh_token
)
return login_result
I also try to tab 2 times to avoid indentation error in return signup_result & return login_result but still got the same error Unexpected indentationPylance
def cognito_login(username: str, password: str):
return login_result
client = boto3.client('cognito-idp', region_name=os.environ.get('COGNITO_REGION_NAME'))
# Authenticate the user and return the tokens
try:
auth_response = client.initiate_auth(
ClientId=os.environ.get('COGNITO_USER_CLIENT_ID'),
AuthFlow='USER_PASSWORD_AUTH',
AuthParameters={
'USERNAME': username,
'PASSWORD': password
}
)
# lots more code...
The cognito_login() function contains only one line of code return login_result because that is the only code that is indented underneath the function.
The rest of the following code is not indented underneath the function, therefore it is not part of the function.
Indentation is very important in Python.
Your code should likely be formatted as follows:
def cognito_login(username: str, password: str):
#return login_result remove this as the next lines of code need to run
client = boto3.client('cognito-idp', region_name=os.environ.get('COGNITO_REGION_NAME'))
# Authenticate the user and return the tokens
try:
auth_response = client.initiate_auth(
ClientId=os.environ.get('COGNITO_USER_CLIENT_ID'),
AuthFlow='USER_PASSWORD_AUTH',
AuthParameters={
'USERNAME': username,
'PASSWORD': password
}
)
# lots more code...
Related
I have researched similar questions but can't find an answer that works for me.
I would like to get the username or user_id from a session when a user connects to a websocket.
This is what I have in consumers.py:
class PracticeConsumer(AsyncConsumer):
async def websocket_connect(self, event):
print('session data', self.scope['user'])
await self.send({"type": "websocket.accept", })
...
#database_sync_to_async
def get_user(self, user_id):
try:
return User.objects.get(username=user_id).pk
except User.DoesNotExist:
return AnonymousUser()
This is my asgi.py:
"""
ASGI config for restapi project.
It exposes the ASGI callable as a module-level variable named application.
For more information on this file, see
https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'signup.settings')
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter(websocket_urlpatterns)
)
)
})
and the user login function + token sent when user logs in:
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
authenticate_kwargs = {
self.username_field: attrs[self.username_field],
"password": attrs["password"],
}
try:
authenticate_kwargs["request"] = self.context["request"]
except KeyError:
pass
user = authenticate(**authenticate_kwargs)
if not user:
return {
'user': 'Username or password is incorrect',
}
token = RefreshToken.for_user(user)
# customizing token payload
token['username'] = user.username
token['first_name'] = user.first_name
token['last_name'] = user.last_name
token['country'] = user.profile.country
token['city'] = user.profile.city
token['bio'] = user.profile.bio
token['photo'] = json.dumps(str(user.profile.profile_pic))
user_logged_in.send(sender=user.__class__, request=self.context['request'], user=user)
if not api_settings.USER_AUTHENTICATION_RULE(user):
raise exceptions.AuthenticationFailed(
self.error_messages["no_active_account"],
"no_active_account",
)
return {
'refresh': str(token),
'access': str(token.access_token),
}
Whenever I print out self.scope['user'] upon connecting, I get AnonymousUser
UPDATE
I tried writing some custom middleware to handle simple JWT authentication:
#database_sync_to_async
def get_user(validated_token):
try:
user = get_user_model().objects.get(id=validated_token["user_id"])
print(f"{user}")
return user
except User.DoesNotExist:
return AnonymousUser()
class JwtAuthMiddleware(BaseMiddleware):
def __init__(self, inner):
self.inner = inner
async def __call__(self, scope, receive, send):
close_old_connections()
token = parse_qs(scope["query_string"].decode("utf8"))["token"][0]
try:
UntypedToken(token)
except (InvalidToken, TokenError) as e:
print(e)
return None
else:
decoded_data = jwt_decode(token, settings.SECRET_KEY, algorithms=["HS256"])
print(decoded_data)
scope["user"] = await get_user(validated_token=decoded_data)
return await super().__call__(scope, receive, send)
def JwtAuthMiddlewareStack(inner):
return JwtAuthMiddleware(AuthMiddlewareStack(inner))
However, this gives me this error:
File "C:\Users\15512\Desktop\django-project\peerplatform\signup\middleware.py", line 37, in __call__
token = parse_qs(scope["query_string"].decode("utf8"))["token"][0]
KeyError: 'token'
I need to create a API with a route that is able to recognize if the current user is the one indicated in the request or not (also no auth should be valid)
For the others paths I followed https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/ and everything work with Bearer with JWT tokens like this
user: User = Depends(get_current_active_user)
Modifying the methods provided by the docs I tried with
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth")
async def get_user_or_none(db: Session = Depends(get_db), token: str = Depends(oauth2_scheme)):
"""
Return the current active user if is present (using the token Bearer) or None
"""
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
return None
except JWTError:
return None
# check user in db
user = crud.get_user(db, username)
if user is None:
return None
return user
#router.get("/api/{user_id}/structure")
async def get_user_structure(
user_id: int,
user = Depends(get_user_or_none),
db: Session = Depends(get_db)
):
# do_something() if user.id == user_id else do_something_else()
but I receive an error
401 Error: Unauthorized {
"detail": "Not authenticated"
}
You need to use a different OAuth2PasswordBearer for these optionally authenticated endpoints with auto_error=False, e.g.
optional_oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth", auto_error=False)
async def get_user_or_none(db: Session = Depends(get_db), token: str = Depends(optional_oauth2_scheme)):
...
Now the token will be None when the Authorization header isn't provided, resulting in your desired behavior.
I have a problem with users trying to register on my application (which is a Flask app deployed on Pythonanywhere with MongoDB Atlas).
Basically when they register they receive an email with a token that they need to click on to confirm. When they click on that link they should enter the application, but instead they receive an error.
When I check the error log, this is what I see (under "/auth/register") when it calls:
existing_user = User.get_by_email(session["email"])
return super(SecureCookieSession, self).__getitem__(key)
Exception KeyError: 'email' was thrown out.
It seems that somehow the session["email"] does not work?
This is my code:
#app.route('/confirm/<token>')
def confirm_email(token):
try:
email = ts.loads(token, salt="email-confirm-key", max_age=7200)
except:
return render_template("token_expired.html")
user = Database.find_one(collection="users", query={"email": email})
return redirect(url_for("register_user"))
#app.route("/auth/register", methods=["GET", "POST"])
def register_user():
existing_user = User.get_by_email(session["email"])
if existing_user is None:
email = session["email"].lower() # our website is making a request to our app
username = session["username"]
companyname = session["companyname"].lower()
password = session["password"].encode("utf-8")
hashed_password = bcrypt.hashpw(password, bcrypt.gensalt())
User.register(email, username, companyname, hashed_password)
session["companyname"] = companyname
excisting_company = Database.find_one(collection="companies", query={"email": session["email"]})
if excisting_company is None:
new_company = NewCompany(session["companyname"], session["email"])
new_company.company_save_to_mongo()
else:
return "A company has already been registered under your email address"
else:
return render_template("email_already_exists.html")
return redirect(url_for("user_results"))
#classmethod
def get_by_email(cls, email):
find_email = Database.find_one(collection="users", query={"email": email})
if find_email is not None:
return cls(email=find_email["email"], username=find_email["username"],
companyname=find_email["companyname"], hashed_password=find_email["password"],
date=find_email["date"], _id=find_email["_id"])
I cant seem to figure out why, as when I register myself it works just fine.
Your help would be greatly appreciated here, many thanks in advance.
UPDATE:
Here is where I set the session["email"]:
#app.route("/email_confirmation", methods=["GET", "POST"])
def confirmation():
email = request.form["email"].lower()
companyname = request.form["companyname"].lower()
password = request.form["password"]
username = request.form["username"]
session["password"] = password
session["email"] = email
session["companyname"] = companyname
session["username"] = username
existing_user = User.get_by_email(email)
if existing_user is None:
msg = Message("Confirm your email", sender=("hello#weliketalent.com"),
recipients=[email])
token = ts.dumps(email, salt="email-confirm-key")
confirm_url = url_for("confirm_email", token=token, _external=True)
msg.html = render_template("email/activate.html", confirm_url=confirm_url)
mail.send(msg)
The error is telling you that there is no "email" value in session object.
I don't see you setting this value anywhere in your code. How is it supposed to get there? Somebody needs to set it somewhere before this code runs.
In addition to that, you should design your code not to crash in such cases, as this could be a security vulnerability. You can use if "email" not in session for test.
Package versioning
Flask 1.0.2
Flask-HTTPAuth 3.2.4
Flask-RESTful 0.3.8
itsdangerous 0.24
I'm working on a API project where a POST request to a Todo resource requires an user to have a token. Upon trying to test for this scenario, I'm getting the following assertion error: AssertionError: 401 != 201. Both BasicHTTPAuth and TokenHTTPAutth from flask-HTTPAuth are handling Authorization credentials.
Based on a User having a token to access this resource, I'm not clear on why I'm getting an Unauthorized error.
tests.py
class TestAuthenicatedUserPostTodo(ApiTestCase):
'''Verify that an API user successfully adds a Todo'''
def setUp(self):
super().setUp()
previous_todo_count = Todo.select().count()
user = User.get(User.id == 1)
token_serializer = Serializer(SECRET_KEY)
self.token = token_serializer.dumps({'id': user.id})
def test_todo_collection_post_todo_success(self):
with app.test_client() as client:
http_response = client.post(
"/api/v1/todos/",
headers={
'Authorization': f"Bearer {self.token}"
},
content_type="application/json",
data={
"name": "Must do a todo",
"user": 1
}
)
current_todo_count = Todo.select().count()
self.assertEqual(http_response.status_code, 201)
self.assertGreater(current_todo_count, previous_todo_count)
auth.py
basic_auth = HTTPBasicAuth()
token_auth = HTTPTokenAuth(scheme="Bearer")
auth = MultiAuth(token_auth, basic_auth)
#basic_auth.verify_password
def verify_password(username, password):
try:
api_user = User.get(User.username == username)
except User.DoesNotExist:
return False
user_verified = api_user.check_password(password)
if user_verified:
g.user = api_user
return True
return False
#token_auth.verify_token
def verify_token(token):
timed_serializer = Serializer(SECRET_KEY)
try:
user = timed_serializer.loads(token)
api_user = User.get_by_id(user['id'])
except (SignatureExpired, BadSignature) as e:
abort(400, description=str(e))
return True
todo.py
#auth.error_handler
def errorhandler():
return jsonify(unauthorized="Cannot add Todo. Login required."), 401
class TodoCollection(Resource):
#auth.login_required
def post(self):
import pdb; pdb.set_trace()
args = self.request_parser.parse_args()
if not args['name']:
return make_response(
{'invalid_request': "Invalid todo provided"}, 400
)
new_todo = Todo.create(**args)
return (
marshal(set_todo_creator(new_todo), todo_fields, 'new_todo'),
201, {'Location': f'{new_todo.location}'}
)
I am using token based authentication to restrict the access to user for my site, I am getting following error
{"_status": "ERR", "_error": {"message": "Please provide proper credentials", "code": 401}}weber#weber-desktop:/var/www/lunar-cloud-web-ui/kukunako$
my sample code shown below.
class TokenAuth(TokenAuth):
def check_auth(self, token, allowed_roles, resource, method):
accounts = app.data.driver.db['people']
return accounts.find_one({'token': token})
app = Eve(__name__,static_url_path='/static', auth = TokenAuth)
app.debug = True,
app.config.update(
DEBUG=True,
#EMAIL SETTINGS
MAIL_SERVER='smtp.gmail.com',
MAIL_PORT=465,
MAIL_USE_SSL=True,
MAIL_USERNAME = '<username>',
MAIL_PASSWORD = '<password>'
)
mail=Mail(app)
socketio = SocketIO(app)
def create_token(user):
payload = {
'sub': str(user['_id']),
'iat': datetime.now(),
'exp': datetime.now() + timedelta(days=14)
}
token = jwt.encode(payload, TOKEN_SECRET)
return token.decode('unicode_escape')
def login_required(f):
#wraps(f)
def decorated_function(*args, **kwargs):
if not request.headers.get('Authorization'):
response = jsonify(error='Missing authorization header')
response.status_code = 401
return response
payload = parse_token(request)
if datetime.fromtimestamp(payload['exp']) < datetime.now():
response = jsonify(error='Token has expired')
response.status_code = 401
return response
g.user_id = payload['sub']
return f(*args, **kwargs)
return decorated_function
#app.route('/auth/login', methods=['POST'])
def login():
accounts = app.data.driver.db['people']
user = accounts.find_one({'email': request.json['email']})
if not user:
response = jsonify(error='Your email does not exist')
response.status_code = 401
return response
if not user['email_confirmed'] == True:
response = jsonify(error='Email is not confirmed')
response.status_code = 401
return response
if not user or not check_password_hash(user['password']['password'], request.json['password']):
response = jsonify(error='Wrong Email or Password')
response.status_code = 401
return response
token = create_token(user)
return jsonify(token=token)
my all code is show in following for settings file and server code file
settings file
server code file
How are you testing it?
I can think of two possible problems.
JWT token needs to be base64 encoded
You may have forgotten : at the end
e.g. If your token is as follows (Taken from jwt.io site)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
You need to do the following:
$ echo 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ:' | base64
ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnpkV0lpT2lJeE1qTTBOVFkzT0Rrd0lpd2libUZ0WlNJNklrcHZhRzRnUkc5bElpd2lZV1J0YVc0aU9uUnlkV1Y5LlRKVkE5NU9yTTdFMmNCYWIzMFJNSHJIRGNFZnhqb1laZ2VGT05GaDdIZ1E6Cg==
Now use this as follows (with curl)
curl -H "Authorization Basic ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnpkV0lpT2lJeE1qTTBOVFkzT0Rrd0lpd2libUZ0WlNJNklrcHZhRzRnUkc5bElpd2lZV1J0YVc0aU9uUnlkV1Y5LlRKVkE5NU9yTTdFMmNCYWIzMFJNSHJIRGNFZnhqb1laZ2VGT05GaDdIZ1E6Cg==" http://127.0.0.1:5000/my_secure_endpoint