Skip to content

Commit

Permalink
Intune API support & typings updates
Browse files Browse the repository at this point in the history
  • Loading branch information
vgrem committed Jan 28, 2024
1 parent 6332a35 commit 9f8e04f
Show file tree
Hide file tree
Showing 43 changed files with 325 additions and 295 deletions.
2 changes: 1 addition & 1 deletion examples/directory/applications/get_by_app_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
https://learn.microsoft.com/en-us/graph/tutorial-applications-basics?tabs=http
You can address an application or a service principal by its ID or by its appId, where ID is referred to
as Object ID and appId is refered to as Application (client) ID on the Azure portal.
as Object ID and appId is referred to as Application (client) ID on the Azure portal.
"""
from office365.graph_client import GraphClient
from tests import test_client_credentials
Expand Down
4 changes: 2 additions & 2 deletions examples/directory/groups/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"""

from office365.graph_client import GraphClient
from tests.graph_case import acquire_token_by_username_password
from tests import test_client_id, test_client_secret, test_tenant

client = GraphClient(acquire_token_by_username_password)
client = GraphClient.with_client_secret(test_tenant, test_client_id, test_client_secret)
groups = client.groups.get().top(100).execute_query()
for grp in groups:
print(grp)
18 changes: 18 additions & 0 deletions examples/directory/policies/get_auth_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""
Retrieves authorization related settings across the company
https://learn.microsoft.com/en-us/graph/api/authorizationpolicy-get?view=graph-rest-1.0
"""
from pprint import pprint

from office365.graph_client import GraphClient
from tests import test_admin_principal_name, test_client_id, test_tenant

client = GraphClient.with_token_interactive(
test_tenant, test_client_id, test_admin_principal_name
)


result = client.policies.authorization_policy.get().execute_query()
pprint(result.to_json())
6 changes: 3 additions & 3 deletions examples/directory/roles/for_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
if o.properties.get("roleTemplateId", None)
]
result = client.directory_roles.get().execute_query()
for o in result:
if o.properties.get("roleTemplateId", None) in role_template_ids:
print(o)
for role in result:
if role.properties.get("roleTemplateId", None) in role_template_ids:
print(role)
6 changes: 4 additions & 2 deletions examples/directory/users/get_my_activities.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
https://learn.microsoft.com/en-us/graph/api/projectrome-get-activities?view=graph-rest-1.0
"""
from office365.graph_client import GraphClient
from tests.graph_case import acquire_token_by_username_password
from tests import test_client_id, test_password, test_tenant, test_username

client = GraphClient(acquire_token_by_username_password)
client = GraphClient.with_username_and_password(
test_tenant, test_client_id, test_username, test_password
)
activities = client.me.activities.get().top(5).execute_query()
for activity in activities:
print(activity)
2 changes: 1 addition & 1 deletion examples/onedrive/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
def upload_excel_sample(graph_client):
# type: (GraphClient) -> DriveItem
local_path = "../../data/Financial Sample.xlsx"
return graph_client.me.drive.root.resumable_upload(local_path).execute_query()
return graph_client.me.drive.root.upload_file(local_path).execute_query()


