Skip to content

Commit

Permalink
security namespace & typings updates
Browse files Browse the repository at this point in the history
  • Loading branch information
vgrem committed Jan 27, 2024
1 parent b1994c1 commit 536356f
Show file tree
Hide file tree
Showing 29 changed files with 271 additions and 237 deletions.
21 changes: 1 addition & 20 deletions examples/directory/applications/grant_perms.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,6 @@
test_tenant,
)


def verify_connect():
"""Test the app-only authentication"""

thumbprint = "12FC1BB6796D114AF4FEBBE95FCA8084CF47D81F"
cert_key_path = "../../selfsignkey.pem"
with open(cert_key_path, "r") as fh:
private_key = fh.read()

ctx = GraphClient.with_certificate(
test_tenant, test_client_id, thumbprint, private_key
)
site = ctx.sites.root.get().execute_query()
print(site.web_url)


client = GraphClient.with_token_interactive(
test_tenant, test_client_id, test_admin_principal_name
)
Expand All @@ -51,7 +35,7 @@ def verify_connect():


# select specific appRole
app_role = resource.app_roles["Place.Read.All"]
app_role = resource.app_roles["ThreatHunting.Read.All"]

# Step 2: Grant an app role to a client app
app = client.applications.get_by_app_id(test_client_id)
Expand All @@ -62,6 +46,3 @@ def verify_connect():
result = resource.app_role_assigned_to.get_all().execute_query()
for app_role_assignment in result:
print(app_role_assignment)


verify_connect()
20 changes: 20 additions & 0 deletions examples/security/run_hunting_query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""
This example specifies a KQL query which does the following:
- Looks into the DeviceProcessEvents table in the advanced hunting schema.
- Filters on the condition that the event is initiated by the powershell.exe process.
- Specifies the output of 3 columns from the same table for each row: Timestamp, FileName, InitiatingProcessFileName.
- Sorts the output by the Timestamp value.
- Limits the output to 2 records (2 rows)
"""
from office365.graph_client import GraphClient
from tests import test_client_id, test_client_secret, test_tenant

client = GraphClient.with_client_secret(test_tenant, test_client_id, test_client_secret)
query = """
DeviceProcessEvents | where InitiatingProcessFileName =~ \"powershell.exe\"
| project Timestamp, FileName, InitiatingProcessFileName
| order by Timestamp desc | limit 2"""
result = client.security.run_hunting_query(query).execute_query()
print(result.value)
212 changes: 106 additions & 106 deletions generator/metadata/MicrosoftGraph.xml

Large diffs are not rendered by default.

9 changes: 4 additions & 5 deletions office365/directory/identities/providers/saml_or_wsfed.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from office365.directory.identities.providers.base import IdentityProviderBase


Expand All @@ -7,9 +9,6 @@ class SamlOrWsFedProvider(IdentityProviderBase):

@property
def issuer_uri(self):
"""
Issuer URI of the federation server.
:rtype: str
"""
# type: () -> Optional[str]
"""Issuer URI of the federation server."""
return self.properties.get("issuerUri", None)
6 changes: 4 additions & 2 deletions office365/directory/permissions/grants/condition_set.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from office365.entity import Entity
from office365.runtime.types.collections import StringCollection

Expand Down Expand Up @@ -29,10 +31,10 @@ def client_application_publisher_ids(self):

@property
def client_applications_from_verified_publisher_only(self):
# type: () -> Optional[bool]
"""
Set to true to only match on client applications with a verified publisher. Set to false to match on any client
app, even if it does not have a verified publisher. Default is false.
:rtype: bool
"""
return self.properties.get("clientApplicationsFromVerifiedPublisherOnly", None)

Expand All @@ -50,9 +52,9 @@ def permissions(self):

@property
def resource_application(self):
# type: () -> Optional[str]
"""
The appId of the resource application (e.g. the API) for which a permission is being granted, or any to match
with any resource application or API. Default is any.
:rtype: str
"""
return self.properties.get("resourceApplication", None)
2 changes: 2 additions & 0 deletions office365/directory/policies/permission_grant.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class PermissionGrantPolicy(PolicyBase):

@property
def excludes(self):
# type: () -> EntityCollection[PermissionGrantConditionSet]
"""
Condition sets which are excluded in this permission grant policy.
This navigation is automatically expanded on GET.
Expand All @@ -32,6 +33,7 @@ def excludes(self):

