roadrecon 1.6.0__py3-none-any.whl → 1.6.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {roadrecon-1.6.0.dist-info → roadrecon-1.6.2.dist-info}/METADATA +6 -2
- {roadrecon-1.6.0.dist-info → roadrecon-1.6.2.dist-info}/RECORD +10 -10
- {roadrecon-1.6.0.dist-info → roadrecon-1.6.2.dist-info}/WHEEL +1 -1
- roadtools/roadrecon/dist_gui/index.html +3 -3
- roadtools/roadrecon/dist_gui/main.85359eb82b074d01.js +1 -0
- roadtools/roadrecon/gather.py +10 -1
- roadtools/roadrecon/plugins/policies.py +20 -6
- roadtools/roadrecon/server.py +30 -2
- roadtools/roadrecon/dist_gui/main.007348bcb2c0fb0b.js +0 -1
- {roadrecon-1.6.0.dist-info → roadrecon-1.6.2.dist-info}/entry_points.txt +0 -0
- {roadrecon-1.6.0.dist-info → roadrecon-1.6.2.dist-info}/top_level.txt +0 -0
roadtools/roadrecon/gather.py
CHANGED
|
@@ -723,8 +723,17 @@ def main(args=None):
|
|
|
723
723
|
dburl = 'sqlite:///' + args.database
|
|
724
724
|
else:
|
|
725
725
|
dburl = args.database
|
|
726
|
+
try:
|
|
727
|
+
_, tokendata = Authentication.parse_accesstoken(token['accessToken'])
|
|
728
|
+
except KeyError:
|
|
729
|
+
print('No access token found in tokenfile')
|
|
730
|
+
return
|
|
731
|
+
if tokendata['aud'] not in ('https://graph.windows.net', 'https://graph.windows.net/', '00000002-0000-0000-c000-000000000000'):
|
|
732
|
+
print(f"Wrong token audience, got {tokendata['aud']} but expected https://graph.windows.net")
|
|
733
|
+
print("Make sure to request a token with -r https://graph.windows.net")
|
|
734
|
+
return
|
|
726
735
|
|
|
727
|
-
headers['Authorization'] =
|
|
736
|
+
headers['Authorization'] = f"Bearer {token['accessToken']}"
|
|
728
737
|
|
|
729
738
|
seconds = time.perf_counter()
|
|
730
739
|
loop = asyncio.get_event_loop()
|
|
@@ -129,6 +129,11 @@ class AccessPoliciesPlugin():
|
|
|
129
129
|
return self.session.query(ServicePrincipal).filter(ServicePrincipal.objectId.in_(uid)).all()
|
|
130
130
|
return self.session.query(ServicePrincipal).filter(ServicePrincipal.objectId == uid).first()
|
|
131
131
|
|
|
132
|
+
def _get_serviceprincipalrule(self, rule):
|
|
133
|
+
if isinstance(rule, list):
|
|
134
|
+
return [', '.join(rule)]
|
|
135
|
+
return [rule]
|
|
136
|
+
|
|
132
137
|
def _get_role(self, rid):
|
|
133
138
|
if isinstance(rid, list):
|
|
134
139
|
return self.session.query(DirectoryRole).filter(DirectoryRole.roleTemplateId.in_(rid)).all()
|
|
@@ -174,6 +179,7 @@ class AccessPoliciesPlugin():
|
|
|
174
179
|
'Groups' : self._get_group,
|
|
175
180
|
'Roles': self._get_role,
|
|
176
181
|
'ServicePrincipals': self._get_serviceprincipal,
|
|
182
|
+
'ServicePrincipalFilterRule': self._get_serviceprincipalrule,
|
|
177
183
|
'GuestsOrExternalUsers': self._translate_guestsexternal
|
|
178
184
|
}
|
|
179
185
|
ot = ''
|
|
@@ -206,6 +212,9 @@ class AccessPoliciesPlugin():
|
|
|
206
212
|
elif ctype == 'GuestsOrExternalUsers':
|
|
207
213
|
ot += 'Guests or external user types: '
|
|
208
214
|
ot += ', '.join([escape(uobj) for uobj in objects])
|
|
215
|
+
elif ctype == 'ServicePrincipalFilterRule':
|
|
216
|
+
ot += 'Service Principals matching the following filter: '
|
|
217
|
+
ot += ', '.join([escape(sprule) for sprule in objects])
|
|
209
218
|
else:
|
|
210
219
|
raise Exception('Unsupported criterium type: {0}'.format(ctype))
|
|
211
220
|
else:
|
|
@@ -222,18 +231,20 @@ class AccessPoliciesPlugin():
|
|
|
222
231
|
ot += ', '.join([escape(action) for action in clist])
|
|
223
232
|
else:
|
|
224
233
|
if 'All' in clist:
|
|
225
|
-
ot += 'All
|
|
234
|
+
ot += 'All resources'
|
|
226
235
|
break
|
|
227
236
|
if 'None' in clist:
|
|
228
237
|
ot += 'None'
|
|
229
238
|
break
|
|
230
239
|
if 'Office365' in clist:
|
|
231
|
-
ot += 'All Office 365 applications'
|
|
240
|
+
ot += 'All Office 365 applications '
|
|
241
|
+
if 'MicrosoftAdminPortals' in clist:
|
|
242
|
+
ot += 'All Microsoft Admin Portals '
|
|
232
243
|
objects = self._get_application(clist)
|
|
233
244
|
if objects is not None:
|
|
234
245
|
if len(objects) > 0:
|
|
235
246
|
if ctype == 'Applications':
|
|
236
|
-
ot += '
|
|
247
|
+
ot += 'Resources: '
|
|
237
248
|
ot += ', '.join([escape(uobj.displayName) for uobj in objects])
|
|
238
249
|
return ot
|
|
239
250
|
|
|
@@ -510,9 +521,9 @@ class AccessPoliciesPlugin():
|
|
|
510
521
|
print(policy.objectId)
|
|
511
522
|
detail = json.loads(policy.policyDetail[0])
|
|
512
523
|
if detail['State'] == 'Reporting':
|
|
513
|
-
out['name'] += ' (<
|
|
524
|
+
out['name'] += ' (<i>Report only</i>)'
|
|
514
525
|
elif detail['State'] != 'Enabled':
|
|
515
|
-
out['name'] += ' (<
|
|
526
|
+
out['name'] += ' (<i>Disabled</i>)'
|
|
516
527
|
if should_print:
|
|
517
528
|
pp.pprint(detail)
|
|
518
529
|
try:
|
|
@@ -524,6 +535,7 @@ class AccessPoliciesPlugin():
|
|
|
524
535
|
print('Invalid policy - no conditions')
|
|
525
536
|
continue
|
|
526
537
|
out['who'] = self._parse_who(conditions)
|
|
538
|
+
out['status'] = escape(detail['State'])
|
|
527
539
|
out['applications'] = self._parse_application(conditions)
|
|
528
540
|
out['authflows'] = self._parse_authflows(conditions)
|
|
529
541
|
out['platforms'] = self._parse_platform(conditions)
|
|
@@ -601,7 +613,9 @@ class AccessPoliciesPlugin():
|
|
|
601
613
|
for out in ol:
|
|
602
614
|
table = '<thead><tr><td colspan="2">{0}</td></tr></thead><tbody>'.format(out['name'])
|
|
603
615
|
table += '<tr><td>Applies to</td><td>{0}</td></tr>'.format(out['who'])
|
|
604
|
-
|
|
616
|
+
if out['status'] != 'Enabled':
|
|
617
|
+
table += '<tr><td>Policy state</td><td>{0}</td></tr>'.format(out['status'])
|
|
618
|
+
table += '<tr><td>Resources</td><td>{0}</td></tr>'.format(out['applications'])
|
|
605
619
|
if out['platforms'] != '':
|
|
606
620
|
table += '<tr><td>On platforms</td><td>{0}</td></tr>'.format(out['platforms'])
|
|
607
621
|
if out['devices'] != '':
|
roadtools/roadrecon/server.py
CHANGED
|
@@ -507,9 +507,24 @@ def get_allroles():
|
|
|
507
507
|
'scopeNames': snames,
|
|
508
508
|
'scopeIds': sids
|
|
509
509
|
}
|
|
510
|
-
|
|
510
|
+
principalType, principal = resolve_objectid(assignment.principalId)
|
|
511
511
|
aobj['principal'] = principal
|
|
512
|
+
|
|
512
513
|
roleobj['assignments'].append(aobj)
|
|
514
|
+
if principalType == 'Group':
|
|
515
|
+
group = db.session.get(Group, assignment.principalId)
|
|
516
|
+
for member in group.memberUsers:
|
|
517
|
+
mp = users_schema.dump([member])[0]
|
|
518
|
+
mp['displayName'] = f"{principal['displayName']} member: {mp['displayName']}"
|
|
519
|
+
roleobj['assignments'].append({
|
|
520
|
+
'type': 'assignment',
|
|
521
|
+
'scope': assignment.resourceScopes,
|
|
522
|
+
'scopeTypes': stypes,
|
|
523
|
+
'scopeNames': snames,
|
|
524
|
+
'scopeIds': sids,
|
|
525
|
+
'principal': mp
|
|
526
|
+
})
|
|
527
|
+
|
|
513
528
|
for assignment in role.eligibleAssignments:
|
|
514
529
|
stypes, snames, sids = translate_rolescopes(assignment.resourceScopes)
|
|
515
530
|
aobj = {
|
|
@@ -519,9 +534,22 @@ def get_allroles():
|
|
|
519
534
|
'scopeNames': snames,
|
|
520
535
|
'scopeIds': sids
|
|
521
536
|
}
|
|
522
|
-
|
|
537
|
+
principalType, principal = resolve_objectid(assignment.principalId)
|
|
523
538
|
aobj['principal'] = principal
|
|
524
539
|
roleobj['assignments'].append(aobj)
|
|
540
|
+
if principalType == 'Group':
|
|
541
|
+
group = db.session.get(Group, assignment.principalId)
|
|
542
|
+
for member in group.memberUsers:
|
|
543
|
+
mp = users_schema.dump([member])[0]
|
|
544
|
+
mp['displayName'] = f"{principal['displayName']} member: {mp['displayName']}"
|
|
545
|
+
roleobj['assignments'].append({
|
|
546
|
+
'type': 'eligible',
|
|
547
|
+
'scope': assignment.resourceScopes,
|
|
548
|
+
'scopeTypes': stypes,
|
|
549
|
+
'scopeNames': snames,
|
|
550
|
+
'scopeIds': sids,
|
|
551
|
+
'principal': mp
|
|
552
|
+
})
|
|
525
553
|
allroles.append(roleobj)
|
|
526
554
|
return jsonify(allroles)
|
|
527
555
|
|