Office365-REST-Python-Client 2.5.14__py3-none-any.whl → 2.6.0__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.
- {Office365_REST_Python_Client-2.5.14.dist-info → Office365_REST_Python_Client-2.6.0.dist-info}/METADATA +2 -2
- {Office365_REST_Python_Client-2.5.14.dist-info → Office365_REST_Python_Client-2.6.0.dist-info}/RECORD +210 -112
- office365/admin/__init__.py +0 -0
- office365/admin/admin.py +69 -0
- office365/admin/microsoft365_apps.py +5 -0
- office365/admin/people_settings.py +5 -0
- office365/admin/report_settings.py +5 -0
- office365/{onedrive → admin}/sharepoint.py +1 -1
- office365/azure_env.py +60 -0
- office365/directory/applications/app_ids.py +6 -0
- office365/directory/authentication/authentication.py +16 -0
- office365/directory/authentication/method_target.py +2 -1
- office365/directory/authentication/methods/microsoft_authenticator.py +6 -0
- office365/directory/authentication/methods/root.py +11 -0
- office365/directory/authentication/methods/sms.py +9 -0
- office365/directory/certificates/self_signed.py +31 -2
- office365/directory/identities/conditional_access_root.py +14 -0
- office365/directory/identitygovernance/privilegedaccess/approval.py +8 -0
- office365/directory/identitygovernance/privilegedaccess/group.py +30 -0
- office365/directory/identitygovernance/privilegedaccess/group_assignment_schedule_instance.py +7 -0
- office365/directory/identitygovernance/privilegedaccess/unified_role_assignment_schedule_request.py +7 -0
- office365/directory/identitygovernance/userconsent/request_collection.py +10 -0
- office365/directory/identitygovernance/workflow/__init__.py +0 -0
- office365/directory/identitygovernance/workflow/base.py +5 -0
- office365/directory/policies/cross_tenant_access.py +13 -0
- office365/directory/policies/feature_rollout.py +16 -0
- office365/directory/policies/root.py +39 -23
- office365/directory/policies/template.py +5 -0
- office365/directory/protection/threatassessment/email_file_request.py +20 -0
- office365/directory/protection/threatassessment/request.py +25 -0
- office365/directory/rolemanagement/application.py +15 -0
- office365/directory/rolemanagement/resource_action.py +8 -4
- office365/directory/rolemanagement/role_permission.py +3 -3
- office365/directory/security/alerts/collection.py +49 -0
- office365/directory/security/scorecontrol/__init__.py +0 -0
- office365/directory/security/scorecontrol/profile.py +6 -0
- office365/directory/security/security.py +17 -4
- office365/directory/serviceprincipals/service_principal.py +36 -28
- office365/directory/tenantinformation/__init__.py +0 -0
- office365/directory/tenantinformation/multi_organization.py +11 -0
- office365/directory/tenantinformation/relationship.py +61 -0
- office365/directory/users/insights_settings.py +5 -0
- office365/graph_client.py +52 -132
- office365/graph_request.py +78 -19
- office365/intune/servicecommunications/health/health.py +1 -1
- office365/intune/servicecommunications/issues/issue.py +2 -2
- office365/onedrive/columns/definition.py +1 -1
- office365/onedrive/contenttypes/content_type.py +1 -1
- office365/onedrive/driveitems/driveItem.py +13 -1
- office365/onedrive/drives/drive.py +1 -1
- office365/onedrive/filestorage/__init__.py +0 -0
- office365/onedrive/filestorage/container.py +7 -0
- office365/onedrive/filestorage/file_storage.py +20 -0
- office365/onedrive/listitems/field_value_set.py +1 -1
- office365/onedrive/listitems/list_item.py +1 -1
- office365/onedrive/lists/list.py +1 -1
- office365/onedrive/recyclebin/__init__.py +0 -0
- office365/onedrive/recyclebin/item.py +6 -0
- office365/onedrive/recyclebin/recyclebin.py +29 -0
- office365/onedrive/recyclebin/settings.py +13 -0
- office365/onedrive/shares/drive_item.py +1 -1
- office365/onedrive/sitepages/base.py +1 -1
- office365/onedrive/sitepages/canvas_layout.py +2 -2
- office365/onedrive/sitepages/sections/__init__.py +0 -0
- office365/onedrive/sitepages/{horizontal_section.py → sections/horizontal.py} +1 -1
- office365/onedrive/sitepages/webparts/data.py +5 -0
- office365/onedrive/sitepages/webparts/position.py +5 -0
- office365/onedrive/sitepages/webparts/standard.py +9 -0
- office365/onedrive/sitepages/webparts/web_part.py +12 -0
- office365/onedrive/sites/site.py +1 -1
- office365/onedrive/storage/storage.py +10 -0
- office365/onedrive/workbooks/charts/axes.py +41 -1
- office365/onedrive/workbooks/charts/axis.py +5 -0
- office365/onedrive/workbooks/charts/chart.py +64 -5
- office365/onedrive/workbooks/charts/fill.py +5 -0
- office365/onedrive/workbooks/charts/font.py +5 -0
- office365/onedrive/workbooks/charts/legend/__init__.py +0 -0
- office365/onedrive/workbooks/charts/legend/format.py +5 -0
- office365/onedrive/workbooks/charts/legend/legend.py +26 -0
- office365/onedrive/workbooks/charts/point.py +5 -0
- office365/onedrive/workbooks/charts/series/__init__.py +0 -0
- office365/onedrive/workbooks/charts/series/format.py +5 -0
- office365/onedrive/workbooks/charts/series/series.py +31 -0
- office365/onedrive/workbooks/charts/title.py +5 -0
- office365/onedrive/workbooks/filter.py +10 -0
- office365/onedrive/workbooks/filter_criteria.py +3 -3
- office365/onedrive/workbooks/ranges/fill.py +11 -1
- office365/onedrive/workbooks/ranges/range.py +26 -0
- office365/onedrive/workbooks/ranges/view.py +14 -0
- office365/onedrive/workbooks/sort_field.py +8 -3
- office365/onedrive/workbooks/tables/sort.py +20 -0
- office365/onedrive/workbooks/worksheets/worksheet.py +11 -0
- office365/partners/billing/azure_usage.py +17 -0
- office365/partners/billing/billed_usage.py +21 -0
- office365/partners/billing/billing.py +17 -0
- office365/partners/billing/operation.py +5 -0
- office365/partners/partners.py +17 -0
- office365/reports/root.py +9 -0
- office365/reports/userregistration/feature_summary.py +5 -0
- office365/runtime/auth/auth_cookies.py +48 -0
- office365/runtime/auth/authentication_context.py +36 -19
- office365/runtime/auth/entra/__init__.py +0 -0
- office365/runtime/auth/entra/authentication_context.py +165 -0
- office365/runtime/auth/providers/acs_token_provider.py +12 -27
- office365/runtime/auth/providers/saml_token_provider.py +41 -54
- office365/runtime/auth/sts_profile.py +8 -8
- office365/runtime/auth/token_response.py +4 -0
- office365/sharepoint/administration/custom_fonts_resource.py +5 -0
- office365/sharepoint/administration/sitemove/__init__.py +0 -0
- office365/sharepoint/administration/sitemove/service.py +68 -0
- office365/sharepoint/administration/sitemove/service_info.py +11 -0
- office365/sharepoint/changes/item.py +15 -0
- office365/sharepoint/client_context.py +61 -37
- office365/sharepoint/directory/group.py +2 -0
- office365/sharepoint/directory/helper.py +2 -0
- office365/sharepoint/directory/provider/provider.py +6 -0
- office365/sharepoint/directory/user.py +20 -0
- office365/sharepoint/files/publish/__init__.py +0 -0
- office365/sharepoint/files/publish/status.py +9 -0
- office365/sharepoint/flows/connector_result.py +17 -0
- office365/sharepoint/flows/permissions.py +11 -7
- office365/sharepoint/fontpackages/__init__.py +0 -0
- office365/sharepoint/fontpackages/collection.py +26 -0
- office365/sharepoint/fontpackages/creation_parameters.py +5 -0
- office365/sharepoint/fontpackages/font_package.py +5 -0
- office365/sharepoint/fontpackages/oob_settings.py +5 -0
- office365/sharepoint/forms/customization.py +26 -0
- office365/sharepoint/ir/__init__.py +0 -0
- office365/sharepoint/ir/migration.py +5 -0
- office365/sharepoint/lists/list.py +30 -0
- office365/sharepoint/marketplace/app_metadata.py +12 -1
- office365/sharepoint/marketplace/app_metadata_collection.py +8 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/addins/instance_info.py +22 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/addins/permission_failed_info.py +5 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/addins/permission_info.py +12 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/addins/permission_response.py +15 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/addins/principals_response.py +5 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/app_request_information.py +9 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/app_response_information.py +9 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/available_addins_response.py +4 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/card_design.py +9 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/card_designs.py +9 -0
- office365/sharepoint/marketplace/corporatecuratedgallery/teams_package_download.py +14 -0
- office365/sharepoint/marketplace/tenant/appcatalog/accessor.py +62 -3
- office365/sharepoint/multigeo/services.py +14 -0
- office365/sharepoint/multigeo/storage_quota.py +9 -0
- office365/sharepoint/policy/license_utilities.py +27 -0
- office365/sharepoint/principal/principal.py +6 -0
- office365/sharepoint/request.py +95 -10
- office365/sharepoint/search/administration/document_crawl_log.py +16 -2
- office365/sharepoint/search/administration/tenant_crawl_versions_info_provider.py +1 -1
- office365/sharepoint/search/reports/abandoned_queries.py +11 -1
- office365/sharepoint/search/reports/abandonedqueries/item.py +7 -1
- office365/sharepoint/sharing/domain_restriction_settings.py +5 -0
- office365/sharepoint/sharing/information.py +12 -0
- office365/sharepoint/sitehealth/result.py +4 -4
- office365/sharepoint/sitehealth/summary.py +5 -5
- office365/sharepoint/sites/copy_job_progress.py +5 -0
- office365/sharepoint/sites/copy_migration_iInfo.py +5 -0
- office365/sharepoint/sites/home/__init__.py +0 -0
- office365/sharepoint/sites/{sph_site.py → home/site.py} +1 -1
- office365/sharepoint/sites/site.py +26 -1
- office365/sharepoint/tenant/administration/app_service_principal_public.py +17 -0
- office365/sharepoint/tenant/administration/audit/data.py +12 -0
- office365/sharepoint/tenant/administration/audit/unified_record.py +18 -0
- office365/sharepoint/tenant/administration/coms/__init__.py +0 -0
- office365/sharepoint/tenant/administration/coms/messages_fields_data.py +5 -0
- office365/sharepoint/tenant/administration/coms/messages_service_proxy.py +16 -0
- office365/sharepoint/tenant/administration/copilot/__init__.py +0 -0
- office365/sharepoint/tenant/administration/copilot/adaptive_card_config.py +11 -0
- office365/sharepoint/tenant/administration/datagovernance/__init__.py +0 -0
- office365/sharepoint/tenant/administration/datagovernance/client_base.py +9 -0
- office365/sharepoint/tenant/administration/datagovernance/insight_client.py +82 -0
- office365/sharepoint/tenant/administration/datagovernance/insight_metadata.py +5 -0
- office365/sharepoint/tenant/administration/default_time_zone_id.py +11 -0
- office365/sharepoint/tenant/administration/endpoints.py +53 -2
- office365/sharepoint/tenant/administration/insights/onedrive_site_sharing.py +4 -0
- office365/sharepoint/tenant/administration/internal/appservice/permission_request.py +4 -0
- office365/sharepoint/tenant/administration/malware/__init__.py +0 -0
- office365/sharepoint/tenant/administration/malware/file.py +18 -0
- office365/sharepoint/tenant/administration/modified_property.py +5 -0
- office365/sharepoint/tenant/administration/policies/content_security_configuration.py +9 -0
- office365/sharepoint/tenant/administration/recent_action.py +9 -0
- office365/sharepoint/tenant/administration/reports/__init__.py +0 -0
- office365/sharepoint/tenant/administration/settings_service.py +38 -5
- office365/sharepoint/tenant/administration/sites/properties.py +78 -0
- office365/sharepoint/tenant/administration/sites/properties_collection.py +19 -0
- office365/sharepoint/tenant/administration/tenant.py +134 -7
- office365/sharepoint/tenant/administration/types.py +76 -1
- office365/sharepoint/tenant/insights/report_manager.py +29 -0
- office365/sharepoint/tenant/management/office365_tenant.py +7 -4
- office365/sharepoint/translation/job_status.py +22 -0
- office365/sharepoint/userprofiles/user_profile.py +6 -0
- office365/sharepoint/webparts/tile_data.py +21 -0
- office365/sharepoint/webs/dataleakage_prevention_status_info.py +5 -0
- office365/sharepoint/webs/web.py +80 -1
- office365/teams/chats/event_message_detail.py +8 -0
- office365/teams/deleted.py +24 -0
- office365/teams/work.py +35 -0
- office365/directory/tenant_relationship.py +0 -23
- office365/onedrive/admin.py +0 -32
- office365/onedrive/workbooks/charts/legend.py +0 -7
- office365/onedrive/workbooks/charts/series.py +0 -5
- {Office365_REST_Python_Client-2.5.14.dist-info → Office365_REST_Python_Client-2.6.0.dist-info}/LICENSE +0 -0
- {Office365_REST_Python_Client-2.5.14.dist-info → Office365_REST_Python_Client-2.6.0.dist-info}/WHEEL +0 -0
- {Office365_REST_Python_Client-2.5.14.dist-info → Office365_REST_Python_Client-2.6.0.dist-info}/top_level.txt +0 -0
- /office365/{onedrive → admin}/sharepoint_settings.py +0 -0
- /office365/directory/{tenant_information.py → tenantinformation/information.py} +0 -0
- /office365/{base_item.py → onedrive/base_item.py} +0 -0
- /office365/onedrive/sitepages/{horizontal_section_column.py → sections/horizontal_column.py} +0 -0
- /office365/onedrive/sitepages/{vertical_section.py → sections/vertical.py} +0 -0
- /office365/sharepoint/sites/{home_sites_details.py → home/details.py} +0 -0
- /office365/sharepoint/sites/{home_site_reference.py → home/reference.py} +0 -0
- /office365/sharepoint/tenant/administration/{app_billing_properties.py → policies/app_billing_properties.py} +0 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from office365.azure_env import AzureEnvironment
|
|
4
|
+
from office365.runtime.auth.token_response import TokenResponse
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AuthenticationContext(object):
|
|
8
|
+
"""Provides authentication context for Microsoft Graph client"""
|
|
9
|
+
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
tenant=None,
|
|
13
|
+
scopes=None,
|
|
14
|
+
token_cache=None,
|
|
15
|
+
environment=AzureEnvironment.Global,
|
|
16
|
+
):
|
|
17
|
+
"""
|
|
18
|
+
:param str tenant: Tenant name, for example: contoso.onmicrosoft.com
|
|
19
|
+
:param list[str] or None scopes: Scopes requested to access an API
|
|
20
|
+
:param Any token_cache: Default cache is in memory only,
|
|
21
|
+
Refer https://msal-python.readthedocs.io/en/latest/#msal.SerializableTokenCache
|
|
22
|
+
"""
|
|
23
|
+
self._tenant = tenant
|
|
24
|
+
if scopes is None:
|
|
25
|
+
scopes = [
|
|
26
|
+
"{0}/.default".format(AzureEnvironment.get_graph_authority(environment))
|
|
27
|
+
]
|
|
28
|
+
self._scopes = scopes
|
|
29
|
+
self._token_cache = token_cache
|
|
30
|
+
self._token_callback = None
|
|
31
|
+
self._environment = environment
|
|
32
|
+
|
|
33
|
+
def acquire_token(self):
|
|
34
|
+
# type: () -> TokenResponse
|
|
35
|
+
"""Acquire access token"""
|
|
36
|
+
if not self._token_callback:
|
|
37
|
+
raise ValueError("Token callback is not set.")
|
|
38
|
+
token_resp = self._token_callback()
|
|
39
|
+
token = TokenResponse.from_json(token_resp)
|
|
40
|
+
return token
|
|
41
|
+
|
|
42
|
+
def with_access_token(self, token_callback):
|
|
43
|
+
""""""
|
|
44
|
+
self._token_callback = token_callback
|
|
45
|
+
return self
|
|
46
|
+
|
|
47
|
+
def with_certificate(self, client_id, thumbprint, private_key):
|
|
48
|
+
"""
|
|
49
|
+
Initializes the confidential client with client certificate
|
|
50
|
+
|
|
51
|
+
:param str client_id: The OAuth client id of the calling application.
|
|
52
|
+
:param str thumbprint: Thumbprint
|
|
53
|
+
:param str private_key: Private key
|
|
54
|
+
"""
|
|
55
|
+
import msal
|
|
56
|
+
|
|
57
|
+
app = msal.ConfidentialClientApplication(
|
|
58
|
+
client_id,
|
|
59
|
+
authority=self.authority_url,
|
|
60
|
+
client_credential={
|
|
61
|
+
"thumbprint": thumbprint,
|
|
62
|
+
"private_key": private_key,
|
|
63
|
+
},
|
|
64
|
+
token_cache=self._token_cache, # Default cache is in memory only.
|
|
65
|
+
# You can learn how to use SerializableTokenCache from
|
|
66
|
+
# https://msal-python.readthedocs.io/en/latest/#msal.SerializableTokenCache
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def _acquire_token():
|
|
70
|
+
return app.acquire_token_for_client(scopes=self._scopes)
|
|
71
|
+
|
|
72
|
+
return self.with_access_token(_acquire_token)
|
|
73
|
+
|
|
74
|
+
def with_client_secret(self, client_id, client_secret):
|
|
75
|
+
# type: (str, str) -> "AuthenticationContext"
|
|
76
|
+
"""
|
|
77
|
+
Initializes the confidential client with client secret
|
|
78
|
+
|
|
79
|
+
:param str client_id: The OAuth client id of the calling application.
|
|
80
|
+
:param str client_secret: Client secret
|
|
81
|
+
"""
|
|
82
|
+
import msal
|
|
83
|
+
|
|
84
|
+
app = msal.ConfidentialClientApplication(
|
|
85
|
+
client_id,
|
|
86
|
+
authority=self.authority_url,
|
|
87
|
+
client_credential=client_secret,
|
|
88
|
+
token_cache=self._token_cache,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def _acquire_token():
|
|
92
|
+
return app.acquire_token_for_client(scopes=self._scopes)
|
|
93
|
+
|
|
94
|
+
return self.with_access_token(_acquire_token)
|
|
95
|
+
|
|
96
|
+
def with_token_interactive(self, client_id, username=None):
|
|
97
|
+
# type: (str, Optional[str]) -> "AuthenticationContext"
|
|
98
|
+
"""
|
|
99
|
+
Initializes the client via user credentials
|
|
100
|
+
Note: only works if your app is registered with redirect_uri as http://localhost
|
|
101
|
+
|
|
102
|
+
:param str client_id: The OAuth client id of the calling application.
|
|
103
|
+
:param str username: Typically a UPN in the form of an email address.
|
|
104
|
+
"""
|
|
105
|
+
import msal
|
|
106
|
+
|
|
107
|
+
app = msal.PublicClientApplication(client_id, authority=self.authority_url)
|
|
108
|
+
|
|
109
|
+
def _acquire_token():
|
|
110
|
+
# The pattern to acquire a token looks like this.
|
|
111
|
+
result = None
|
|
112
|
+
|
|
113
|
+
# Firstly, check the cache to see if this end user has signed in before
|
|
114
|
+
accounts = app.get_accounts(username=username)
|
|
115
|
+
if accounts:
|
|
116
|
+
chosen = accounts[0] # Assuming the end user chose this one to proceed
|
|
117
|
+
# Now let's try to find a token in cache for this account
|
|
118
|
+
result = app.acquire_token_silent(self._scopes, account=chosen)
|
|
119
|
+
|
|
120
|
+
if not result:
|
|
121
|
+
result = app.acquire_token_interactive(
|
|
122
|
+
self._scopes,
|
|
123
|
+
login_hint=username,
|
|
124
|
+
)
|
|
125
|
+
return result
|
|
126
|
+
|
|
127
|
+
return self.with_access_token(_acquire_token)
|
|
128
|
+
|
|
129
|
+
def with_username_and_password(self, client_id, username, password):
|
|
130
|
+
# type: (str, str, str) -> "AuthenticationContext"
|
|
131
|
+
"""
|
|
132
|
+
Initializes the client via user credentials
|
|
133
|
+
|
|
134
|
+
:param str client_id: The OAuth client id of the calling application.
|
|
135
|
+
:param str username: Typically a UPN in the form of an email address.
|
|
136
|
+
:param str password: The password.
|
|
137
|
+
"""
|
|
138
|
+
import msal
|
|
139
|
+
|
|
140
|
+
app = msal.PublicClientApplication(
|
|
141
|
+
authority=self.authority_url,
|
|
142
|
+
client_id=client_id,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def _acquire_token():
|
|
146
|
+
result = None
|
|
147
|
+
accounts = app.get_accounts(username=username)
|
|
148
|
+
if accounts:
|
|
149
|
+
result = app.acquire_token_silent(self._scopes, account=accounts[0])
|
|
150
|
+
|
|
151
|
+
if not result:
|
|
152
|
+
result = app.acquire_token_by_username_password(
|
|
153
|
+
username=username,
|
|
154
|
+
password=password,
|
|
155
|
+
scopes=self._scopes,
|
|
156
|
+
)
|
|
157
|
+
return result
|
|
158
|
+
|
|
159
|
+
return self.with_access_token(_acquire_token)
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def authority_url(self):
|
|
163
|
+
return "{0}/{1}".format(
|
|
164
|
+
AzureEnvironment.get_login_authority(self._environment), self._tenant
|
|
165
|
+
)
|
|
@@ -3,6 +3,7 @@ from typing import Optional
|
|
|
3
3
|
import requests
|
|
4
4
|
|
|
5
5
|
import office365.logger
|
|
6
|
+
from office365.azure_env import AzureEnvironment
|
|
6
7
|
from office365.runtime.auth.authentication_provider import AuthenticationProvider
|
|
7
8
|
from office365.runtime.auth.token_response import TokenResponse
|
|
8
9
|
from office365.runtime.compat import urlparse
|
|
@@ -10,7 +11,7 @@ from office365.runtime.http.request_options import RequestOptions
|
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class ACSTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
13
|
-
def __init__(self, url, client_id, client_secret, environment=
|
|
14
|
+
def __init__(self, url, client_id, client_secret, environment=None):
|
|
14
15
|
"""
|
|
15
16
|
Provider to acquire the access token from a Microsoft Azure Access Control Service (ACS)
|
|
16
17
|
|
|
@@ -18,7 +19,7 @@ class ACSTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
18
19
|
:param str client_secret: Secret string that the application uses to prove its identity when requesting a token
|
|
19
20
|
:param str url: SharePoint web or site url
|
|
20
21
|
:param str environment: The Office 365 Cloud Environment endpoint used for authentication
|
|
21
|
-
defaults to '
|
|
22
|
+
defaults to 'Azure Global'.
|
|
22
23
|
"""
|
|
23
24
|
self.url = url
|
|
24
25
|
self.redirect_url = None
|
|
@@ -26,18 +27,14 @@ class ACSTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
26
27
|
self.SharePointPrincipal = "00000003-0000-0ff1-ce00-000000000000"
|
|
27
28
|
self._client_id = client_id
|
|
28
29
|
self._client_secret = client_secret
|
|
29
|
-
self._cached_token = None
|
|
30
|
+
self._cached_token = None # type: Optional[TokenResponse]
|
|
30
31
|
self._environment = environment
|
|
31
32
|
|
|
32
33
|
def authenticate_request(self, request):
|
|
33
34
|
# type: (RequestOptions) -> None
|
|
34
|
-
self.ensure_app_only_access_token()
|
|
35
|
-
request.set_header("Authorization", self._get_authorization_header())
|
|
36
|
-
|
|
37
|
-
def ensure_app_only_access_token(self):
|
|
38
35
|
if self._cached_token is None:
|
|
39
36
|
self._cached_token = self.get_app_only_access_token()
|
|
40
|
-
|
|
37
|
+
request.set_header("Authorization", self._cached_token.authorization_header)
|
|
41
38
|
|
|
42
39
|
def get_app_only_access_token(self):
|
|
43
40
|
"""Retrieves an app-only access token from ACS"""
|
|
@@ -65,9 +62,7 @@ class ACSTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
65
62
|
self.SharePointPrincipal, target_host, target_realm
|
|
66
63
|
)
|
|
67
64
|
principal_id = self.get_formatted_principal(self._client_id, None, target_realm)
|
|
68
|
-
sts_url = self.get_security_token_service_url(
|
|
69
|
-
target_realm, environment=self._environment
|
|
70
|
-
)
|
|
65
|
+
sts_url = self.get_security_token_service_url(target_realm)
|
|
71
66
|
oauth2_request = {
|
|
72
67
|
"grant_type": "client_credentials",
|
|
73
68
|
"client_id": principal_id,
|
|
@@ -86,11 +81,6 @@ class ACSTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
86
81
|
def _get_realm_from_target_url(self):
|
|
87
82
|
"""Get the realm for the URL"""
|
|
88
83
|
response = requests.head(url=self.url, headers={"Authorization": "Bearer"})
|
|
89
|
-
return self.process_realm_response(response)
|
|
90
|
-
|
|
91
|
-
@staticmethod
|
|
92
|
-
def process_realm_response(response):
|
|
93
|
-
# type: (requests.Response) -> Optional[str]
|
|
94
84
|
header_key = "WWW-Authenticate"
|
|
95
85
|
if header_key in response.headers:
|
|
96
86
|
auth_values = response.headers[header_key].split(",")
|
|
@@ -105,20 +95,15 @@ class ACSTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
105
95
|
return "{0}/{1}@{2}".format(principal_name, host_name, realm)
|
|
106
96
|
return "{0}@{1}".format(principal_name, realm)
|
|
107
97
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
98
|
+
def get_security_token_service_url(self, realm):
|
|
99
|
+
# type: (str) -> str
|
|
100
|
+
if self._environment:
|
|
101
|
+
return "{0}/{1}/tokens/OAuth/2".format(
|
|
102
|
+
AzureEnvironment.get_login_authority(self._environment), realm
|
|
103
|
+
)
|
|
113
104
|
else:
|
|
114
105
|
return (
|
|
115
106
|
"https://accounts.accesscontrol.windows.net/{0}/tokens/OAuth/2".format(
|
|
116
107
|
realm
|
|
117
108
|
)
|
|
118
109
|
)
|
|
119
|
-
|
|
120
|
-
def _get_authorization_header(self):
|
|
121
|
-
return "Bearer {0}".format(self._cached_token.accessToken)
|
|
122
|
-
|
|
123
|
-
def get_last_error(self):
|
|
124
|
-
return self.error
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import uuid
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from typing import Optional
|
|
3
5
|
from xml.dom import minidom
|
|
4
6
|
from xml.etree import ElementTree
|
|
5
7
|
|
|
@@ -7,6 +9,7 @@ import requests
|
|
|
7
9
|
import requests.utils
|
|
8
10
|
|
|
9
11
|
import office365.logger
|
|
12
|
+
from office365.runtime.auth.auth_cookies import AuthCookies
|
|
10
13
|
from office365.runtime.auth.authentication_provider import AuthenticationProvider
|
|
11
14
|
from office365.runtime.auth.sts_profile import STSProfile
|
|
12
15
|
from office365.runtime.auth.user_realm_info import UserRealmInfo
|
|
@@ -20,23 +23,17 @@ def resolve_base_url(url):
|
|
|
20
23
|
return parts[0] + "://" + host_name
|
|
21
24
|
|
|
22
25
|
|
|
23
|
-
def
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return
|
|
26
|
+
def string_escape(value):
|
|
27
|
+
value = value.replace("&", "&")
|
|
28
|
+
value = value.replace("<", "<")
|
|
29
|
+
value = value.replace(">", ">")
|
|
30
|
+
value = value.replace('"', """)
|
|
31
|
+
value = value.replace("'", "'")
|
|
32
|
+
return value
|
|
30
33
|
|
|
31
34
|
|
|
32
|
-
def
|
|
33
|
-
"""
|
|
34
|
-
Validates authorization cookies
|
|
35
|
-
"""
|
|
36
|
-
return any(values) and (
|
|
37
|
-
values.get("FedAuth", None) is not None
|
|
38
|
-
or values.get("SPOIDCRL", None) is not None
|
|
39
|
-
)
|
|
35
|
+
def datetime_escape(value):
|
|
36
|
+
return value.isoformat("T")[:-9] + "Z"
|
|
40
37
|
|
|
41
38
|
|
|
42
39
|
class SamlTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
@@ -60,7 +57,7 @@ class SamlTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
60
57
|
self.error = ""
|
|
61
58
|
self._username = username
|
|
62
59
|
self._password = password
|
|
63
|
-
self._cached_auth_cookies = None
|
|
60
|
+
self._cached_auth_cookies = None # type: Optional[AuthCookies]
|
|
64
61
|
self.__ns_prefixes = {
|
|
65
62
|
"S": "{http://www.w3.org/2003/05/soap-envelope}",
|
|
66
63
|
"s": "{http://www.w3.org/2003/05/soap-envelope}",
|
|
@@ -82,24 +79,20 @@ class SamlTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
82
79
|
Authenticate request handler
|
|
83
80
|
"""
|
|
84
81
|
logger = self.logger(self.authenticate_request.__name__)
|
|
85
|
-
self.ensure_authentication_cookie()
|
|
86
|
-
logger.debug_secrets(self._cached_auth_cookies)
|
|
87
|
-
cookie_header_value = "; ".join(
|
|
88
|
-
[
|
|
89
|
-
"=".join([key, str(val)])
|
|
90
|
-
for key, val in self._cached_auth_cookies.items()
|
|
91
|
-
]
|
|
92
|
-
)
|
|
93
|
-
request.set_header("Cookie", cookie_header_value)
|
|
94
82
|
|
|
95
|
-
|
|
96
|
-
if
|
|
83
|
+
request_time = datetime.now(timezone.utc)
|
|
84
|
+
if (
|
|
85
|
+
self._cached_auth_cookies is None
|
|
86
|
+
or request_time >= self._sts_profile.expires
|
|
87
|
+
):
|
|
88
|
+
self._sts_profile.reset()
|
|
97
89
|
self._cached_auth_cookies = self.get_authentication_cookie()
|
|
98
|
-
|
|
90
|
+
logger.debug_secrets(self._cached_auth_cookies)
|
|
91
|
+
request.set_header("Cookie", self._cached_auth_cookies.cookie_header)
|
|
99
92
|
|
|
100
93
|
def get_authentication_cookie(self):
|
|
101
94
|
"""Acquire authentication cookie"""
|
|
102
|
-
logger = self.logger(self.
|
|
95
|
+
logger = self.logger(self.get_authentication_cookie.__name__)
|
|
103
96
|
logger.debug("get_authentication_cookie called")
|
|
104
97
|
|
|
105
98
|
try:
|
|
@@ -132,9 +125,6 @@ class SamlTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
132
125
|
return info
|
|
133
126
|
return None
|
|
134
127
|
|
|
135
|
-
def get_last_error(self):
|
|
136
|
-
return self.error
|
|
137
|
-
|
|
138
128
|
def _acquire_service_token_from_adfs(self, adfs_url):
|
|
139
129
|
logger = self.logger(self._acquire_service_token_from_adfs.__name__)
|
|
140
130
|
|
|
@@ -143,10 +133,10 @@ class SamlTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
143
133
|
{
|
|
144
134
|
"auth_url": adfs_url,
|
|
145
135
|
"message_id": str(uuid.uuid4()),
|
|
146
|
-
"username":
|
|
147
|
-
"password":
|
|
148
|
-
"created": self._sts_profile.created,
|
|
149
|
-
"expires": self._sts_profile.expires,
|
|
136
|
+
"username": string_escape(self._username),
|
|
137
|
+
"password": string_escape(self._password),
|
|
138
|
+
"created": datetime_escape(self._sts_profile.created),
|
|
139
|
+
"expires": datetime_escape(self._sts_profile.expires),
|
|
150
140
|
"issuer": self._sts_profile.tokenIssuer,
|
|
151
141
|
},
|
|
152
142
|
)
|
|
@@ -195,11 +185,11 @@ class SamlTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
195
185
|
"SAML.xml",
|
|
196
186
|
{
|
|
197
187
|
"auth_url": self._sts_profile.authorityUrl,
|
|
198
|
-
"username":
|
|
199
|
-
"password":
|
|
188
|
+
"username": string_escape(self._username),
|
|
189
|
+
"password": string_escape(self._password),
|
|
200
190
|
"message_id": str(uuid.uuid4()),
|
|
201
|
-
"created": self._sts_profile.created,
|
|
202
|
-
"expires": self._sts_profile.expires,
|
|
191
|
+
"created": datetime_escape(self._sts_profile.created),
|
|
192
|
+
"expires": datetime_escape(self._sts_profile.expires),
|
|
203
193
|
"issuer": self._sts_profile.tokenIssuer,
|
|
204
194
|
},
|
|
205
195
|
)
|
|
@@ -300,9 +290,9 @@ class SamlTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
300
290
|
},
|
|
301
291
|
)
|
|
302
292
|
logger.debug_secrets("session.cookies: %s", session.cookies)
|
|
303
|
-
cookies = requests.utils.dict_from_cookiejar(session.cookies)
|
|
293
|
+
cookies = AuthCookies(requests.utils.dict_from_cookiejar(session.cookies))
|
|
304
294
|
logger.debug_secrets("cookies: %s", cookies)
|
|
305
|
-
if not
|
|
295
|
+
if not cookies.is_valid:
|
|
306
296
|
self.error = (
|
|
307
297
|
"An error occurred while retrieving auth cookies from {0}".format(
|
|
308
298
|
self._sts_profile.signin_page_url
|
|
@@ -312,19 +302,16 @@ class SamlTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
|
|
|
312
302
|
raise ValueError(self.error)
|
|
313
303
|
return cookies
|
|
314
304
|
|
|
315
|
-
|
|
316
|
-
def _prepare_request_from_template(template_name, params):
|
|
305
|
+
def _prepare_request_from_template(self, template_name, params):
|
|
317
306
|
"""Construct the request body to acquire security token from STS endpoint"""
|
|
318
|
-
logger =
|
|
307
|
+
logger = self.logger(self._prepare_request_from_template.__name__)
|
|
319
308
|
logger.debug_secrets("params: %s", params)
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
309
|
+
|
|
310
|
+
template_path = os.path.join(
|
|
311
|
+
os.path.dirname(__file__), "templates", template_name
|
|
323
312
|
)
|
|
324
|
-
|
|
313
|
+
|
|
314
|
+
with open(template_path, encoding="utf8") as f:
|
|
325
315
|
data = f.read()
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
return data
|
|
329
|
-
finally:
|
|
330
|
-
f.close()
|
|
316
|
+
|
|
317
|
+
return data.format(**params)
|
|
@@ -5,9 +5,7 @@ from office365.runtime.compat import timezone, urlparse
|
|
|
5
5
|
|
|
6
6
|
class STSProfile(object):
|
|
7
7
|
def __init__(self, authority_url, environment):
|
|
8
|
-
|
|
9
|
-
:type authority_url: str
|
|
10
|
-
"""
|
|
8
|
+
# type: (str, str) -> None
|
|
11
9
|
self.authorityUrl = authority_url
|
|
12
10
|
if environment == "GCCH":
|
|
13
11
|
self.serviceUrl = "https://login.microsoftonline.us"
|
|
@@ -16,13 +14,15 @@ class STSProfile(object):
|
|
|
16
14
|
self.securityTokenServicePath = "extSTS.srf"
|
|
17
15
|
self.userRealmServicePath = "GetUserRealm.srf"
|
|
18
16
|
self.tokenIssuer = "urn:federation:MicrosoftOnline"
|
|
19
|
-
|
|
20
|
-
self.
|
|
21
|
-
self.expires = (now + timedelta(minutes=10)).astimezone(timezone.utc).isoformat(
|
|
22
|
-
"T"
|
|
23
|
-
)[:-9] + "Z"
|
|
17
|
+
self.created = datetime.now(tz=timezone.utc)
|
|
18
|
+
self.expires = self.created + timedelta(minutes=30)
|
|
24
19
|
self.signInPage = "_forms/default.aspx?wa=wsignin1.0"
|
|
25
20
|
|
|
21
|
+
def reset(self):
|
|
22
|
+
"""Renew the expiration time."""
|
|
23
|
+
self.created = datetime.now(tz=timezone.utc)
|
|
24
|
+
self.expires = self.created + timedelta(minutes=30)
|
|
25
|
+
|
|
26
26
|
@property
|
|
27
27
|
def tenant(self):
|
|
28
28
|
return urlparse(self.authorityUrl).netloc
|
|
@@ -9,6 +9,10 @@ class TokenResponse(object):
|
|
|
9
9
|
def is_valid(self):
|
|
10
10
|
return self.accessToken is not None and self.tokenType == "Bearer"
|
|
11
11
|
|
|
12
|
+
@property
|
|
13
|
+
def authorization_header(self):
|
|
14
|
+
return "Bearer {0}".format(self.accessToken)
|
|
15
|
+
|
|
12
16
|
@staticmethod
|
|
13
17
|
def from_json(value):
|
|
14
18
|
error = value.get("error", None)
|
|
File without changes
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
from office365.runtime.client_result import ClientResult
|
|
4
|
+
from office365.runtime.client_value import ClientValue
|
|
5
|
+
from office365.runtime.paths.service_operation import ServiceOperationPath
|
|
6
|
+
from office365.runtime.queries.service_operation import ServiceOperationQuery
|
|
7
|
+
from office365.sharepoint.entity import Entity
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from office365.sharepoint.client_context import ClientContext
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SystemSiteLockExpirationResult(ClientValue):
|
|
14
|
+
""""""
|
|
15
|
+
|
|
16
|
+
def __init__(self, error=None, expiration=None):
|
|
17
|
+
self.Error = error
|
|
18
|
+
self.Expiration = expiration
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SiteMoveService(Entity):
|
|
22
|
+
""" """
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
context,
|
|
27
|
+
site_id,
|
|
28
|
+
site_subscription_id=None,
|
|
29
|
+
source_database_id=None,
|
|
30
|
+
target_database_id=None,
|
|
31
|
+
):
|
|
32
|
+
# type: (ClientContext, str, str, str, str) -> None
|
|
33
|
+
""""""
|
|
34
|
+
static_path = ServiceOperationPath(
|
|
35
|
+
"Microsoft.SharePoint.Administration.SiteMove.Service.SiteMoveService",
|
|
36
|
+
{
|
|
37
|
+
"siteId": site_id,
|
|
38
|
+
"siteSubscriptionId": site_subscription_id,
|
|
39
|
+
"sourceDatabaseId": source_database_id,
|
|
40
|
+
"targetDatabaseId": target_database_id,
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
super(SiteMoveService, self).__init__(context, static_path)
|
|
44
|
+
|
|
45
|
+
def acquire_system_site_lock(
|
|
46
|
+
self, lock_requestor, lock_type, lease_duration_in_minutes
|
|
47
|
+
):
|
|
48
|
+
""""""
|
|
49
|
+
return_type = ClientResult(self.context, SystemSiteLockExpirationResult())
|
|
50
|
+
payload = {
|
|
51
|
+
"lockRequestor": lock_requestor,
|
|
52
|
+
"lockType": lock_type,
|
|
53
|
+
"leaseDurationInMinutes": lease_duration_in_minutes,
|
|
54
|
+
}
|
|
55
|
+
qry = ServiceOperationQuery(
|
|
56
|
+
self,
|
|
57
|
+
"AcquireSystemSiteLock",
|
|
58
|
+
None,
|
|
59
|
+
payload,
|
|
60
|
+
None,
|
|
61
|
+
return_type,
|
|
62
|
+
)
|
|
63
|
+
self.context.add_query(qry)
|
|
64
|
+
return return_type
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def entity_type_name(self):
|
|
68
|
+
return "Microsoft.SharePoint.Administration.SiteMove.Service.SiteMoveService"
|
|
@@ -20,6 +20,21 @@ class ChangeItem(Change):
|
|
|
20
20
|
"""Specifies an identifier for the content type"""
|
|
21
21
|
return self.properties.get("ContentTypeId", ContentTypeId())
|
|
22
22
|
|
|
23
|
+
@property
|
|
24
|
+
def editor(self):
|
|
25
|
+
"""Specifies the editor of the changed item."""
|
|
26
|
+
return self.properties.get("Editor", None)
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def editor_email_hint(self):
|
|
30
|
+
"""Returns the email corresponding to Editor."""
|
|
31
|
+
return self.properties.get("EditorEmailHint", None)
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def editor_login_name(self):
|
|
35
|
+
"""Returns login name of the Editor."""
|
|
36
|
+
return self.properties.get("EditorLoginName", None)
|
|
37
|
+
|
|
23
38
|
@property
|
|
24
39
|
def file_type(self):
|
|
25
40
|
# type: () -> Optional[str]
|