I have a user update api that is supposed to update the user's details. I have used set_password() to encrypt the password and from my print statements, it seems to encrypt fine. However when I save the updated user, the password still saves as plain text. What am I missing here ?
print(user.password) gives me
pbkdf2_sha256$216000$26YKhuRQ4i4S$HnfbowEjappYtP7nbbMZJXcjLi13sWPpj1EqjEbUutI=
Yet when I return user it maintains the password as plain text.
class UserDetail(APIView):
def get_user(self, pk):
try:
return User.objects.get(pk=pk)
except User.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
def put(self, request, pk, format=None):
user = self.get_user(pk)
data = request.data
new_password = data["password"]
user.set_password(new_password)
user.save()
print(user.password)
serializers = UserSerializer(user, request.data)
if serializers.is_valid():
serializers.save()
return Response(serializers.data)
else:
return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
Related
I havent really changed anything and added a View to update some user data. Then i wanted to test my View and Django says that the current user is not authenticated. I logged out and logged in multiple Times and also looked at the requests in Burp. To me every looks fine, it always sends the session_id and also login goes through without problems. I also get my User Object returned to the frontend on login.
When i then try the "edit" function for the User then i'm unauthenticated...
This is my login:
#action(methods=['post'], detail=False, url_path='sign-in', url_name='sign-in')
def login_user(self, request):
email = str(request.data.get('email'))
password = str(request.data.get('password'))
if email is None or password is None:
return _ERROR_INCOMPLETE_CREDENTIALS
# User authentication...
user = authenticate_user(email=email, password=password)
if user is None:
return _ERROR_BAD_CREDENTIALS
user_profile = UserProfile.objects.get(id=user.id)
serialized_user = UserProfileSerializer([user_profile], many=True).data
print(serialized_user)
res = login(request, user)
print(res)
return Response(serialized_user, status=status.HTTP_200_OK)
This is the custom authenticate_user Method:
def authenticate_user(email, password):
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None
This is a view which fails due to unauthentication:
#action(methods=['get'], detail=False, url_name='current', url_path='current')
def get_current_user(self, request):
if not request.user.is_authenticated:
return Response({"detail": "You need to be logged in for this!"}, status=status.HTTP_401_UNAUTHORIZED)
user = request.user
user_profile = UserProfile.objects.get(id=user.id)
return Response(UserProfileSerializer([user_profile], many=True).data)
How can I authenticate and login the user from Active Directory? This is my code
Authenticate.py:
from .models import User
from ldap3 import ALL, Server, Connection, NTLM
from ldap3.core.exceptions import LDAPException
from django.contrib.auth.backends import ModelBackend
def validate_user_credentials(username, password):
server = Server(host='#xxxDomain',
use_ssl=False, get_info=ALL)
try:
with Connection(
server, authentication="NTLM", user=f"{''}\\{username}", password=password, raise_exceptions=False,
) as connection:
print(connection.result['description'])
return True
except LDAPException as e:
print(e)
return False
class UserAuth(ModelBackend):
def authenticate(self,request,username=None,password=None,**kwargs):
try:
if (validate_user_credentials(username, password)):
print("Helloooooooooooooo")
user = User.objects.get(username=username)
print(user)
return user
return None
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(username=user_id)
except User.DoesNotExist:
return None
views.py:
class UserLoginView(View):
form_class = UserLoginForm
def get(self, request):
form = self.form_class
return render(request, 'login/login.html', {'form': form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
cd = form.cleaned_data
userexistindb = User.objects.filter(
username=cd['username'], is_user_local=False).exists()
username = cd['username']
password = cd['password']
try:
if userexistindb:
try:
user = authenticate(
request, username=username, password=password)
if (user is not None):
login(request=request, user=user)
messages.success(
request, 'Loged in success', 'success')
return redirect('login:result')
else:
messages.error(request, 'us', 'warning')
except User.DoesNotExist:
messages.error(
request, 'Invalid User/Password', 'warning')
except User.DoesNotExist:
username = None
messages.error(
request, 'Invalid User/Password', 'warning')
return render(request, 'login/login.html', {'form': form})
The result is the sessionid It is created,The username and password
are correct and the answer is correct
but the captured user information is not displayed. Information is
displayed in the log!
enter image description here
What should I do!
I am using a updateapiview to the update my user information. This is my view
class UserUpdateView(generics.UpdateAPIView):
serializer_class = UserUpdateSerializer
def get_queryset(self):
print(self.kwargs['pk'])
return User.objects.filter(pk=self.kwargs['pk'])
def partial_update(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data, partial=True)
if self.get_object() != request.user:
return Response({'error': 'permission denied'}, status=status.HTTP_400_BAD_REQUEST)
print(request.data['password'])
request.data['password'] = make_password(request.data['password'])
instance = super(UserUpdateView, self).partial_update(request, *args, **kwargs)
return instance
This is my serializer
class UserUpdateSerializer(serializers.ModelSerializer):
email = serializers.EmailField(required=True)
def validate_username(self, username):
if User.objects.filter(username=username):
raise serializers.ValidationError('Username already exists!!')
return username
def validate_email(self, email):
if User.objects.filter(email=email):
raise serializers.ValidationError('Email already exists!!')
return email
class Meta:
model = User
fields = ('pk', 'username', 'password', 'email')
read_only_fields = ('pk',)
I am getting the data updated and returned successfully. But I want to add some field like message with content 'successfully updated' on successful updation of the user profile. I searched if there is any way to perform this but can't find the appropriate way to do it (alike get_context_data method in django). So, is there any way to perform the above task ??
Question 2:
How to prevent the self user ( i.e if has a email sample#gmail.com and if user clicks udpate with the same email, it should not raise an error that username already exists, I guess this can be done with self.instance (but not sure how actually to implement it).
Thanks!
I'm not sure what version of DRF you are using but in the latest 3.9.0 UpdateAPIView uses UpdateModelMixin, which returns Response object instead of instance. So you can modify data before returning.
def partial_update(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data, partial=True)
if self.get_object() != request.user:
return Response({'error': 'permission denied'}, status=status.HTTP_400_BAD_REQUEST)
print(request.data['password'])
request.data['password'] = make_password(request.data['password'])
response = super(UserUpdateView, self).partial_update(request, *args, **kwargs)
response.data['message'] = 'Successfully updated'
return response
Regarding your second question you can exclude the current user using self.instance.
def validate_email(self, email):
if User.objects.filter(email=email).exclude(id=self.instance.id).exists():
raise serializers.ValidationError('Email already exists!!')
return email
I have made a model with its own password field. This is wholly separate from the User object. I'm using the django.contrib.auth.hashers library for this.
In the create method for this model (overwriting a generic CreateListAPI view)
def create(self, request, *args, **kwargs):
data = request.data
data['password'] = make_password(data['password'])
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
This stores a hashed password in my database as expected, but when I try to authenticate with the password
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
try:
# Grabs the 'name' parameter from the URL
obj = queryset.get(name=self.kwargs['name'])
except Group.DoesNotExist:
raise Http404
print(self.request.data['password']) # raw password string
print(obj.password) # encoded password from database
if check_password(self.request.data['password']), obj.password):
raise Http404
obj.user_set.add(self.request.user)
self.check_object_permissions(self.request, obj)
return obj
check_password returns False. However, passing in the encoded password as the raw string password works. So hashing the password works, but not comparing the raw password to it after the fact.
if not check_password(self.request.data['password'], obj.password):
raise Http404
change the line to the above code
I've been struggling to pass some extra data form my Form class to my views. For a password recovery an user has to fill in an username or e-mail address. When cleaning, the username and password are checked if one of them exists in the database:
def clean(self):
username = self.cleaned_data.get("username")
email = self.cleaned_data.get("email")
if username:
try:
user = User.objects.get(username__iexact=username, is_active=True) # <- to view
except User.DoesNotExist:
raise forms.ValidationError(
self.error_messages["invalid_username"],
code="invalid_username"
)
elif email:
try:
user = User.objects.get(email__iexact=email, is_active=True) # <- to view
except User.DoesNotExist:
raise forms.ValidationError(
self.error_messages["invalid_email"],
code="invalid_email"
)
else:
raise forms.ValidationError(
self.error_messages["empty_form"],
code="empty_form"
)
return self.cleaned_data
When the form has been validated, I want to send the user data to the view. This to separate the send_email logics away from the form and being able to add some information to the context, so it can be rendered in the template.
So in my FormView, if the form is valid, I want to be able to use the user object retrieved in the Form.
Currently I have attempted quite some 'answers' of other SO questions and examples of the web. But I keep getting AttributeErrors, KeyErrors, 'WSGIRequest' object does not support item assignment.
The last attempt I made was to overwrite the init in my Form, and the get_form_kwargs in my view:
Form
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(RecoverPasswordForm, self).__init__(*args, **kwargs)
def clean(self):
....
self.request["user"] = User.objects.get(username__iexact=username, is_active=True)
View
def get_form_kwargs(self, **kwargs):
kwargs = super(RecoverPassword, self).get_form_kwargs()
kwargs["request"] = self.request
return kwargs
Which leads to the following error
'WSGIRequest' object does not support item assignment
Can somebody give me an explanation of what I'm doing wrong, and push me in the right direction to solve this problem? Thanks in advance!
From what I understand, I think you are trying to send an email with reset password link to the user from your view after validating the username/email in your form. Next to add some info to the context, so it can be rendered in the template.
So this can done by overriding the form_valid method in your class like:
def form_valid(self, form):
username = form.cleaned_data['username']
email = form.cleaned_data['email']
if username: user = User.objects.get(username__iexact=username, is_active=True)
else: user = User.objects.get(email__iexact=email, is_active=True)
send_email(user)
data = {'info':'give your info here'}
render(request, 'success.html', data)
Learn more here
Update:
to can access the user object from the form do like:
def clean():
...
self.cleaned_data["user"] = User.objects.get(username__iexact=username, is_active=True)
In your form_valid
def form_valid(self, form):
user = form.cleaned_data['user']
send_email(user)
data = {'info':'give your info here'}
render(request, 'success.html', data)