@property
def includes(self):
# type: () -> EntityCollection[PermissionGrantConditionSet]
"""
Condition sets which are included in this permission grant policy.
This navigation is automatically expanded on GET.
Expand Down
23 changes: 20 additions & 3 deletions office365/directory/security/security.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
from office365.directory.security.alerts.alert import Alert
from office365.directory.security.attacksimulations.root import AttackSimulationRoot
from office365.directory.security.cases.root import CasesRoot
from office365.directory.security.hunting_query_results import HuntingQueryResults
from office365.directory.security.incidents.incident import Incident
from office365.directory.security.threatintelligence.threat_intelligence import (
ThreatIntelligence,
)
from office365.directory.security.triggers.root import TriggersRoot
from office365.entity import Entity
from office365.entity_collection import EntityCollection
from office365.runtime.client_result import ClientResult
from office365.runtime.paths.resource_path import ResourcePath
from office365.runtime.queries.service_operation import ServiceOperationQuery


class Security(Entity):
"""The security resource is the entry point for the Security object model. It returns a singleton security resource.
It doesn't contain any usable properties."""

def run_hunting_query(self, query):
"""
Queries a specified set of event, activity, or entity data supported by Microsoft 365 Defender
to proactively look for specific threats in your environment.
:param str query: The hunting query in Kusto Query Language (KQL). For more information on KQL syntax,see KQL
quick reference: https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/kql-quick-reference
"""
return_type = ClientResult(self.context, HuntingQueryResults())
payload = {"Query": query}
qry = ServiceOperationQuery(
self, "runHuntingQuery", None, payload, None, return_type
)
self.context.add_query(qry)
return return_type

