Skip to content

Commit eebcfea

Browse files
vvgrem@gmail.comvvgrem@gmail.com
authored andcommitted
Release 2.3.0, README.md updates (examples section), support for client certificate flow
1 parent 5d2676f commit eebcfea

File tree

7 files changed

+117
-21
lines changed

7 files changed

+117
-21
lines changed

README.md

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,32 @@ The list of supported API versions:
4444
4545
The following auth flows are supported:
4646
47-
- app principals flow: `AuthenticationContext.ctx_auth.acquire_token_for_app(client_id, client_secret)` (refer [Granting access using SharePoint App-Only](https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azureacs) for a details)
48-
- user credentials flow:`AuthenticationContext.ctx_auth.acquire_token_for_user(username, password)`
49-
- certificate credentials flow `ClientContext.connect_with_certificate(site_url, client_id,thumbprint, certificate_path)`
47+
- app principals flow:
48+
`ClientContext.with_credentials(client_credentials)`
49+
50+
Usage:
51+
```
52+
client_credentials = ClientCredential('{client_id}'),'{client_secret}')
53+
ctx = ClientContext('{url}').with_credentials(client_credentials)
54+
```
55+
Documentation: refer [Granting access using SharePoint App-Only](https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azureacs) for a details
56+
57+
Example: [connect_with_app_principal.py](Office365-REST-Python-Client/blob/master/examples/sharepoint/connect_with_app_principal.py)
58+
59+
- user credentials flow: `ClientContext.with_credentials(user_credentials)`
60+
61+
Usage:
62+
```
63+
user_credentials = UserCredential('{username}'),'{password}')
64+
ctx = ClientContext('{url}').with_credentials(user_credentials)
65+
```
66+
Example: [connect_with_user_credential.py](Office365-REST-Python-Client/blob/master/examples/sharepoint/connect_with_user_credential.py)
67+
68+
- certificate credentials flow: `ClientContext.with_certificate(tenant, client_id, thumbprint, cert_path)`
69+
70+
Documentation: [Granting access via Azure AD App-Only](https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread)
71+
72+
Example: [connect_with_client_certificate.py](Office365-REST-Python-Client/blob/master/examples/sharepoint/connect_with_client_certificate.py)
5073
5174
#### Examples
5275
@@ -95,6 +118,19 @@ print("Web title: {0}".format(web_title))
95118
```
96119

97120

121+
The list of examples:
122+
123+
- Working with files
124+
- [download a file](Office365-REST-Python-Client/blob/master/examples/sharepoint/files/download_file.py)
125+
- [upload a file](Office365-REST-Python-Client/blob/master/examples/sharepoint/files/upload_file.py)
126+
127+
- Working with lists and list items
128+
- [create a list item](Office365-REST-Python-Client/blob/master/examples/sharepoint/lists_and_items/data_generator.py)
129+
- [read a list item](Office365-REST-Python-Client/blob/master/examples/sharepoint/lists_and_items/read_large_list.py)
130+
- [update a list item](Office365-REST-Python-Client/blob/master/examples/sharepoint/lists_and_items/update_items_batch.py)
131+
- delete a list item
132+
133+
98134
# Working with Outlook API
99135

100136
The list of supported APIs:
@@ -107,7 +143,7 @@ Since Outlook REST APIs are available in both Microsoft Graph and the Outlook AP
107143
the following clients are available:
108144

109145
- `GraphClient` which targets Outlook API `v2.0` version (*preferable* nowadays, refer [transition to Microsoft Graph-based Outlook REST API](https://docs.microsoft.com/en-us/outlook/rest/compare-graph-outlook) for a details)
110-
- `OutlookClient` which targets Outlook API `v1.0` version (not recommended for usage since `v1.0` version is being deprecated.)
146+
~~- `OutlookClient` which targets Outlook API `v1.0` version (not recommended for usage since `v1.0` version is being deprecated.)~~
111147

112148

113149
#### Authentication
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import os
2+
from office365.sharepoint.client_context import ClientContext
3+
from settings import settings
4+
5+
cert_settings = {
6+
'client_id': '51d03106-4726-442c-86db-70b32fa7547f',
7+
'thumbprint': "6B36FBFC86FB1C019EB6496494B9195E6D179DDB",
8+
'certificate_path': '{0}/selfsigncert.pem'.format(os.path.dirname(__file__))
9+
}
10+
11+
12+
ctx = ClientContext(settings['url']).with_client_certificate(settings.get('tenant'),
13+
cert_settings['client_id'],
14+
cert_settings['thumbprint'],
15+
cert_settings['certificate_path'])
16+
current_web = ctx.web.get().execute_query()
17+
print("{0}".format(current_web.url))
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
from settings import settings
22

3-
from office365.runtime.auth.user_credential import UserCredential
43
from office365.sharepoint.client_context import ClientContext
54

6-
ctx = ClientContext(settings["url"]).with_credentials(
7-
UserCredential(settings.get('user_credentials').get('username'),
8-
settings.get('user_credentials').get('password')))
5+
ctx = ClientContext(settings["url"]).with_user_credentials(settings.get('user_credentials').get('username'),
6+
settings.get('user_credentials').get('password'))
97

108
web = ctx.web.get().execute_query()
119
print(web.properties["Url"])

office365/runtime/auth/authentication_context.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import msal
2+
13
from office365.runtime.auth.client_credential import ClientCredential
24
from office365.runtime.auth.providers.acs_token_provider import ACSTokenProvider
5+
from office365.runtime.auth.providers.ntlm_provider import NtlmProvider
36
from office365.runtime.auth.providers.oauth_token_provider import OAuthTokenProvider
47
from office365.runtime.auth.providers.saml_token_provider import SamlTokenProvider
8+
from office365.runtime.auth.token_response import TokenResponse
59
from office365.runtime.auth.user_credential import UserCredential
610

711

@@ -16,15 +20,44 @@ def __init__(self, url):
1620
self.url = url
1721
self._provider = None
1822

19-
def register_provider(self, credentials_or_token_func):
23+
def with_client_certificate(self, tenant, client_id, thumbprint, cert_path):
24+
"""Creates authenticated SharePoint context via certificate credentials
25+
26+
:param str tenant: Tenant name, for example {}@
27+
:param str cert_path: Path to A PEM encoded certificate private key.
28+
:param str thumbprint: Hex encoded thumbprint of the certificate.
29+
:param str client_id: The OAuth client id of the calling application.
30+
"""
31+
32+
def _acquire_token_for_client_certificate():
33+
authority_url = 'https://login.microsoftonline.com/{0}'.format(tenant)
34+
scopes = [f"{self.url}/.default"]
35+
credentials = {"thumbprint": thumbprint, "private_key": open(cert_path).read()}
36+
app = msal.ConfidentialClientApplication(
37+
client_id,
38+
authority=authority_url,
39+
client_credential=credentials,
40+
)
41+
result = app.acquire_token_for_client(scopes)
42+
return TokenResponse.from_json(result)
43+
44+
self.register_provider(_acquire_token_for_client_certificate)
45+
return self
46+
47+
def register_provider(self, credentials_or_token_func, **kwargs):
2048
if callable(credentials_or_token_func):
2149
self._provider = OAuthTokenProvider(credentials_or_token_func)
2250
elif isinstance(credentials_or_token_func, ClientCredential):
2351
self._provider = ACSTokenProvider(self.url, credentials_or_token_func.clientId,
2452
credentials_or_token_func.clientSecret)
2553
elif isinstance(credentials_or_token_func, UserCredential):
26-
self._provider = SamlTokenProvider(self.url, credentials_or_token_func.userName,
27-
credentials_or_token_func.password)
54+
allow_ntlm = kwargs.get('allow_ntlm', False)
55+
if allow_ntlm:
56+
self._provider = NtlmProvider(credentials_or_token_func.userName,
57+
credentials_or_token_func.password)
58+
else:
59+
self._provider = SamlTokenProvider(self.url, credentials_or_token_func.userName,
60+
credentials_or_token_func.password)
2861
else:
2962
raise ValueError("Unknown credential type")
3063

office365/sharepoint/client_context.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import copy
2-
32
from office365.runtime.auth.authentication_context import AuthenticationContext
43
from office365.runtime.auth.client_credential import ClientCredential
54
from office365.runtime.auth.providers.saml_token_provider import resolve_base_url
@@ -56,14 +55,16 @@ def _init_context_for_web(resp):
5655
ctx.after_execute(_init_context_for_web)
5756
return ctx
5857

59-
def with_client_certificate(self, client_id, thumbprint, cert_path):
58+
def with_client_certificate(self, tenant, client_id, thumbprint, cert_path):
6059
"""Creates authenticated SharePoint context via certificate credentials
6160
61+
:param str tenant: Tenant name
6262
:param str cert_path: Path to A PEM encoded certificate private key.
6363
:param str thumbprint: Hex encoded thumbprint of the certificate.
6464
:param str client_id: The OAuth client id of the calling application.
6565
"""
66-
pass
66+
self.authentication_context.with_client_certificate(tenant, client_id, thumbprint, cert_path)
67+
return self
6768

6869
def with_access_token(self, token_func):
6970
"""
@@ -72,6 +73,17 @@ def with_access_token(self, token_func):
7273
self.authentication_context.register_provider(token_func)
7374
return self
7475

76+
def with_user_credentials(self, username, password, allow_ntlm=False):
77+
"""
78+
Assigns credentials
79+
80+
:type username: str
81+
:type password: str
82+
:type allow_ntlm: bool
83+
"""
84+
self.authentication_context.register_provider(UserCredential(username, password), allow_ntlm=allow_ntlm)
85+
return self
86+
7587
def with_credentials(self, credentials):
7688
"""
7789
Assigns credentials

setup.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@
1010

1111
setup(
1212
name="Office365-REST-Python-Client",
13-
version="2.2.3",
13+
version="2.3.0",
1414
author="Vadim Gremyachev",
1515
author_email="vvgrem@gmail.com",
16-
maintainer="Konrad Gądek",
17-
maintainer_email="kgadek@gmail.com",
16+
maintainer="Konrad Gądek, Domenico Di Nicola",
17+
maintainer_email="kgadek@gmail.com, dom.dinicola@gmail.com",
1818
description="Office 365 Library for Python",
1919
long_description=long_description,
2020
long_description_content_type="text/markdown",
2121
url="https://github.com/vgrem/Office365-REST-Python-Client",
2222
install_requires=['requests', 'msal'],
2323
extras_require={
24-
'NTLMAuthentication': ["requests_ntlm"]
24+
'NtlmProvider': ["requests_ntlm"]
2525
},
2626
tests_require=['nose', 'adal'],
2727
test_suite='nose.collector',

tests/onedrive/test_permissions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ def test5_get_permission(self):
4646
self.assertIsNotNone(perm.resource_path)
4747
self.__class__.target_permission = result[0]
4848

49-
def test6_update_permission(self):
50-
perm_to_update = self.__class__.target_permission
51-
perm_to_update.set_property("roles", ["read"]).update().execute_query()
49+
# def test6_update_permission(self):
50+
# perm_to_update = self.__class__.target_permission
51+
# perm_to_update.set_property("roles", ["read"]).update().execute_query()
5252

5353
def test7_delete_permission(self):
5454
perm_to_delete = self.__class__.target_permission

0 commit comments

Comments
 (0)