我正在与Microsoft Graph API交互以提取广告组及其成员身份。
在这种情况下,我们可以将组和用户都作为组的成员。
在定义ADGroup
对象时,我添加了一个名为member_groups
的字段,该字段将包含ADGroup
类的多个实例。
一切似乎都可以正常工作,但是在调试时,我注意到嵌套的ADGroup
对象没有生成一个空的member_groups
属性(即使我没有将它们传递给构造函数,我仍在填充它们在__init__()
上使用方法。
我已经尝试调试,并且仅在将组对象嵌套在其他组对象中时才会看到此行为。
ADGroup类
class AzureADGroup:
id = ''
deleted_date_time = ''
classification = ''
created_date_time = ''
description = ''
display_name = ''
mail = ''
mail_enabled = False
mail_nickname = ''
security_enabled = False
member_groups = []
member_users = []
def __init__(
self,
id,
deleted_date_time='',
classification='',
created_date_time='',
description='',
display_name='',
mail='',
mail_enabled=False,
mail_nickname='',
security_enabled=False
):
self.id = id
self.deleted_date_time = deleted_date_time
self.created_date_time = created_date_time
self.classification = classification
self.description = description
self.display_name = display_name
self.mail = mail
self.mail_enabled = mail_enabled
self.mail_nickname = mail_nickname
self.security_enabled = security_enabled
self.__populate_group_members()
def __repr__(self):
return self.display_name
def __populate_group_members(self):
ad_helper = ADGroupHelper()
members = ad_helper.get_group_members(self.id)['value']
for member in members:
if member['@odata.type'] == '#microsoft.graph.group':
ad_group = AzureADGroup(
id=member['id'],
deleted_date_time=member['deletedDateTime'],
created_date_time=member['createdDateTime'],
display_name=member['displayName'],
description=member['description'],
mail=member['mail'],
mail_enabled=member['mailEnabled'],
mail_nickname=member['mailNickname'],
security_enabled=member['securityEnabled'],
)
if not any(existing_group.id == ad_group.id for existing_group in self.member_groups):
self.member_groups.append(ad_group)
elif member['@odata.type'] == '#microsoft.graph.user':
ad_user = AzureADUser(
id=member['id'],
business_phones=member['businessPhones'],
display_name=member['displayName'],
given_name=member['givenName'],
job_title=member['jobTitle'],
mail=member['mail'],
mobile_phone=member['mobilePhone'],
office_location=member['officeLocation'],
preferred_language=member['preferredLanguage'],
surname=member['surname'],
user_principal_name=member['userPrincipalName']
)
if not any(existing_member.id == ad_user.id for existing_member in self.member_users):
self.member_users.append(ad_user)
# pylint: disable=too-few-public-methods
class AzureHelper:
"""This helper is intended to easen working with Azure."""
client_id = os.environ.get('PGA_READER_ID', False)
client_secret = os.environ.get('PGA_READER_SECRET', False)
tenant = os.environ.get('PGA_TENANT', False)
def __init__(self):
if not self.client_id or not self.client_secret or not self.tenant:
raise Exception("Azure Environment variables not set")
AD Helper类(对图形API进行请求):
class ADGroupHelper(AzureHelper):
"""This helper is supposed to make it easier to query AD objects."""
def get_group_by_id(self, object_id):
"""This method retrieves an AD group by its Object ID"""
response = requests.get(
url='https://login.microsoftonline.com/{}/oauth2/token'.format(
self.tenant),
data={
'client_id': self.client_id,
'client_secret': self.client_secret,
'grant_type': 'client_credentials',
'resource': 'https://graph.microsoft.com',
'scope': 'https%3A%2F%2Fgraph.microsoft.com%2F.default'
})
assert (response.status_code == 200), \
"There was a problem fetching the token"
headers = {"Authorization": "Bearer {}".format(
response.json()["access_token"])}
response = requests.get(
'https://graph.microsoft.com/v1.0/groups/{}'.format(object_id),
headers=headers
)
if response.status_code == 404:
return False
return response.json()
def get_team_members(self, team: str or Team):
if isinstance(team, Team):
team_code = team.team_code
else:
team_code = team
team_name = "ROL-XX-CGLOBL-IT-{}".format(team_code.upper())
def get_group_by_name(self, group_name):
"""
This method retrieves the group with the specified
displayName
"""
response = requests.get(
url='https://login.microsoftonline.com/{}/oauth2/token'.format(
self.tenant),
data={
'client_id': self.client_id,
'client_secret': self.client_secret,
'grant_type': 'client_credentials',
'resource': 'https://graph.microsoft.com',
'scope': 'https%3A%2F%2Fgraph.microsoft.com%2F.default'
})
assert (response.status_code == 200), \
"There was a problem fetching the token"
headers = {"Authorization": "Bearer {}".format(
response.json()["access_token"])}
response = requests.get(
'https://graph.microsoft.com/v1.0/groups?$filter=displayName eq \'{}\''.format(
group_name),
headers=headers
)
if response.status_code != 200:
return False
ds_json = json.loads(response.text)['value'][0]
az_ad_group = AzureADGroup(
id=ds_json['id'],
deleted_date_time=ds_json['deletedDateTime'],
created_date_time=ds_json['createdDateTime'],
display_name=ds_json['displayName'],
description=ds_json['description'],
mail=ds_json['mail'],
mail_enabled=ds_json['mailEnabled'],
mail_nickname=ds_json['mailNickname'],
security_enabled=ds_json['securityEnabled'],
)
return az_ad_group
def get_group_members(self, object_id):
"""
This method retrieves the members of an AD Group with the
specified Object ID
"""
response = requests.get(
url='https://login.microsoftonline.com/{}/oauth2/token'.format(
self.tenant),
data={
'client_id': self.client_id,
'client_secret': self.client_secret,
'grant_type': 'client_credentials',
'resource': 'https://graph.microsoft.com',
'scope': 'https%3A%2F%2Fgraph.microsoft.com%2F.default'
})
assert (response.status_code == 200), \
"There was a problem fetching the token"
headers = {"Authorization": "Bearer {}".format(
response.json()["access_token"])}
response = requests.get(
'https://graph.microsoft.com/v1.0/groups/{}/members'.format(
object_id),
headers=headers
)
if response.status_code == 404:
return False
return response.json()
给一个A组,里面有两个组(internal
和external
),我应该得到一个组对象,其中member_users
属性的用户和{{ 1}}属性。
member_groups
中的每个组应该是类型为member_groups
的对象,并具有自己的ADGroup
和member_users
。
这是填充成员之前的对象(请注意member_groups
和member_groups
为空):
member_users
第一个成员组被解析:
self = {AzureADGroup} ROL-XX-CGLOBL-IT-OPS
classification = {str} ''
created_date_time = {str} '2018-04-13T13:16:54Z'
deleted_date_time = {NoneType} None
description = {str} 'Team members'
display_name = {str} 'ROL-XX-CGLOBL-IT-OPS'
id = {str} 'd8cb4ad1-ed86-4742-bea3-521567356a10'
mail = {NoneType} None
mail_enabled = {bool} False
mail_nickname = {str} 'ROL-XX-CGLOBL-IT-OPS'
member_groups = {list} <class 'list'>: []
member_users = {list} <class 'list'>: []
security_enabled = {bool} True
填充第一个成员组的用户后:
self = {AzureADGroup} ROL-XX-CGLOBL-IT-OPS-external
classification = {str} ''
created_date_time = {str} '2018-04-13T13:46:55Z'
deleted_date_time = {NoneType} None
description = {str} 'Team members that are not employees, but contractors'
display_name = {str} 'ROL-XX-CGLOBL-IT-OPS-external'
id = {str} 'b3fcdac9-0ba2-4459-ae2a-9aee96327eee'
mail = {NoneType} None
mail_enabled = {bool} False
mail_nickname = {str} 'ROL-XX-CGLOBL-IT-OPS-external'
member_groups = {list} <class 'list'>: []
member_users = {list} <class 'list'>: []
security_enabled = {bool} True
填充第二个成员组的用户:
self = {AzureADGroup} ROL-XX-CGLOBL-IT-OPS-external
classification = {str} ''
created_date_time = {str} '2018-04-13T13:46:55Z'
deleted_date_time = {NoneType} None
description = {str} 'Team members that are not employees, but external users'
display_name = {str} 'ROL-XX-CGLOBL-IT-OPS-external'
id = {str} 'b3fcdac9-0ba2-4459-ae2a-9aee96327eee'
mail = {NoneType} None
mail_enabled = {bool} False
mail_nickname = {str} 'ROL-XX-CGLOBL-IT-OPS-external'
member_groups = {list} <class 'list'>: []
member_users = {list} <class 'list'>: [User A Ext, User B Ext]
security_enabled = {bool} True
在这一点上,很明显有些问题了,我觉得这可能与我引用self = {AzureADGroup} ROL-XX-CGLOBL-IT-OPS-internal
classification = {str} ''
created_date_time = {str} '2018-04-13T13:46:55Z'
deleted_date_time = {NoneType} None
description = {str} 'Team members that are employees'
display_name = {str} 'ROL-AKE-CGLOBL-IT-OPS-internal'
id = {str} 'ed0ae802-09b8-4911-885b-b99e6fc1b6c1'
mail = {NoneType} None
mail_enabled = {bool} False
mail_nickname = {str} 'ROL-XX-CGLOBL-IT-OPS-internal'
member_groups = {list} <class 'list'>: [ROL-XX-CGLOBL-IT-OPS-external, ROL-XX-CGLOBL-IT-OPS-external]
0 = {AzureADGroup} ROL-XX-CGLOBL-IT-OPS-external
1 = {AzureADGroup} ROL-XX-CGLOBL-IT-OPS-external
__len__ = {int} 2
member_users = {list} <class 'list'>: [User A Ext, User B Ext]
0 = {AzureADUser} User A Ext
1 = {AzureADUser} User B Ext
__len__ = {int} 2
security_enabled = {bool} True
并在组及其成员上都调用方法的事实有关。