Django role permissions - available_permissions aren't automatically assigned to Group - python

I'm trying to use django-role-permissions but it doesn't assign available_permissions to Group nor to User.
from rolepermissions.roles import AbstractUserRole
class PERMISSIONS:
CAN_SEE_ALL_INVOICES = 'can_see_all_invoices'
CAN_SEE_OWN_INVOICES = 'can_see_own_invoices'
class Admin(AbstractUserRole):
verbose_name = 'Admin'
available_permissions = {
PERMISSIONS.CAN_SEE_ALL_INVOICES:True,
}
class Broker(AbstractUserRole):
verbose_name = 'Maklér'
available_permissions = {
PERMISSIONS.CAN_SEE_ALL_INVOICES: False,
PERMISSIONS.CAN_SEE_OWN_INVOICES: True,
}
After sync_roles I checked the admin and also tried to programmatically check the permission for the user that has Broker role and they doesn't have the permission.
How is that possible?

Related

Why user.has_perm print always True?

A user is assigned to a student group and from the group remove delete_permission, but the below code returns true.
student_group = Group.objects.get(name='student')
content_type = ContentType.objects.get_for_model(Department)
department_permission = Permission.objects.filter(content_type=content_type)
user = User.objects.get(email='test#gmail.com')
student_group.user_set.add(user)
for perm in department_permission:
if perm.codename == "delete_department":
student_group.permissions.remove(perm)
print(user.has_perm("quiz.delete_department"), "Quiz Permission after")
Permissions are cached on the user object see Django documentation. Also refresh_from_db() won't work you need to fetch the user again see this issue.
In your case:
student_group = Group.objects.get(name='student')
content_type = ContentType.objects.get_for_model(Department)
department_permission = Permission.objects.filter(content_type=content_type)
user = User.objects.get(email='test#gmail.com')
student_group.user_set.add(user)
for perm in department_permission:
if perm.codename == "delete_department":
student_group.permissions.remove(perm)
# re-fetch the user from the database after permission change
user = User.objects.get(email='test#gmail.com')
print(user.has_perm("quiz.delete_department"), "Quiz Permission after")

Playhouse's (peewee extenstion) signals does not work correctly

I have two models: User and UserSettings because I decided to divide user related properties and privacy settings.
I am using PeeweeORM for building models and creating tables. Here is a short part of my code:
class User(BaseModel):
id = UUIDField(primary_key=True, default=uuid4)
tg_id = BigIntegerField(unique=True, null=True)
class UserSettings(BaseModel):
user: User = ForeignKeyField(User, backref='settings', unique=True)
show_location: bool = BooleanField(default=True)
As far as I know peewee itself has no built-in OneToOne relation support and I have decided to use playhouse's django-like signals described in peewee docs so that there is one record in UserSettings table for each one User. As it was defined in docs, I have inherited my BaseModel class from playhouse.signal Model class to make signals working. Here is a signal itself:
#post_save(sender=User)
def on_user_created(model_class: User, instance: User, created: bool):
print("works1") # Signal is working correctly. I see this output in console
if created: # DOES NOT WORK HERE! I AM GETTING False value on created
print('works2')
us = UserSettings()
us.user = instance
us.save(force_insert=True)
So this is the way I am creating new users:
def create_or_update_user_tg(tg_id: int, name: str, age: int, city: str,
gender: Gender, search_gender: SearchGender,
profile_description: str = None, location: Location = None,
medias: typing.List[tuple[str]] = None) -> \
typing.Union[User, None]:
u, is_creating = User.get_or_none(tg_id=tg_id), False
if not u:
u, is_creating = User(), True
u.tg_id = tg_id
u.name = name
u.age = age
u.city = city
u.gender = gender.value
u.search_gender = search_gender.value
u.profile_description = profile_description
if location:
u.longitude = location.longitude
u.latitude = location.latitude
u.save(force_insert=is_creating)
upload_user_medias(u.tg_id, medias, delete_existing=True)
return u
Thanks for responses guys! Waiting for your advices.
It seems to be working fine for me. Here's a stripped-down, simplified example:
from peewee import *
from playhouse.signals import Model, post_save
from uuid import uuid4
db = SqliteDatabase(':memory:')
class User(Model):
id = UUIDField(default=uuid4)
username = TextField()
class Meta:
database = db
db.create_tables([User])
#post_save(sender=User)
def on_save(model_class, instance, created=None):
print(instance.username, created)
u = User()
u.username='foo'
u.save(force_insert=True)
u.save()
The output, as expected:
foo True
foo False