@property
def alerts(self):
# type: () -> EntityCollection[Alert]
Expand All @@ -28,9 +46,7 @@ def alerts(self):
@property
def alerts_v2(self):
# type: () -> EntityCollection[Alert]
"""
A collection of alerts in Microsoft 365 Defender.
"""
"""A collection of alerts in Microsoft 365 Defender."""
return self.properties.get(
"alerts_v2",
EntityCollection(
Expand Down Expand Up @@ -69,6 +85,7 @@ def incidents(self):

@property
def triggers(self):
""""""
return self.properties.get(
"triggers",
TriggersRoot(self.context, ResourcePath("triggers", self.resource_path)),
Expand Down
1 change: 1 addition & 0 deletions office365/directory/serviceprincipals/service_principal.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ def owners(self):

@property
def oauth2_permission_scopes(self):
# type: () -> ClientValueCollection[PermissionScope]
"""
The delegated permissions exposed by the application. For more information see the oauth2PermissionScopes
property on the application entity's api property.
Expand Down
2 changes: 2 additions & 0 deletions office365/directory/synchronization/synchronization.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Synchronization(Entity):

@property
def jobs(self):
# type: () -> EntityCollection[SynchronizationJob]
"""
Performs synchronization by periodically running in the background, polling for changes in one directory,
and pushing them to another directory.
Expand All @@ -31,6 +32,7 @@ def jobs(self):

@property
def templates(self):
# type: () -> EntityCollection[SynchronizationTemplate]
"""
Performs synchronization by periodically running in the background, polling for changes in one directory,
and pushing them to another directory.
Expand Down
2 changes: 1 addition & 1 deletion office365/intune/audit/event_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from office365.runtime.types.collections import StringCollection


class AuditEventCollection(EntityCollection):
class AuditEventCollection(EntityCollection[AuditEvent]):
def __init__(self, context, resource_path=None):
super(AuditEventCollection, self).__init__(context, AuditEvent, resource_path)

Expand Down
9 changes: 9 additions & 0 deletions office365/onedrive/workbooks/filter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
from typing import Optional

from office365.entity import Entity
from office365.onedrive.workbooks.filter_criteria import WorkbookFilterCriteria


class WorkbookFilter(Entity):
"""Manages the filtering of a table's column."""

@property
def criteria(self):
# type: () -> Optional[WorkbookFilterCriteria]
"""The currently applied filter on the given column."""
return self.properties.get("criteria", WorkbookFilterCriteria())
5 changes: 5 additions & 0 deletions office365/onedrive/workbooks/filter_criteria.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@

class WorkbookFilterCriteria(ClientValue):
"""Represents the filtering criteria applied to a column."""

def __init__(self, operator=None, values=None):
""" """
self.operator = operator
self.values = values
2 changes: 2 additions & 0 deletions office365/onedrive/workbooks/functions/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@


class WorkbookFunctionResult(Entity):
""""""

@property
def value(self):
return self.properties.get("value", None)
2 changes: 2 additions & 0 deletions office365/onedrive/workbooks/worksheets/protection.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@


class WorkbookWorksheetProtection(Entity):
"""Represents the protection of a sheet object."""

pass
14 changes: 7 additions & 7 deletions office365/outlook/calendar/permissions/permission.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from office365.entity import Entity
from office365.outlook.calendar.email_address import EmailAddress
from office365.runtime.types.collections import StringCollection
Expand Down Expand Up @@ -37,28 +39,26 @@ def email_address(self):

@property
def is_inside_organization(self):
# type: () -> Optional[bool]
"""
True if the user in context (sharee or delegate) is inside the same organization as the calendar owner.
:rtype: bool or None
True if the user in context (sharee or delegate) is inside the same organization as the calendar owner
"""
return self.properties.get("isInsideOrganization", None)

@property
def is_removable(self):
# type: () -> Optional[bool]
"""
True if the user can be removed from the list of sharees or delegates for the specified calendar,
false otherwise. The "My organization" user determines the permissions other people within your organization
have to the given calendar. You cannot remove "My organization" as a sharee to a calendar.
:rtype: bool or None
"""
return self.properties.get("isRemovable", None)

@property
def role(self):
"""
Current permission level of the calendar sharee or delegate.
:rtype: str or None
"""
# type: () -> Optional[str]
"""Current permission level of the calendar sharee or delegate."""
return self.properties.get("role", None)

def get_property(self, name, default_value=None):
Expand Down
8 changes: 5 additions & 3 deletions office365/outlook/calendar/place.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from office365.entity import Entity
from office365.outlook.mail.physical_address import PhysicalAddress

Expand All @@ -8,9 +10,8 @@ class Place(Entity):

@property
def display_name(self):
"""The name associated with the place.
:rtype: str or None
"""
# type: () -> Optional[str]
"""The name associated with the place."""
return self.properties.get("displayName", None)

@property
Expand All @@ -20,5 +21,6 @@ def address(self):

@property
def phone(self):
# type: () -> Optional[str]
"""The phone number of the place."""
return self.properties.get("phone", None)
25 changes: 25 additions & 0 deletions office365/reports/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,18 @@ def get_email_activity_user_detail(self, period):
self.context.add_query(qry)
return qry.return_type

def get_email_app_usage_apps_user_counts(self, period):
"""
Get the count of unique users per email app.
:param str period: Specifies the length of time over which the report is aggregated.
The supported values for {period_value} are: D7, D30, D90, and D180. These values follow the format
Dn where n represents the number of days over which the report is aggregated. Required.
"""
qry = create_report_query(self, "getEmailAppUsageAppsUserCounts", period)
self.context.add_query(qry)
return qry.return_type

def get_m365_app_user_counts(self, period=None):
"""
Get a report that provides the trend in the number of active users for each app (Outlook, Word, Excel,
Expand Down Expand Up @@ -166,6 +178,19 @@ def get_mailbox_usage_detail(self, period):
self.context.add_query(qry)
return qry.return_type

def get_mailbox_usage_mailbox_counts(self, period):
"""
Get the total number of user mailboxes in your organization and how many are active each day of the reporting
period. A mailbox is considered active if the user sent or read any email.
:param str period: Specifies the length of time over which the report is aggregated.
The supported values for {period_value} are: D7, D30, D90, and D180. These values follow the format
Dn where n represents the number of days over which the report is aggregated. Required.
"""
qry = create_report_query(self, "getMailboxUsageMailboxCounts", period)
self.context.add_query(qry)
return qry.return_type

def get_sharepoint_activity_pages(self, period):
"""
Get the number of unique pages visited by users.
Expand Down
5 changes: 3 additions & 2 deletions office365/sharepoint/audit/audit.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from office365.sharepoint.entity import Entity


Expand All @@ -8,11 +10,10 @@ class Audit(Entity):

@property
def allow_designer(self):
# type: () -> Optional[bool]
"""
Specifies whether a designer can be used on this site collection.
See Microsoft.SharePoint.Client.Web.AllowDesignerForCurrentUser, which is the scalar property used
to determine the behavior for the current user. The default, if not disabled on the Web application, is "true".
:rtype: bool or None
"""
return self.properties.get("AllowDesigner", None)
8 changes: 4 additions & 4 deletions office365/sharepoint/changes/list.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from office365.runtime.paths.resource_path import ResourcePath
from office365.sharepoint.changes.change import Change

Expand All @@ -19,10 +21,8 @@ def base_template(self):

@property
def list_id(self):
"""
Identifies the changed list
:rtype: str or None
"""
# type: () -> Optional[str]
"""Identifies the changed list"""
return self.properties.get("ListId", None)

@property
Expand Down
Loading

0 comments on commit 536356f

Please sign in to comment.