-
Notifications
You must be signed in to change notification settings - Fork 2
Django Authentication Basics
A VERY BASIC and not very secure cookie-based authentication system has been implemented in Django for the OPS. The actual storage and management of the authentication (in the database) is secure, but how clients authenticate (by passing simple cookies and plain-text passwords) is not.
Django User Profile Application
Setting Season Group (public/private)
Telling Django to include the models (database schema) for authentication is as simple as including the following lines in the settings.py file.
Add 'django.contrib.auth',
to INSTALLED_APPS
Add 'django.contrib.auth.middleware.AuthenticationMiddleware',
to MIDDLEWARE_CLASSES
With those two lines on the syncdb
command all the framework needed to store basic Django users is created.
To have a custom user profile tied to each Django user (containing custom permissions) we need to add a few things in settings.py AND create some new files.
The new files created are in ops/opsuser/*
. The only key one is models.py:
from django.contrib.gis.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.OneToOneField(User,related_name="profile", unique=True)
rds_season_groups = models.ManyToManyField('rds.season_groups',null=True)
rds_layer_groups = models.ManyToManyField('rds.layer_groups',null=True)
accum_season_groups = models.ManyToManyField('accum.season_groups',null=True)
accum_layer_groups = models.ManyToManyField('accum.layer_groups',null=True)
snow_season_groups = models.ManyToManyField('snow.season_groups',null=True)
snow_layer_groups = models.ManyToManyField('snow.layer_groups',null=True)
kuband_season_groups = models.ManyToManyField('kuband.season_groups',null=True)
kuband_layer_groups = models.ManyToManyField('kuband.layer_groups',null=True)
layerGroupRelease = models.BooleanField(default=False)
seasonRelease = models.BooleanField(default=False)
createData = models.BooleanField(default=False)
bulkDeleteData = models.BooleanField(default=False)
isRoot = models.BooleanField(default=False)
def create_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
profile.rds_season_groups = [1]
profile.accum_season_groups = [1]
profile.snow_season_groups = [1]
profile.kuband_season_groups = [1]
profile.rds_layer_groups = [1,2]
profile.accum_layer_groups = [1,2]
profile.snow_layer_groups = [1,2]
profile.kuband_layer_groups = [1,2]
post_save.connect(create_profile, sender=User)
This file defines an additional schema in the database for a user profile. Note the last line post_save.connect(create_profile, sender=User)
which tells Django to create a new profile with a 1-1 relationship with a Django user each time a new user is created.
In settings.py we need to add the following:
Add the line AUTH_PROFILE_MODULE = 'opsuser.UserProfile'
Add 'opsuser',
to INSTALLED_APPS
Creating users is simple. One can use the createUser() view or follow the procedure outlined below. This procedure is stored in /vagrant/conf/tools/createUserExample.py which also contains instructions for running the script.
- Become user root
sudo -i
- Activate the virtual environment
source /usr/bin/venv/bin/activate
- Start the Django shell
python /var/django/ops/manage.py shell
- Modify the following code (set username,email,password) and paste into the Django shell. You can also edit the default permissions if you want to. The permissions shown are for a default CReSIS internal data user.
from django.contrib.auth.models import User
# set new user properties
userName=''
userEmail=''
userPassword=''
# create the new user
newUser = User.objects.create_user(userName, userEmail, userPassword)
# set the user profile options (example for cresis superuser)
newUser.profile.rds_layer_groups = [1,2]
newUser.profile.accum_layer_groups = [1,2]
newUser.profile.kuband_layer_groups = [1,2]
newUser.profile.snow_layer_groups = [1,2]
newUser.profile.rds_season_groups = [1,2]
newUser.profile.accum_season_groups = [1,2]
newUser.profile.kuband_season_groups = [1,2]
newUser.profile.snow_season_groups = [1,2]
newUser.profile.layerGroupRelease = True
newUser.profile.bulkDeleteData = False
newUser.profile.createData = True
newUser.profile.seasonRelease = True
# save the user profile
newUser.profile.save()
To add/remove permissions from an existing user, root users can use the alterUserPermissions() view. User authentication information is stored in the auth_user table. The opsuser_userprofile table maps the auth_user ID to the opsuser ID. The particular layer group can be found in the SYS_layer_groups table (e.g. rds_layer_groups). The SQL command might look like INSERT INTO opsuser_userprofile_rds_layer_groups (userprofile_id,layer_groups_id) VALUES (38,7)
. Administrators can also execute the following commands in the Django shell using Django:
from django.contrib.auth.models import User
userObj = User.objects.get(username_exact='ENTERNAMEHERE')
userProf = userObj.profile
# TO ADD SOMETHING
userProf.rds_layer_groups.add(SOMEGROUPID)
# TO REMOVE SOMETHING
userProf.rds_layer_groups.delete(SOMEGROUPID)
# TO SAVE CHANGES
userProf.save()
To add user USERNAME to layer group GROUP, run the following query:
INSERT INTO opsuser_userprofile_rds_layer_groups (userprofile_id,layer_groups_id) VALUES ((SELECT opsuser_userprofile.id FROM auth_user,opsuser_userprofile WHERE auth_user.username=''USERNAME'' AND auth_user.id=opsuser_userprofile.user_id),(SELECT id FROM rds_layer_groups WHERE name=''GROUP''))
Seasons can either be public (group 1) or private (group 2). The season name is usually a string of a form similar to 2011_Greenland_P3. For example, to make season SEASON private:
UPDATE rds_seasons SET season_group_id=2 WHERE name=''SEASON''
An example would be to check if a user is allowed to create data. From createPath in views.py:
models,data,app,cookies = utility.getInput(request) # get the input and models
userProfileObj,status = utility.getUserProfile(cookies)
if status:
if not userProfileObj.createData:
return utility.response(0,'ERROR: USER NOT AUTHORIZED TO CREATE DATA.',{})
else:
return utility.response(0,userProfileObj,{});
The cookies (from whatever client, see getData
in utility.py) are retrieved in the call to getInput
. Then the function getUserProfile(cookies)
is used to retrieve the user profile object. At that point it's just logical checks against permissions.
Django is setup to be open to all IP addresses from the Apache interface. Access to write interfaces is supported by a Django decorator and IP addresses need to be added to the authip.py file located at /var/django/ops/ops.
Location | IP Address range -------------------+------------------ Lindley Hall | 129.237.14[45].{0-255} Nichols Hall | 129.237.16[45].{0-255} Indiana University | 149.165.2{29,30}.{0-255} VM Net | 10.0.2.2, 127.0.0.1, 192.168.111.{0-255}