How to give staff access to newly created User In Django - django

I am new to Djnago and Python.
I created middleware class in Djnago with the name StaffAccessMiddleware
I used social_django app to create user from Gmail and i want to implement
is_staff = True and assign at least one group only if users login in DJango firstTime .
My question is how to access user in middleware and check only first time user will enter in this code in that case i need to assign is_staff = True and assign group once user is created.
I tried to create middle ware class like below.
class StaffAccessMiddleware(object):
def process_request(self, request):
if hasattr(request, 'user') and request.user.is_authenticated():
user = request.user
if groups:
groups[0].name
return None

I would suggest you to use pipeline, something like this:
Add a custom pipeline to update user as is_staff=True
In that pipeline check for is_new parameter and update user only when is_new is True. Social-auth sends is_new=True when user is logging in for first time i.e. when user is created.
Add your custom pipeline in SOCIAL_AUTH_PIPELINE settings.
Then you can restrict some views to staff users only by specifying permission_required settings.
Your final pipeline may look something like this:
def make_new_user_as_staff(backend, user, is_new=False, *args, **kwargs):
if backend.name == 'gmail' and is_new:
user.is_staff = False
user.save()
In settings.py (or settings file)
SOCIAL_AUTH_PIPELINE = (
#other pipelines goes here
"<full-path-to-make_new_user_as_staff-pipeline>",
#some other pipelines goes here
)
Reference : https://python-social-auth-docs.readthedocs.io/en/latest/pipeline.html
Let me know if I have misunderstood your query/this doesn't resolve your issue

Related

Custom user permission based on User Profile Model Filed Role

i am creating a Todo list app using Django rest framework.
in this app only manager can post task in the list.
User Profile has a field named as a role.
I have a User Profile Model with extended User Model.
model.py
class UserProfile(models.Model):
user = models.OneToOneField(User,unique=False)
department = models.CharField(max_length=50, choices=DEPARTMENT_CHOICES,default='technology')
role = models.CharField(max_length=50, choices=ROLE_CHOICES,default='manager')
User Profile have a role field.
I want the only manager can post Task in my app.
How can I write custom user permission in order to achieve this?
Restricted to POST request only. All other requests can be permitted.
You would create a permission which subclasses rest_framework.permissions.IsAuthenticated and add your logic in has_permission(self, request, view) (see more).
If you only want it to be applied to POST, simply check the request's method and return True if it's a different method. Something like:
from rest_framework import permissions
class CustomPermission(permissions.IsAuthenticated):
def has_permission(self, request, view):
if request.user.user_profile.role == 'ADMIN' or request.method != 'POST':
return True
return False
Don't forget to include this permission in your view's permission_classes.
PS: I should warn you, though, it's a bit odd that you'd allow only admins to POST tasks while allowing everyone to PUT and DELETE on them. Maybe you mean you want to allow everyone in safe_methods only (GET, OPTIONS and HEAD)? If that's the case, replace request.method != 'POST' with request.method in permissions.SAFE_METHODS.

Django - PermissionRequiredMixin with custom user model as well as AUTHENTICATION_BACKENDS

