Password protect a whole django app - python

I am running a simple staging env on heroku and I am now looking to password protect the whole app with some sort of simple authentication
I am wondering if there is a simple app or middleware that already supports this.
Have tried looking around for solutions with Heroku / Cloudflare and django, but nothing seems really straight forward.
Django 1.3.1

I use django-lockdown for exactly this purpose. It allows you to add a simple password over the whole of a dev site, without having to add in any extra auth bits on your views that aren't used outside of a dev environment. It also means you can login as admin, or regular users to test whatever your site does
https://github.com/Dunedan/django-lockdown
I use Heroku and Lockdown with this bit of code in my settings.py file
USE_LOCKDOWN = os.environ.get('USE_LOCKDOWN', 'False') == 'True'
if USE_LOCKDOWN:
INSTALLED_APPS += ('lockdown',)
MIDDLEWARE_CLASSES += ('lockdown.middleware.LockdownMiddleware',)
LOCKDOWN_PASSWORDS = (os.environ.get('LOCKDOWN_PASSWORD', 'False'),)
LOCKDOWN_URL_EXCEPTIONS = (r'^/some/url/not/locked/down/$',)
Then obviously set a config var of USE_LOCKDOWN as True on my dev site, and False on my production site so no need to change the code for either.

Django's authentication framework has built-in utilities #login_required which helps you to password protect your view functions (and its corresponding "url" of course).
Usage like this:-
from django.contrib.auth.decorators import permission_required, login_required
#login_required
def view_organization(request, org_slug):
"""
Only permit a logged in user to view the organization.
"""
org = get_object_or_404(organization, slug=org_slug)
org_users = organizationuser.objects.filter(organization=org,\
organization__is_active=true)
template = 'organizations/view_organization.html'
template_vars = {'org_users': org_users, 'org': org}
return render(request, template, template_vars)
For advanced access control, use #permission_required decorator.

Related

Custom Authentication in Django Rest Framework

I have a django rest framework application with custom authentication scheme implemented. Now I want to allow external app call some methods of my application.
There's an endpoint for external app to login /external-app-login which implemented like this:
class ExternalAppLoginView(views.APIView):
def post(self, request):
if request.data.get('username') == EXTERNAL_APP_USER_NAME and request.data.get('password') == EXTERNAL_APP_PASSWORD:
user = models.User.objects.get(username=username)
login(request, user)
return http.HttpResponse(status=200)
return http.HttpResponse(status=401)
Now I want to add authentication. I implemented it like this:
class ExternalAppAuthentication(authentication.SessionAuthentication):
def authenticate(self, request):
return super().authenticate(request)
But authentication fails all the time. What is the correct way to do it? I want to store login/password of external app in variables in application, not in database.
The authentication fails, because it needs to return a registered user in your database to authenticate. However as the user info is all in variables instead of database, the issue arises.
There are more than one ways to overcome this issue. Firstly i would suggest you write the authentication code instead of using
return super().authenticate(request) as this would lead you to the real reason of the issue.
Also must give a read to this documentation link, it clears a lot of things regarding authentication.
https://www.django-rest-framework.org/api-guide/authentication/
Now after you have done all that, and you seek ways how to authenticate, then you can try either remote user authentication, or you can check for existing users in your variables and use anonymous user for authentication which resolves the issue.

Flask Security giving routing error on security.register

While trying to link to Flask-Securities register view in my template with:
<li>Register</li>
I get a routing error
werkzeug.routing.BuildError
werkzeug.routing.BuildError: Could not build url for endpoint 'security.register'. Did you mean 'security.login' instead?
From what I've searched around for, setting the Flask Security config line "SECURITY_REGISTERABLE" to True should have fixed it, and yet it's set to True and I'm still getting this error...
I setup Flask Security in my models.py like so:
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
I just had the exact same error after refactoring my app. In my new app.py I missed these config settings:
# More Flask Security settings
app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_REGISTER_URL'] = '/admin/create_account'
app.config['SECURITY_LOGIN_URL'] = '/admin/login'
app.config['SECURITY_POST_LOGIN_VIEW'] = '/admin'
app.config['SECURITY_LOGOUT_URL'] = '/admin/logout'
app.config['SECURITY_POST_LOGOUT_VIEW'] = '/admin'
app.config['SECURITY_RESET_URL'] = '/admin/reset'
app.config['SECURITY_CHANGE_URL'] = '/admin/change'
app.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = ['email', 'username']
The example above uses url endpoint inside my "Flask Admin" /admin
In your case i'm not exactly sure: by default flask security should be able to find the template folder and routes in the Flask Security package I think. The quickstart docs don't mention any routes that you've you need to manually setup.
You'll also need a app config with something like this:
app.secret_key = 'SECRETSTUFF'
Probably an good idea to add explicit routes for the register page.
The above error is occuring because there is no register() route available in the security blueprint or may be you have named register route as login() in your code. Plz recheck your code. By my little knowledge in flask-Security i think register view is enabled by default. To define the register view you just need to decorate the route using #security.route('/register). I hope this is useful.