How to get the ARN of an EC2 instance in AWS-CDK

I am creating a EC2 instance using CfnInstance in CDK and I would like to use the ARN later in an IAM role, so I can give permission to that specific resource and to avoid to use *. How can I access the ARN of the EC2 instance just created. The code is as follows:
instance_profile = self.create_instance_profile()
self.instance = ec2.CfnInstance(self, 'Client',
image_id = image_id,
instance_type = instance_type,
subnet_id = subnet_id,
iam_instance_profile = instance_profile.ref,
security_group_ids = [cluster_security_group_id],
user_data = core.Fn.base64('\n'.join(self.user_data_commands)),
tags = [{ 'key': 'Name', 'value': 'MskEc2Client' }],
)
def create_instance_profile(self):
role = iam.Role(self, 'Role', assumed_by = iam.ServicePrincipal('ec2.amazonaws.com'))
ssm_policy_statement = iam.PolicyStatement(
resources = ['*'], #TODO GIVE PERMISSION TO THE SPECIFIC RESOURCE (EC2)
actions = [
'ssm:UpdateInstanceInformation', 'ssmmessages:CreateControlChannel',
'ssmmessages:CreateDataChannel', 'ssmmessages:OpenControlChannel', 'ssmmessages:OpenDataChannel'])
ssm_policy = iam.Policy(self, 'SessionManagerPolicy', statements = [ssm_policy_statement])
self.add_w12_suppression(ssm_policy, 'Session Manager actions do not support resource level permissions')
ssm_policy.attach_to_role(role)
msk_policy = iam.Policy(self, 'MskPolicy', #TODO GIVE PERMISSION TO SPECIFIC RESOURCES (EC2)
statements = [iam.PolicyStatement(resources = ['*'], actions = ['kafka:DescribeCluster', 'kafka:GetBootstrapBrokers'])]
)
self.add_w12_suppression(msk_policy, 'MSK actions do not support resource level permissions')
msk_policy.attach_to_role(role)
cfn_role = role.node.default_child
return iam.CfnInstanceProfile(self, 'InstanceProfile', roles = [cfn_role.ref])
You can use the default return value of the instance to construct the arn to populate the resources
ssm_policy_statement = iam.PolicyStatement(
resources = [f'arn:{self.partition}:ec2:{self.region}:{self.account}:instance/{self.instance.ref}'],
actions = [
'ssm:UpdateInstanceInformation', 'ssmmessages:CreateControlChannel',
'ssmmessages:CreateDataChannel', 'ssmmessages:OpenControlChannel', 'ssmmessages:OpenDataChannel'
]
)

Django LDAP Authorization