def ensure_workbook_sample(graph_client):
Expand Down
6 changes: 4 additions & 2 deletions examples/onedrive/files/upload_large.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
"""

from office365.graph_client import GraphClient
from tests.graph_case import acquire_token_by_username_password
from tests import test_client_id, test_password, test_tenant, test_username


def print_progress(range_pos):
# type: (int) -> None
print("{0} bytes uploaded".format(range_pos))


client = GraphClient(acquire_token_by_username_password)
client = GraphClient.with_username_and_password(
test_tenant, test_client_id, test_username, test_password
)
chunk_size = 1 * 1024 * 1024
local_path = "../../../tests/data/big_buck_bunny.mp4"
remote_folder = client.me.drive.root.get_by_path("archive")
Expand Down
6 changes: 3 additions & 3 deletions office365/directory/applications/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,7 @@ def identifier_uris(self):

@property
def public_client(self):
"""
Specifies settings for installed clients such as desktop or mobile devices.
"""
"""Specifies settings for installed clients such as desktop or mobile devices."""
return self.properties.get("publicClient", PublicClientApplication())

@property
Expand All @@ -269,6 +267,7 @@ def signin_audience(self):

@property
def created_on_behalf_of(self):
# type: () -> DirectoryObject
""""""
return self.properties.get(
"createdOnBehalfOf",
Expand All @@ -279,6 +278,7 @@ def created_on_behalf_of(self):

@property
def owners(self):
# type: () -> DirectoryObjectCollection
"""Directory objects that are owners of the application."""
return self.properties.get(
"owners",
Expand Down
65 changes: 40 additions & 25 deletions office365/directory/object_collection.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing_extensions import Self

from office365.delta_collection import DeltaCollection
from office365.directory.object import DirectoryObject
from office365.entity_collection import EntityCollection
from office365.runtime.client_result import ClientResult
from office365.runtime.http.http_method import HttpMethod
from office365.runtime.http.request_options import RequestOptions
from office365.runtime.queries.service_operation import ServiceOperationQuery
Expand All @@ -15,29 +16,32 @@ def __init__(self, context, resource_path=None):
context, DirectoryObject, resource_path
)

def get_by_ids(self, ids):
def get_by_ids(self, ids, types=None):
"""
Returns the directory objects specified in a list of IDs.
:type ids: list[str]
:param list[str] ids: A collection of IDs for which to return objects. The IDs are GUIDs, represented as
strings. You can specify up to 1000 IDs.
:param list[str] types: A collection of resource types that specifies the set of resource collections to search.
If not specified, the default is directoryObject, which contains all of the resource types defined in
the directory. Any object that derives from directoryObject may be specified in the collection;
for example: user, group, and device objects.
"""
return_type = ClientResult(self.context)
params = {"ids": ids}
return_type = DirectoryObjectCollection(self.context)
params = {"ids": ids, "types": types}
qry = ServiceOperationQuery(self, "getByIds", params, None, None, return_type)
self.context.add_query(qry)
return return_type

def add(self, user_id):
"""
Add a user to the group.
def add(self, directory_object):
# type: (DirectoryObject) -> Self
"""Adds directory objects to the collection."""

:type user_id: str
"""
payload = {
"@odata.id": "https://graph.microsoft.com/v1.0/users/{0}".format(user_id)
}
qry = ServiceOperationQuery(self, "$ref", None, payload)
self.context.add_query(qry)
def _add():
payload = {"@odata.id": directory_object.resource_url}
qry = ServiceOperationQuery(self, "$ref", None, payload)
self.context.add_query(qry)

directory_object.ensure_property("id", _add)
return self

def get_available_extension_properties(self, is_synced_from_on_premises=None):
Expand All @@ -60,19 +64,30 @@ def get_available_extension_properties(self, is_synced_from_on_premises=None):
self.context.add_query(qry)
return return_type

def remove(self, user_id):
"""Remove a user from the group.
:param str user_id: User identifier
def remove(self, directory_object):
# type: (DirectoryObject|str) -> Self
"""Removes directory object from the collection.
:param str directory_object: Directory object or identifier
"""

qry = ServiceOperationQuery(self, "{0}/$ref".format(user_id))
def _remove(id_):
qry = ServiceOperationQuery(self, "{0}/$ref".format(id_))

def _construct_request(request):
# type: (RequestOptions) -> None
request.method = HttpMethod.Delete

self.context.add_query(qry).before_query_execute(_construct_request)

if isinstance(directory_object, DirectoryObject):

def _loaded():
_remove(directory_object.id)

def _construct_request(request):
# type: (RequestOptions) -> None
request.method = HttpMethod.Delete
directory_object.ensure_property("id", _loaded)
else:
_remove(directory_object)

self.context.add_query(qry).before_query_execute(_construct_request)
return self