I am using Django 1.9. When I tried to add PermissionRequiredMixin to my class-based-view, it seems not to work as expected. I created a new user in a auth_group. This auth_group doesn't have any permission to any apps or models. This new user is not a superuser or admin user. But the app doesn't prevent this user from accessing to a particular view that needs permission_required.
Firstly, here is what I tried to make sure the user doesn't have permission:
user.get_all_permissions() # return set() - empty permission, which is correct.
user.is_superuser # return false, which is correct.
user.has_perm('myapp.add_something or even any words that make no sense') # always return true, which is very weird.
The app has custom user model and also uses django-allauth as the AUTHENTICATION_BACKENDS. I am not sure if PermissionRequiredMixin will check user.has_perm() and it always return true so that's why checking permission doesn't work as expected?
# views.py
class My_View(PermissionRequiredMixin, View):
permission_required = 'polls.can_vote'
def get(self, request, *args, **kwargs):
# do something...
return render(request, "template.html", {})
# models.py - Custom User Model
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
group = models.ManyToManyField(Group, through='UserGroupRelationship')
....
# models.py - many-to-many relationship between user and group
class UserGroupRelationship(models.Model):
user = models.ForeignKey("CustomUser")
user_group = models.ForeignKey(Group)
I also tried the old way to check permission in urls.py. It doesn't prevent user accessing either so I do not think that's the problem of using PermissionRequiredMixin.
urlpatterns = patterns('',
(r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
)
After spending a few days on this problem, I eventually find out the cause.
When I looked into the source code about PermissionRequiredMixin, I found that PermissionRequiredMixin indeed checks user.has_perm(). When I tried to find the source code of has_perm(), I found that my codes (which is copied from the custom user model example from Django's document) contains the following overridden method...
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
That's reason why user.has_perm('anything') always return true, which also affects the functionality of PermissionRequiredMixin. Therefore, if you are new to Django and try to copy some example codes from document, you need to be very careful about each line...

Django Authenticate returns None

I have the following code snippet:
user = User(username='h#h.com',email='h#h.com')
user.set_password('pass')
user.save()
u = authenticate(username='h#h.com', password='pass') #this always returns None!!!
The problem is, u is always None. I've followed code samples on other stack overflow posts and have narrowed it down to the above lines.
Any ideas as to what might be happening?
Put something like this in your settings
#Authentication backends
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)
or if you are using userena for your accounts
#Authentication backends
AUTHENTICATION_BACKENDS = (
'userena.backends.UserenaAuthenticationBackend',
'guardian.backends.ObjectPermissionBackend',
'django.contrib.auth.backends.ModelBackend',
)
Interestingly enough, check_password returns True in the following:
eml = "4#a.com"
pw = "pass"
uname = 'w2'
user = User.objects.create_user(uname,eml,pw)
user.save()
log.debug("Password check passes?")
log.debug(user.check_password(pw)) # Logs True!!!
user = authenticate(username=uname, password=pw)
Why don't you create a user like this:
user = User.objects.create_user( username="whatever", email="whatever#some.com", password="password")
user = authenticate( username="whatever",password="password")
In settings.py, add
AUTH_USER_MODEL = your custom user class
e.g if django app name is office and custom user class is Account then
AUTH_USER_MODEL = 'office.Account'
set_password is a misleading method, it doesn't save the password on the user table. You need to call user.save() in order for it to work on your flow
You have to check whether user is active? If not, you only set active for user in admin panel, or set when creating user by adding the following line to user model:
is_active = models.BooleanField(default=True)
Also check that you have the right username/password combo. sometimes the one that is created from the createsuperuser command is different than a username you would typically use.
As most of them suggested if we create the user's using User.objects.create_user(**validated_data) this will hash the raw password and store the hashed password. In-case if you you are using User model serializers to validate and create users, it is required to override the serializer method like this
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
# this is the method responsible for insertion of data with hashed password
def create(self, validated_data):
return User.objects.create_user(**validated_data)
I puzzled with this problem for four days, and the above answers didn't help.
The problem was that I, as you, was using the user.save() and I could not see what the problem was, but then I looked at it with debug eyes, and it turns out that if you use user.save() it messes with the hashing of the password somehow, don't ask me how I don't know. So I worked around it by using the user.create() method that Django provides, worked like a charm:
#api_view(['POST'])
def create_user(request):
new_user = UserSerializer(data=request.data)
if new_user.is_valid():
user_saved = new_user.create(request.data)
return Response('User {} created'.format(user_saved.username),
status=status.HTTP_200_OK)
else:
return Response('User not created', status=status.HTTP_200_OK)
I used something like this, but you can do as you wish just use the user.create().

'User' Object has no attribude is_authenticated

I've created a User model for my django app
class User(Model):
"""
The Authentication model. This contains the user type. Both Customer and
Business models refer back to this model.
"""
email = EmailField(unique=True)
name = CharField(max_length=50)
passwd = CharField(max_length=76)
user_type = CharField(max_length=10, choices=USER_TYPES)
created_on = DateTimeField(auto_now_add=True)
last_login = DateTimeField(auto_now=True)
def __unicode__(self):
return self.email
def save(self, *args, **kw):
# If this is a new account then encrypt the password.
# Lets not re-encrypt it everytime we save.
if not self.created_on:
self.passwd = sha256_crypt.encrypt(self.passwd)
super(User, self).save(*args, **kw)
I've also created an authentication middleware to use this model.
from accounts.models import User
from passlib.hash import sha256_crypt
class WaitformeAuthBackend(object):
"""
Authentication backend fo waitforme
"""
def authenticate(self, email=None, password=None):
print 'authenticating : ', email
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
user = None
if user and sha256_crypt.verify(password, user.passwd):
return user
else:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
I have ammended the settings.py file correctly and if I add some print statements to this backend I can see the user details print out. I don't recall reading that I need to implement is_authenticated in the django docs. Am I missing something silly?
I'm not quite sure why you have created a new User model instead of using Django's built-in one and adding a linked UserProfile, which is the recommended thing to do (until 1.5 is released, when pluggable user models will be available). However, yes you need to define an is_authenticated method, which always returns True: this is exactly what the built-in model does. The reason is that if you have an actual User, it will always be authenticated: otherwise, you will have an AnonymousUser object, whose is_authenticated method always returns False.
you dont have to reinvent the wheel. Just use Djangos build in authentication system and save yourself a lot of trouble. You can also extend it to your needs or use different authentication backends. Have a read here. HTH.

Profile page getting acess to user object in Django

I have a requirement where I have to register users first via email. So, I went with django-registraton and I managed to integrate tat module into my django project.
After a successful login, the page redirects to 'registration/profile.html'.
I need to get access to the user object which was used in the authentication.
I need this object to make changes to a model which holds custom profile information about my users. I have already defined this in my models.py
Here is the URL I am using to re-direct to my template..
url(r'^profile/$',direct_to_template,{'template':'registration/profile.html'}),
So my question is this... after login, the user has to be taken to a profile page that needs to be filled up.
Any thoughts on how I can achieve this?
I have set up something similar earlier. In my case I defined new users via the admin interface but the basic problem was the same. I needed to show certain page (ie. user settings) on first log in.
I ended up adding a flag (first_log_in, BooleanField) in the UserProfile model. I set up a check for it at the view function of my frontpage that handles the routing. Here's the crude idea.
views.py:
def get_user_profile(request):
# this creates user profile and attaches it to an user
# if one is not found already
try:
user_profile = request.user.get_profile()
except:
user_profile = UserProfile(user=request.user)
user_profile.save()
return user_profile
# route from your urls.py to this view function! rename if needed
def frontpage(request):
# just some auth stuff. it's probably nicer to handle this elsewhere
# (use decorator or some other solution :) )
if not request.user.is_authenticated():
return HttpResponseRedirect('/login/')
user_profile = get_user_profile(request)
if user_profile.first_log_in:
user_profile.first_log_in = False
user_profile.save()
return HttpResponseRedirect('/profile/')
return HttpResponseRedirect('/frontpage'')
models.py:
from django.db import models
class UserProfile(models.Model):
first_log_in = models.BooleanField(default=True, editable=False)
... # add the rest of your user settings here
It is important that you set AUTH_PROFILE_MODULE at your setting.py to point to the model. Ie.
AUTH_PROFILE_MODULE = 'your_app.UserProfile'
should work.
Take a look at this article for further reference about UserProfile. I hope that helps. :)