I configure Django with ldap. the authorization in ldap seems to work. but the group membership does'nt work. The user fall back to the login.
here the settings.py and the Debug
------------------- Config ------------------------------
import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType, NestedActiveDirectoryGroupType
# Baseline configuration.
AUTH_LDAP_SERVER_URI = "ldap://srv.domain.com"
AUTH_LDAP_BIND_DN = "cn=ldapreader,ou=admins,ou=City,dc=domain,dc=com"
AUTH_LDAP_BIND_PASSWORD = "LdapreadeR"
AUTH_LDAP_USER_SEARCH = LDAPSearch("ou=City,dc=domain,dc=com",
ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)")
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("ou=xgroups,ou=City,dc=domain,dc=com",
ldap.SCOPE_SUBTREE, "(objectClass=group)"
)
AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
"is_active": "cn=django,ou=xgroups,ou=City,dc=domain,dc=com",
"is_staff": "cn=django_staff,ou=xgroups,ou=City,dc=domain,dc=com",
"is_superuser": "cn=django_admin,ou=xgroups,ou=City,dc=domain,dc=com"
}
AUTH_LDAP_FIND_GROUP_PERMS = True
AUTH_LDAP_PROFILE_FLAGS_BY_GROUP = {
"is_awesome": "cn=awesome,ou=django,ou=groups,dc=example,dc=com",
}
AUTH_LDAP_MIRROR_GROUPS = True
------------------ DEBUG ----------------------------------
search_s('ou=City,dc=domain,dc=com', 2, '(sAMAccountName=%(user)s)') returned 1 objects: cn=Farmer Nic,ou=users,ou=City,dc=domain,dc=com
Populating Django user fn000000
search_s('ou=xgroups,ou=City,dc=domain,dc=com', 2, '(& (objectClass=group)(|(member=cn=Farmer Nic,ou=users,ou=City,dc=domain,dc=com)))') returned 4 objects:
cn=django_admin,ou=xgroups,ou=City,dc=domain,dc=com;
cn=django,ou=xgroups,ou=City,dc=domain,dc=com;
cn=pbspot_op,ou=xgroups,ou=City,dc=domain,dc=com;
cn=xxx_super,ou=xgroups,ou=City,dc=domain,dc=com
search_s('ou=xgroups,ou=City,dc=domain,dc=com', 2, '(&(objectClass=group)(|
(member=cn=django_admin,ou=xgroups,ou=City,dc=domain,dc=com)
(member=cn=django,ou=xgroups,ou=City,dc=domain,dc=com)
(member=cn=pbspot_op,ou=xgroups,ou=City,dc=domain,dc=com)
(member=cn=xxx_super,ou=xgroups,ou=City,dc=domain,dc=com)))')
returned 0 objects:
cn=Farmer Nic,ou=users,ou=City,dc=domain,dc=com is a member of cn=django_admin,ou=xgroups,ou=City,dc=domain,dc=com
cn=Farmer Nic,ou=users,ou=City,dc=domain,dc=com is not a member of cn=django_staff,ou=xgroups,ou=City,dc=domain,dc=com
cn=Farmer Nic,ou=users,ou=City,dc=domain,dc=com is a member of cn=django,ou=xgroups,ou=City,dc=domain,dc=com
Django found, that the user Member of django_admin Group is, but he got not the admin-page.
what is wrong?
Thx
I resolve the problem by myself.
User must be member in cn=django_admin.. and cn=django_staff.. group. Now "Farmer Nick" can login. Ich changed the row "is_staff" to "is_staff": "django_admin..." and all things would be ok.

Tastypie serializing Virtual Field's Model

I've Patient, Doctor, Story Model. Each Story have a patient_id and a doctor_id. I want to retrieve a list of doctors the patient have visited ever.
class Patient(Person):
def visits(self):
doctor_visits = []
for v in self.stories.values('doctor').annotate(visits=Count('doctor')):
# replace the doctor id with doctor object
v['doctor'] = Doctor.objects.get(id=v['doctor'])
doctor_visits.append(v)
return doctor_visits
Here is my tastypie Resource
class PatientResource(ModelResource):
stories = fields.ToManyField('patients.api.StoryResource', 'stories', null=True)
visits = fields.ListField(attribute='visits', readonly=True)
class Meta:
queryset = Patient.objects.all()
excludes = ['id', 'login', 'password']
with the above tastypie results the following
{
address:"ADDRESS",
dob:"1985-12-04",
email:"EMAIL",
name:"Nogen",
resource_uri:"/patients/api/v1/patient/9/",
sex:"M",
stories:[
"/patients/api/v1/story/1/",
"/patients/api/v1/story/2/",
"/patients/api/v1/story/4/"
],
visits:[
{
doctor:"Dr. X",
visits:2
},
{
doctor:"Dr. Y",
visits:1
}
]
}
See Its caling the __unicode__ method of Doctor rather I expected this to be a link /patients/api/v1/doctor/<doctor_id>/ Do I need to construct the path manually or There is some other way around ?
I've tried using dehydrate possibly incorrectly
class PatientResource(ModelResource):
stories = fields.ToManyField('patients.api.StoryResource', 'stories', null=True)
visits = fields.ListField(attribute='visits', readonly=True)
class Meta:
queryset = Patient.objects.all()
excludes = ['id', 'login', 'password']
def dehydrate_visits(self, bundle):
for visit in bundle.data['visits']:
visit['doctor'] = DoctorResource(visit['doctor'])
return bundle
Which Results in maximum recursion depth exceeded while calling a Python object Exception
Not sure why you get maximum recursion depth but your method is wrong.
class PatientResource(ModelResource):
[...]
def dehydrate_visits(self, bundle):
# Make sure `bundle.data['visits'][0]['doctor'] isn't string.
# If it's already dehydrated string: try use `bundle.obj.visits` instead.
for visit in bundle.data['visits']:
visit['doctor'] = DoctorResource.get_resource_uri(visit['doctor'])
return bundle
I didn't test that. So fill free to comment if its incorrect.

Categories

Resources