Simple auth method for a Flask application?

I work on my simple blogging system written in Python, Flask and SQLite,
and I've created a simple authorization system for it. There is no need for anything fancy, so it's just a matter of sending login and password through a form and setting a flag in Flask's session. I wanted to know how things like this are done, so I didn't use any modules.
I'm wondering if this method is correct and secure just enough.
# from auth module
#auth.route('/login', methods=['POST'])
def login():
"""Login as blog admin."""
# Successeful login conditions
user_is_valid = request.form['user'] == current_app.config['USER']
password_is_valid = request.form['password'] == current_app.config['PASSWORD']
trap_is_empty = not request.form['trap']
# Login user if credentials are correct
if user_is_valid and password_is_valid and trap_is_empty:
session['is_admin'] = True
return redirect(url_for('admin.posts_page'))
else:
return render_template('auth.html')
# from admin module
#admin.before_request
def before_request():
""" Before any request check admin flag, redirect to the main page if there is none. """
if not session.get('is_admin'):
return redirect(url_for('blog.index_page'))
proj.db.connect()
It honestly looks fine for just a basic authentication system. The bad part is storing the credentials in the config.
If you want to get all cool and fancy, you can use itsdangerous to generate hashes and salts of passwords and store them in your sqlite database.
Typically, you'd have a table with id, username, password, and a boolean flag like "is_admin" or something that you can check when you authenticate.
So, it's fine for some playing around, but I wouldn't recommend anything like this in production.

Avoiding redundant code in mobile/desktop with Django sites framework

According to the Django docs, the best practice for serving a mobile and desktop application would appear to be the following:
views.py
from django.contrib.sites.models import Site
def my_view(request):
current_site = Site.objects.get_current()
if current_site.domain == 'foo.com':
# Render desktop home page
elif current_site.domain == 'm.foo.com':
# Render mobile home page
Unfortunately this means that I'll be making the if/then choice in every single view I write. Is it possible for me to instead do the following:
views.py
from django.contrib.sites.models import Site
current_site = Site.objects.get_current()
if current_site.domain == 'foo.com':
def my_view(request):
# Render desktop home page
elif current_site.domain == 'm.foo.com':
def my_view(request):
# Render mobile home page
I'd like to get some sense of the possibility here before I start tearing through my views.py in an attempt to test this the hard way.
Have you looked at this app: http://pypi.python.org/pypi/django-mobility?
Using a middleware for detecting the device and decorators to switch templates depending on the incoming device are a good approach to avoid redundant if/else constructs.
And if you look at the examples given for django-mobility they look pretty similiar to your desired construct:
def view(request):
...
#mobilized(view)
def view(request):
...
You can use middleware to detect whether or not the request is to the 'm' subdomain or not, and then specify the correct URL conf to direct you to the views you want. I've been using a modified version of the django-subdomains app for this and it's been working nicely. This is an effective and simple solution if your view logic for your mobile site is quite different from the view logic of your regular site. Here's the link:
https://github.com/tkaemming/django-subdomains
Then all you have to do is write a new URL conf for your mobile site, specify this in your settings, and then write your views/templates for your mobile site just like you would for your regular app.

Excluding a Django app from being localized using a middleware

I need to localize a django project, but keep one of the applications (the blog) English only.
I wrote this middleware in order to achieve this:
from django.conf import settings
from django.core.urlresolvers import resolve
class DelocalizeMiddleware:
def process_request(self, request):
current_app_name = __name__.split('.')[-2]
match = resolve(request.path)
if match.app_name == current_app_name:
request.LANGUAGE_CODE = settings.LANGUAGE_CODE
Problem is, it assumes the middleware lies directly in the application module (e.g. blog/middleware.py) for retrieving the app name. Other projects might have the middleware in blog/middleware/delocalize.py or something else altogether.
What's the best way to retrieve the name of the currently running app?
You can use Django's resolve function to get the current app name.
https://docs.djangoproject.com/en/dev/topics/http/urls/#resolve

Categories