How can i perform basic authentication in bottle framework? in flask i used to:
def check( username, password ):
# This function is called to check if a username/password combination is valid
return username == 'nikos' and password == '******'
def authenticate():
# Sends a 401 response that enables basic auth
return Response( 'Credentials of a registered user required!', 401, {'WWW-Authenticate': 'Basic realm="User!"'} )
and called as:
auth = request.authorization
if not auth or not counters.check( auth.username, auth.password ):
return counters.authenticate()
How can i achieve the same in Bottle framework?
As reported here, Bottle natively contains a decorator that makes Basic Auth pretty straightforward:
from bottle import auth_basic, request, route
def is_authenticated_user(user, password):
# You write this function. It must return
# True if user/password is authenticated, or False to deny access.
#route('/')
#auth_basic(is_authenticated_user)
def home():
return ['hooray, you are authenticated! your info is: {}'.format(request.auth)]
Adapted from ron rothman with a basic auth solution using werkzeug.
from bottle import auth_basic, request, route
from werkzeug.security import generate_password_hash, check_password_hash
users = {'user1': generate_password_hash('pwd!')}
def is_authenticated_user(user, password):
# You write this function. It must return
# True if user/password is authenticated, or False to deny access.
return user in users and check_password_hash(users[user], password)
#route('/')
#auth_basic(is_authenticated_user)
def home():
return ['hooray, you are authenticated! your info is: {}'.format(request.auth)]
Related
I'm working my way through Miguel Grinberg's book Flask Web Development, and I've run into a snag in Chapter 14 (Application Programming Interfaces) with the authentication routine. I'm attempting to update the code to use the current version of flask-HTTPAuth according to the example code in the github repo. I can authenticate to HTTPBasicAuth with email/password, but when I try to pass a token I still get a password prompt.
Here is my app/api/authentication.py file:
from flask import g, jsonify
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth, MultiAuth
from ..models import User
from . import api
from .errors import forbidden, unauthorized
basic_auth = HTTPBasicAuth()
token_auth = HTTPTokenAuth(scheme='Bearer')
multi_auth = MultiAuth(basic_auth, token_auth)
#basic_auth.verify_password
def verify_password(email, password):
if email == '':
return False
user = User.query.filter_by(email=email).first()
if not user:
return False
g.current_user = user
g.token_used = False
if user.verify_password(password):
return user
else:
return False
#token_auth.verify_token
def verify_token(token):
user = User.verify_auth_token(token)
if user:
g.current_user = user
g.token_used = True
return user
else:
return False
#basic_auth.error_handler
def auth_error():
return unauthorized('Invalid credentials')
#token_auth.error_handler
def auth_error():
return unauthorized('Invalid credentials')
#api.before_request
#multi_auth.login_required
def before_request():
if not g.current_user.is_anonymous and not g.current_user.confirmed:
return forbidden('Unconfirmed account')
#api.route('/tokens/', methods=['POST'])
#multi_auth.login_required
def get_token():
if g.current_user.is_anonymous or g.token_used:
return unauthorized('Invalid credentials')
return jsonify({'token': g.current_user.generate_auth_token(), 'expiration': 3600})
I'm using Python 3.10.6, Flask 2.2.2 and HTTPie 3.2.1. What am I doing wrong?
I've figured it out. The current version of HTTPie (3.2.1) needs to know whether you're sending a token or a userid:password pair. To do this, you use the command
http --auth <username>:<password> ...
for basic authentication or
http --auth-type bearer --auth <token> ...
for token authentication.
I'm trying to create a login system using Flask and HTTP Basic Auth. My question is, is it my responsibility to provide user information from databases, or does basicauth create and access those databases for me? If it doesn't, what can I use to do that?
Werkzeug can decode the Basic Authorization header for you, into the username and password. The rest is up to you to see what you want to do with that information.
The request.authorization attribute returns a Authorization object. For basic authentication headers, only username and password are set.
A project like Flask-Login can help you manage more complex logins with Basic Authorization, and tie that in with a user model you provide. That model can be stored in a database or anything else you so desire.
And you can look at Flask-Security for a more fully integrated security package that uses Flask-Login and other packages to provide Basic Authentication and session based logins.
The Flask-HTTPAuth extension (shameless plug, I'm the author) simplifies the implementation of HTTP Basic Auth. Instead of working with the request.authorization data directly you set up callback functions where you plug the authentication logic.
Regarding your database question, Flask-HTTPAuth makes no assumptions about how your users are stored. You have to provide the logic that retrieves users and validates passwords.
Werkzeug parses the Authorization header into request.authorization, which is an Authorization object.
For security reasons, a browser might only send this header if it first received a 401 error response with a WWW-Authenticate header set. A different client, such as the requests library, will send the header directly.
The simplest demonstration of this is a decorator that checks request.authorization and returns a 401 response if it's not set, or if the credentials were invalid. In practice, you should use an extension such as Flask-Login or Flask-HTTPAuth to manage this.
from functools import wraps
from flask import request
def login_required(f):
#wraps(f)
def wrapped_view(**kwargs):
auth = request.authorization
if not (auth and check_auth(auth.username, auth.password)):
return ('Unauthorized', 401, {
'WWW-Authenticate': 'Basic realm="Login Required"'
})
return f(**kwargs)
return wrapped_view
#app.route('/secret')
#login_required
def secret():
return f'Logged in as {request.authorization.username}.'
import requests
response = requests.get('http://127.0.0.1:5000/secret', auth=('world', 'hello'))
print(response.text)
# Logged in as world.
Here's a Flask Basic authentication example using Python decorator function.
It will return 401, Authentication required if not auth or wrong auth.
Flask API
def check_auth(username, password):
return username == 'username' and password == 'password'
def login_required(f):
""" basic auth for api """
#wraps(f)
def decorated_function(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
return jsonify({'message': 'Authentication required'}), 401
return f(*args, **kwargs)
return decorated_function
#app.route('/', methods=["GET"]
#login_required
def home():
return {"Hello": "world"}
While requesting on server
response = requests.get(url, auth=('username', 'password'))
I am using python flask to build a simple web app, in which user can hit a path say localhost:8000/ and login. if login is successful, another page is displayed, but i want to know how can I redirect to the main page, if the user is already logged in ? for example, if I log in for the first time, I am taken to the main page, and if I open a second tab and again hit the url for login, I am redirected to the main page automatically( much like gmail? ).
class LoginPage(object):
def on_get(self, req, resp, form={}):
For very simple applications HTTP Basic Auth is probably good enough. Flask makes this very easy. The following decorator applied around a function that is only available for certain users does exactly that:
from functools import wraps
from flask import request, Response
def check_auth(username, password):
"""This function is called to check if a username password combination is valid. """
return username == 'admin' and password == 'secret'
def authenticate():
"""Sends a 401 response that enables basic auth"""
return Response(
'Could not verify your access level for that URL.\n'
'You have to login with proper credentials', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'})
def requires_auth(f):
#wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
return authenticate()
return f(*args, **kwargs)
return decorated
To use this decorator, just wrap a view function:
#app.route('/secret-page')
#requires_auth
def secret_page():
return render_template('secret_page.html')
If you are using basic auth with mod_wsgi you will have to enable auth forwarding, otherwise apache consumes the required headers and does not send it to your application: WSGIPassAuthorization.
I am new to Flask and have been working on an existing app for its login module. It has to be delivered asap. The login credentials validates by Active Directory authentication, which is working as expected. I am referring this flask link which says
url_for('main', page=2): return the internal URL /?page=2. All optional keyword arguments are treated as GET parameters.
My index page is loaded from here (working perfectly):
#app.route("/", methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
userName = request.form['username']
pwd = request.form['password']
try:
ldapobject = auth.bind(userName,pwd)
return redirect(url_for('scheduler')) ----> NEED TO PASS USER AND PWD TO scheduler function using post here
except ldap.LDAPError, error_message:
error = 'Invalid Credentials. Please try again'
return render_template('login.html', error=error)
My scheduler function:
#app.route("/home", methods=['POST'])
def scheduler():
# some code here
# WANT TO HAVE USER CREDENTIALS IN THIS FUNCTION FROM login page
return render_template("scheduler.html", scheduler=form)
Problem: How to pass user's credentials to scheduler method as a POST call
If you want to persist user data between your application pages - you will need to store some session data on user side, e.g. cookies.
flask-login module (https://flask-login.readthedocs.org/en/) can do all the dirty work for you.
In short you need to create User class with several required fields and methods (https://flask-login.readthedocs.org/en/latest/#your-user-class) and specify several methods with decorators to load and check users that are being authenticated:
from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app=app)
#login_manager.user_loader
def load_user(username):
return User(username)
#login_manager.request_loader
def load_from_request(request):
return User.auth_is_valid(request.authorization)
After that you can mark any routes that need user credentials with #login_requied decorator and access logged in user via current_user variable:
from flask_login import login_required, current_user
#app.route("/user_needed")
#login_required
def some_function():
print(current_user)
I'm trying to have my backend server sign and send the username at the end of an OAuth request. The example I'm trying to follow uses this package (https://www.npmjs.com/package/express-jwt) but my backend is in Google App Engine. So, I was wondering how I can achieve the same (signing the username with some secret) inside the App Engine/webapp2 framework?
First download python jwt to folder lib of projects
Code:
import cgi
import datetime
import webapp2
from base_handler import BaseRequestHandler, login_required
from webapp2 import Route
from models import Customer
from lib import jwt
import logging
def login_required(fn):
def check(self, *args, **kargs):
auth = self.request.headers.get('Authorization')
login_info = jwt.decode(auth, 'secret', algorithms=['HS256'])
# your verify login token here
logging.error(login_info)
# verify success
fn(self, *args, **kargs)
return check
class LoginHandler(BaseRequestHandler):
def login(self):
username = self.request.get('username')
password = self.request.get('password')
if Customer.login(username, password) is True:
encoded = jwt.encode({'username': username}, 'secret', algorithm='HS256')
self.response.write({'token': encoded})
return
self.response.write('login unsuccess', status=404)
class APIHandler(BaseRequestHandler):
#login_required
def get(self):
self.response.write('product found')
app = webapp2.WSGIApplication([
Route('/login', handler=LoginHandler, handler_method='login', name='login', methods=['POST']),
('/', APIHandler)
], debug=True)
Note: for test client you can usage postman and add header (token are get from login request)