def validate_properties(
Expand Down
5 changes: 5 additions & 0 deletions office365/directory/permissions/default_user_role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from office365.runtime.client_value import ClientValue


class DefaultUserRolePermissions(ClientValue):
"""Contains certain customizable permissions of default user role in Microsoft Entra ID."""
47 changes: 47 additions & 0 deletions office365/directory/policies/authorization.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Optional

from office365.directory.permissions.default_user_role import DefaultUserRolePermissions
from office365.directory.policies.base import PolicyBase


Expand All @@ -13,3 +14,49 @@ def allowed_to_sign_up_email_based_subscriptions(self):
# type: () -> Optional[bool]
"""Indicates whether a user can join the tenant by email validation."""
return self.properties.get("allowedToSignUpEmailBasedSubscriptions", None)

@property
def allowed_to_use_sspr(self):
# type: () -> Optional[bool]
"""Indicates whether users can use the Self-Service Password Reset feature on the tenant."""
return self.properties.get("allowedToUseSSPR", None)

@property
def allow_email_verified_users_to_join_organization(self):
# type: () -> Optional[bool]
"""Indicates whether a user can join the tenant by email validation."""
return self.properties.get("allowEmailVerifiedUsersToJoinOrganization", None)

@property
def allow_invites_from(self):
# type: () -> Optional[str]
"""Indicates who can invite external users to the organization.
Possible values are: none, adminsAndGuestInviters, adminsGuestInvitersAndAllMembers, everyone.
everyone is the default setting for all cloud environments except US Government.
"""
return self.properties.get("allowInvitesFrom", None)

@property
def allow_user_consent_for_risky_apps(self):
# type: () -> Optional[bool]
"""Indicates whether user consent for risky apps is allowed.
We recommend keeping allowUserConsentForRiskyApps as false. Default value is false.
"""
return self.properties.get("allowUserConsentForRiskyApps", None)

@property
def block_msol_powershell(self):
# type: () -> Optional[bool]
"""To disable the use of MSOL PowerShell, set this property to true. This also disables user-based access to
the legacy service endpoint used by MSOL PowerShell. This doesn't affect Microsoft Entra Connect
or Microsoft Graph.
"""
return self.properties.get("blockMsolPowerShell", None)

@property
def default_user_role_permissions(self):
# type: () -> Optional[DefaultUserRolePermissions]
"""Specifies certain customizable permissions for default user role."""
return self.properties.get(
"defaultUserRolePermissions", DefaultUserRolePermissions()
)
8 changes: 4 additions & 4 deletions office365/directory/protection/riskyusers/risky_user.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.entity_collection import EntityCollection
from office365.runtime.paths.resource_path import ResourcePath
Expand Down Expand Up @@ -27,8 +29,6 @@ def history(self):

@property
def user_principal_name(self):
"""
Risky user principal name.
:rtype: str or None
"""
# type: () -> Optional[str]
"""Risky user principal name."""
return self.properties.get("userPrincipalName", None)
12 changes: 5 additions & 7 deletions office365/directory/security/alerts/alert.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from office365.directory.security.alerts.evidence import AlertEvidence
from office365.directory.security.alerts.history_state import AlertHistoryState
from office365.entity import Entity
Expand All @@ -11,17 +13,13 @@ class Alert(Entity):

@property
def actor_display_name(self):
"""
The adversary or activity group that is associated with this alert.
:rtype: str
"""
# type: () -> Optional[str]
"""The adversary or activity group that is associated with this alert."""
return self.properties.get("actorDisplayName", None)

@property
def alert_policy_id(self):
"""
:rtype: str
"""
# type: () -> Optional[str]
return self.properties.get("alertPolicyId", None)

@property
Expand Down
2 changes: 2 additions & 0 deletions office365/directory/security/attacksimulations/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class AttackSimulationRoot(Entity):

@property
def simulations(self):
# type: () -> EntityCollection[Simulation]
"""Represents an attack simulation training campaign in a tenant."""
return self.properties.get(
"simulations",
Expand All @@ -25,6 +26,7 @@ def simulations(self):

@property
def simulation_automations(self):
# type: () -> EntityCollection[SimulationAutomation]
"""Represents simulation automation created to run on a tenant."""
return self.properties.get(
"simulationAutomations",
Expand Down
21 changes: 8 additions & 13 deletions office365/directory/security/incidents/incident.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from typing import Optional

from office365.directory.security.alerts.alert import Alert
from office365.directory.security.alerts.comment import AlertComment
Expand All @@ -23,37 +24,31 @@ class Incident(Entity):

@property
def assigned_to(self):
"""
Owner of the incident, or null if no owner is assigned. Free editable text.
:rtype: str or None
"""
# type: () -> Optional[str]
"""Owner of the incident, or null if no owner is assigned. Free editable text."""
return self.properties.get("assignedTo", None)

@property
def classification(self):
"""
The specification for the incident.
# type: () -> Optional[str]
"""The specification for the incident.
Possible values are: unknown, falsePositive, truePositive, informationalExpectedActivity, unknownFutureValue.
:rtype: str or None
"""
return self.properties.get("classification", None)

@property
def comments(self):
"""
Array of comments created by the Security Operations (SecOps) team when the incident is managed.
"""
"""Array of comments created by the Security Operations (SecOps) team when the incident is managed."""
return self.properties.get("comments", ClientValueCollection(AlertComment))

@property
def created_datetime(self):
"""
Time when the incident was first created.
"""
"""Time when the incident was first created."""
return self.properties("createdDateTime", datetime.min)

@property
def alerts(self):
# type: () -> EntityCollection[Alert]
"""The list of related alerts. Supports $expand."""
return self.properties.get(
"alerts",
Expand Down

0 comments on commit 9f8e04f

Please sign in to comment.