Problem
You want to print Users and Groups for a Azure AD alias connection and running /usr/share/univention-office365/scripts/print_users_and_groups Uni-connection the following error occurs:
Using Azure AD connection alias 'Uni-connection'.
Traceback (most recent call last):
File "/usr/share/univention-office365/scripts/print_users_and_groups", line 150, in <module>
print_users_and_groups(adconnection_alias)
File "/usr/share/univention-office365/scripts/print_users_and_groups", line 42, in print_users_and_groups
groups = GroupAzure.list(core)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/univention/office365/microsoft/objects/azureobjects.py", line 999, in list
groups = [GroupAzure.from_dict(x) for x in groups_value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/univention/office365/microsoft/objects/azureobjects.py", line 999, in <listcomp>
groups = [GroupAzure.from_dict(x) for x in groups_value]
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/univention/office365/microsoft/objects/azureobjects.py", line 121, in from_dict
return cls(**{a.name: data.get(a.name, a.default) for a in cls.__attrs_attrs__})
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<attrs generated init univention.office365.microsoft.objects.azureobjects.GroupAzure>", line 110, in __init__
File "/usr/lib/python3/dist-packages/attr/validators.py", line 105, in __call__
raise TypeError(
TypeError: ("'isAssignableToRole' must be (<class 'str'>, <class 'NoneType'>) (got False that is a <class 'bool'>).", Attribute(name='isAssignableToRole', default=None, validator=<instance_of validator for type (<class 'str'>, <class 'NoneType'>)>, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False, inherited=False, on_setattr=None, alias='isAssignableToRole'), (<class 'str'>, <class 'NoneType'>), False)
Root Cause
Microsoft Azure returns the isAssignableToRole attribute as a Boolean value (true or false). The office365 Connector incorrectly defines this attribute as a string.
When the Azure response is parsed, the Boolean value is passed directly to GroupAzure.from_dict(). The attrs validator expects a string or None and raises a
TypeError when it receives the Boolean value false.
Microsoft documents isAssignableToRole as a Boolean attribute:
This will be also tracked in Bug 59902
Investigation
The affected file is:
modules/univention/office365/microsoft/objects/azureobjects.py
The problematic code is:
isAssignableToRole = attr.ib(
validator=attr.validators.instance_of((str, type(None))),
default=None,
) #: str
GroupAzure.from_dict() passes response values directly to the object:
return cls(**{
a.name: data.get(a.name, a.default)
for a in cls.__attrs_attrs__
})
Therefore, a response value of false is validated as a Python bool against the expected types str and None, causing the traceback.
Workaround
A patch file is provided as fix-isAssignableToRole.patch on the Bugreport.
The patch changes the validator to accept Boolean values:
From:
- isAssignableToRole = attr.ib(validator=attr.validators.instance_of((str, type(None))), default=None) #: str
To:
+ isAssignableToRole = attr.ib(validator=attr.validators.instance_of((bool, type(None))), default=None) #: bool
To apply the patch on UCS 5.2
1. Install the patch software:
apt update && apt install patch
2. Create a backup of the installed Python module:
cp \
/usr/lib/python3/dist-packages/univention/office365/microsoft/objects/azureobjects.py \
/usr/lib/python3/dist-packages/univention/office365/microsoft/objects/azureobjects.py.bak
3. Create the patchfile fix-isAssignableToRole.patch
cat > fix-isAssignableToRole.patch <<'EOF'
diff --git a/modules/univention/office365/microsoft/objects/azureobjects.py b/modules/univention/office365/microsoft/objects/azureobjects.py
--- a/modules/univention/office365/microsoft/objects/azureobjects.py
+++ b/modules/univention/office365/microsoft/objects/azureobjects.py
@@ -822,7 +822,7 @@ class GroupAzure(AzureObject):
deletedDateTime = attr.ib(validator=attr.validators.instance_of((str, type(None))), default=None) #: str
creationOptions = attr.ib(validator=attr.validators.instance_of((List, type(None))), default=None) #: List
expirationDateTime = attr.ib(validator=attr.validators.instance_of((str, type(None))), default=None) #: str
- isAssignableToRole = attr.ib(validator=attr.validators.instance_of((str, type(None))), default=None) #: str
+ isAssignableToRole = attr.ib(validator=attr.validators.instance_of((bool, type(None))), default=None) #: bool
membershipRule = attr.ib(validator=attr.validators.instance_of((str, type(None))), default=None) #: str
membershipRuleProcessingState = attr.ib(validator=attr.validators.instance_of((str, type(None))), default=None) #: str
onPremisesDomainName = attr.ib(validator=attr.validators.instance_of((str, type(None))), default=None) #: str
EOF
4. Apply the patch to the installed module:
patch \
/usr/lib/python3/dist-packages/univention/office365/microsoft/objects/azureobjects.py \
< fix-isAssignableToRole.patch
5. Confirm that the change is present:
grep -n "isAssignableToRole" \
/usr/lib/python3/dist-packages/univention/office365/microsoft/objects/azureobjects.py
The line must contain:
825: isAssignableToRole = attr.ib(validator=attr.validators.instance_of((bool, type(None))), default=None) #: bool
6. Run the command again:
/usr/share/univention-office365/scripts/print_users_and_groups Uni-connection
Hint:
This workaround changes an installed package file. The change may be overwritten by a future package update.