I am implementing basic authentication to validate username and password with the following code:
def auth_required(f):
#wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
cur = get_db().cursor().execute("SELECT * FROM users where user_name='parag'")
result = cur.fetchall()
if auth and auth.username == result[0][user_name] and auth.password== result[0][password]:
return True
return make_response('could not verify', 401, {'WWW-authenticate' : 'Basic realm = "Login Required"'})
return decorated
#app.route("/")
#auth_required
def index():
data = request.get_json()
cur = get_db().cursor())
return '''<h1> hi paarg </h1>'''
but auth.username and auth.password is none.
auth = request.authorization is coming as a NoneType.
Please help.
Related
I have this main.py file. I am creating a jwt token here at /auth endpoint. After the token is generated, now I am unable to redirect it to base path("/"). How can I achieve that. If I try to access the / path, i get redirected to auth endpoint with the bearer token displayed. Any help or pointers on how this can be done.
main.py
from authlib.integrations.starlette_client import OAuth
oauth = OAuth()
CONF_URL = "https://localhost:8080/.well-known/openid-configuration"
oauth.register(
name="cad",
server_metadata_url=CONF_URL,
client_id=settings.CLIENT_ID,
client_secret=settings.CLIENT_SECRET,
client_kwargs={"scope": "openid email profile authorization_group"},
)
oauth2_scheme = OAuth2PasswordBearer(tokenUrl='/auth')
def create_access_token(*, data: dict, expires_delta: datetime.timedelta = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.datetime.utcnow() + expires_delta
else:
expire = datetime.datetime.utcnow() + datetime.timedelta(minutes=15)
to_encode.update({'exp': expire})
encoded_jwt = jwt.encode(to_encode, "abcd", algorithm="HS256")
return encoded_jwt
def create_token(id):
access_token_expires = datetime.timedelta(minutes=120)
access_token = create_access_token(data={'sub': id}, expires_delta=access_token_expires)
return access_token
#app.middleware("http")
async def authorize(request: Request, call_next):
if not (request.scope["path"].startswith("/login") or request.scope["path"].startswith("/auth")):
if not is_session_okay(request.session):
return RedirectResponse(url="/login")
return await call_next(request)
#app.get("/login")
async def login(request: Request):
redirect_uri = request.url_for("auth")
return await oauth.cad.authorize_redirect(request, redirect_uri)
#app.get("/auth")
async def auth(request: Request):
try:
token = await oauth.cad.authorize_access_token(request)
except OAuthError as error:
return HTMLResponse(f"<h1>{error.error}</h1>")
user = await oauth.cad.parse_id_token(request, token)
access_token = create_token(user['sub'])
return {"access_token": access_token, "token_type": "bearer"}
#app.get("/", tags=["Web-UI"])
def index():
frontend_root = "./ui"
return FileResponse(str(frontend_root) + "/index.html", media_type="text/html")
Since you are using fastapi you should use it's jwt implementation.
The framework provide classes especialy for that => OAuth2PasswordBearer and OAuth2PasswordRequestForm
the doc on this is available in the advanced documentation:
(from the doc)
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
class Token(BaseModel):
access_token: str
token_type: str
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
#app.post("/token", response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
I am trying to build a decorator to verify aws cognito token.
Below is the dummy code that I tried.
Is there any improvements needed or is it correct way.
def verify_cognito_token(func):
def wrapper(*args, **kwargs):
parser.add_argument('Authorization', location='headers')
args = parser.parse_args()
token = args.get("Authorization")
print("Inside wrapper : ", token)
if token:
try:
verified_claims: dict = cognitojwt.decode(
token,
config['aws']['aws_cognito_region'],
config['aws']['aws_cognito_userpool_id'],
app_client_id = config['aws']['aws_cognito_app_client_id'] # Optional
# testmode=True # Disable token expiration check for testing purposes
)
print("Token verified")
val = func(*args, **kwargs)
return val
except CognitoJWTException as e:
print("Token expired")
return {"message":400}
else:
print("Token missing")
return {"message":401}
return wrapper
class HomePage(Resource):
#verify_cognito_token
def post(self):
parser.add_argument('Authorization', location='headers')
args = parser.parse_args()
print("Inside method: ",args)
return jsonify({"success":200})
api.add_resource(HomePage, "/index")
I am working with Spotify API to request song data through a URL. I imported urlencode to run the song's ID as a function parameter into the url. Essentially, I need the ID portion of the url request to be the ID by itself, not "id=<id string>"
I tried assigning the id string to a parameter of my 'search' function. The search function takes a user input song ID from spotify, inserts it into the proper position in the URL request, and sends it to the spotify database to retrieve that songs data analysis. The program successfully sends out the request, but the id portion I am filling in puts "id=<song ID>" instead of the song ID by itself.
import requests
import datetime
from urllib.parse import urlencode
# In[3]:
import base64
# In[4]:
client_id = 'fb5af83351d4402fa82904fc04f7fc9e'
client_secret = 'b5057eb39b024180b61b02eb45fb97a6'
# In[5]:
class SpotifyAPI(object):
access_token = None
access_token_expires = datetime.datetime.now()
access_token_did_expire = True
client_id = None
client_secret = None
token_url = "https://accounts.spotify.com/api/token"
def __init__(self, client_id, client_secret, *args, **kwargs):
super().__init__(*args, **kwargs)
self.client_id = client_id
self.client_secret = client_secret
def get_client_credentials(self):
client_id = self.client_id
client_secret = self.client_secret
if client_secret == None or client_id == None:
raise Exception("You must set client_id and client_secret")
client_creds = f"{client_id}:{client_secret}"
client_creds_b64 = base64.b64encode(client_creds.encode())
return client_creds_b64.decode()
def get_token_headers(self):
client_creds_b64 = self.get_client_credentials()
return {
"Authorization": f"Basic {client_creds_b64}"
}
def get_token_data(self):
return {
"grant_type": "client_credentials"
}
def perform_authorization(self):
token_url = self.token_url
token_data = self.get_token_data()
token_headers = self.get_token_headers()
r = requests.post(token_url, data=token_data, headers=token_headers)
print(r.json())
if r.status_code not in range(200,299):
raise Exception("Could not authenticate client")
#return False
data = r.json()
now = datetime.datetime.now()
access_token = data['access_token']
expires_in = data['expires_in'] #seconds
expires = now + datetime.timedelta(seconds=expires_in)
self.access_token = access_token
self.access_token_expires = expires
self.access_token_did_expire = expires < now
return True
def get_access_token(self):
token = self.access_token
expires = self.access_token_expires
now = datetime.datetime.now()
if expires < now:
self.perform_authorization()
return self.get_access_token()
elif token == None:
self.perform_authorization()
return self.get_access_token()
return token
def search(self, id):
access_token = self.get_access_token()
headers = {
"Authorization": f"Bearer {access_token}"
}
end_point = "https://api.spotify.com/v1/audio-analysis/"
data = urlencode({"id":id})
print(data)
lookup_url = f"{end_point}{data}"
print(lookup_url)
r = requests.get(lookup_url, headers = headers)
if r.status_code not in range(200, 299):
return r
return r.json()
it returns
{'access_token': 'BQCLoKT_b2PF7KPSbscosa1dCpE5rzd_RBkswOvwklVdlAL4AeEGCDn0iYuqac5o86BTqCIz0m95u3olLp4', 'token_type': 'Bearer', 'expires_in': 3600}
id=1UGD3lW3tDmgZfAVDh6w7r
https://api.spotify.com/v1/audio-analysis/id=1UGD3lW3tDmgZfAVDh6w7r
I have created a fixture to create user and auto login in conftest.py
#pytest.fixture
def test_password():
return 'strong-test-pass'
#pytest.fixture(scope='session')
def create_user(db, test_password):
def make_user(**kwargs):
employee = e_ge_employee.objects.create()
kwargs['password'] = test_password
if 'username' not in kwargs:
kwargs['username'] = str(uuid.uuid4())
if 'employee' not in kwargs:
kwargs['employee'] = employee
return e_ge_user.objects.create(**kwargs)
return make_user
#pytest.fixture
def auto_login_user(db, client, create_user, test_password):
def make_auto_login(user=None):
if user is None:
user = create_user()
client.login(username=user.username, password=test_password)
return client, user
return make_auto_login
and then wrote a testcase to check get api in test_urls.py
class TestUrls:
#pytest.mark.parametrize('param', [
('generate_token'),
('roi_report')
])
def test_generate_token_url(self, auto_login_user, param):
url = reverse(param)
client, user = auto_login_user()
print("client",client)
print("user",user)
resp = client.get(url)
print(resp)
assert resp.status_code == 200
It is giving me the error
{"detail":"Authentication credentials were not provided."}
in my api_views I am using authentication_classes = [SessionAuthentication, ]
permission_classes = [IsAuthenticated, ] these two classes
Can someone please provide me with the solution.....Thanks in Advance
Try rewriting your auto_login_user as follows to force_authenticate the user.
first import APIClient from rest_framework.test
# import
from rest_framework.test import APIClient
#pytest.fixture
def auto_login_user(db, create_user):
api_client = APIClient()
api_client.force_authenticate(user=create_user)
return api_client
and now update your test as follows
def test_generate_token_url(self, auto_login_user, create_user, param):
url = reverse(param)
user = create_user
resp = auto_login_user.get(url)
print(resp)
assert resp.status_code == 200
if this doesn't work maybe the problem is with the create_user fixture
I'm trying to implement flask_jwt_extended to my flask app.
My Use Case is, I want to set Authorization headers to every request. So that when a #jwt_required decorator is decorated to a flask route it can be access if an access token is present on the Authorization headers.
I've tried some solutions like the one below:
I use #app.after_request to attach headers to every request but still it gives me this response
{
"msg": "Missing Authorization Header"
}
Here is my code:
#app.after_request
def add_headers(resp):
access_token = session.get("access_token", None)
if access_token is not None:
resp.headers["Authorization"] = f"Bearer {access_token}"
return resp
return resp
my login route:
#app.route('/', methods=["GET", "POST"])
def login():
if request.method == "POST":
form = request.form
_username = form["username"]
_password = form["password"]
for username in Users:
if username.get(_username):
if safe_str_cmp(username[_username]["password"],_password):
access_token = create_access_token(identity=username[_username]["user_id"], fresh = True)
session["access_token"] = access_token
res = make_response(redirect(url_for("home")))
res.headers["Authorization"] = f"Bearer {access_token}"
return res
else:
return "Incorrect password"
return f"Hello{_username} doesn't exist"
return render_template("login.html")
Here is my protected route:
#app.route('/home')
#jwt_required
def home():
res = Response(render_template("base.html"))
return res
I've also tried adding my headers in the route,But it still the headers I specify are not recognize and still give me the same response message. Here's how do it
#app.route('/home')
#jwt_required
def home():
access_token = session.get("access_token", None)
print(access_token)
if access_token is not None:
res = Response(render_template("base.html"), headers={"Authorization" : f"Bearer {access_token}"})
return res
res = Response(render_template("base.html"))
return res
Writing this for those who will come across this and are trying to implement an OAuth flow
Don't use decorators use middleware instead
I believe you should handle this in a middleware. In the middleware, you can set the authorization property of the 2nd parameter of the call function which contains the current wsgi app environment variables you have passed in your init function. Look at code below:
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
cookie = Request(environ).cookies.get('access_token')
if cookie is not None:
environ['HTTP_AUTHORIZATION']='Bearer '+cookie
return self.app(environ, start_response)