Skip to content

Commit 0885ff8

Browse files
committed
#836 ClientContext.with_client_certificate support for Passphrase if the private_key is encrypted
1 parent 2ed6c44 commit 0885ff8

19 files changed

+83
-21
lines changed

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ Steps to access:
7575
- [Granting access using SharePoint App-Only](https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azureacs)
7676
- [wiki](https://github.com/vgrem/Office365-REST-Python-Client/wiki/How-to-connect-to-SharePoint-Online-and-and-SharePoint-2013-2016-2019-on-premises--with-app-principal)
7777
78-
Example: [connect_with_app_principal.py](examples/sharepoint/connect_with_app_only_principal.py)
78+
Example: [connect_with_app_principal.py](examples/sharepoint/auth_app_only.py)
7979
8080
#### 2. Using username and password
8181
@@ -85,15 +85,15 @@ Steps to access:
8585
ctx = ClientContext('{url}').with_credentials(user_credentials)
8686
```
8787
88-
Example: [connect_with_user_credential.py](examples/sharepoint/connect_with_user_credential.py)
88+
Example: [connect_with_user_credential.py](examples/sharepoint/auth_user_credential.py)
8989
9090
#### 3. Using an Azure AD application (certificate credentials flow)
9191
9292
Documentation:
9393
- [Granting access via Azure AD App-Only](https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread)
9494
- [wiki](https://github.com/vgrem/Office365-REST-Python-Client/wiki/How-to-connect-to-SharePoint-Online-with-certificate-credentials)
9595
96-
Example: [connect_with_client_certificate.py](examples/sharepoint/connect_with_client_certificate.py)
96+
Example: [connect_with_client_certificate.py](examples/sharepoint/auth_client_certificate.py)
9797
9898
#### 4. Interactive
9999
@@ -104,7 +104,7 @@ Steps to access:
104104
> In Azure Portal, configure the Redirect URI of your
105105
"Mobile and Desktop application" as ``http://localhost``.
106106
107-
Example: [connect_interactive.py](examples/sharepoint/connect_interactive.py)
107+
Example: [connect_interactive.py](examples/sharepoint/auth_interactive.py)
108108
109109
Usage:
110110
```python

examples/communications/create_call.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
Create peer-to-peer VoIP call with service hosted media
33
"""
44
from office365.graph_client import GraphClient
5-
from tests.graph_case import acquire_token_by_client_credentials
5+
from tests import test_client_id, test_client_secret, test_tenant
66

7-
client = GraphClient(acquire_token_by_client_credentials)
7+
client = GraphClient.with_client_secret(test_tenant, test_client_id, test_client_secret)
88
call = client.communications.calls.create(
99
"https://mediadev8.com/teamsapp/api/calling"
1010
).execute_query()

examples/outlook/messages/download_with_attachments.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88
import tempfile
99

1010
from office365.graph_client import GraphClient
11-
from tests import test_user_principal_name
12-
from tests.graph_case import acquire_token_by_client_credentials
11+
from tests import (
12+
test_client_id,
13+
test_client_secret,
14+
test_tenant,
15+
test_user_principal_name,
16+
)
1317

14-
client = GraphClient(acquire_token_by_client_credentials)
18+
client = GraphClient.with_client_secret(test_tenant, test_client_id, test_client_secret)
1519
user = client.users[test_user_principal_name]
1620
messages = (
1721
user.messages.filter("hasAttachments eq true")

examples/sharepoint/connect_with_client_certificate.py renamed to examples/sharepoint/auth_client_certificate.py

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
test_client_id,
2121
test_site_url,
2222
test_tenant,
23-
test_tenant_name,
2423
)
2524

2625
cert_credentials = {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
When using SharePoint Online you can define applications in Azure AD and these applications can
3+
be granted permissions to SharePoint, but also to all the other services in Office 365.
4+
This model is the preferred model in case you're using SharePoint Online, if you're using SharePoint on-premises
5+
you have to use the SharePoint Only model via based Azure ACS as described in here:
6+
7+
Demonstrates how to use Azure AD App-Only auth flow
8+
9+
https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread
10+
11+
Refer wiki for a more details:
12+
https://github.com/vgrem/Office365-REST-Python-Client/wiki/How-to-connect-to-SharePoint-Online-with-certificate-credentials
13+
14+
To create a self signed certificate with encrypted private key run:
15+
openssl req -x509 -newkey rsa:2048 -keyout selfsignkey.pem -out selfsigncert.pem -days 365
16+
"""
17+
18+
import os
19+
20+
from office365.sharepoint.client_context import ClientContext
21+
from tests import (
22+
test_cert_thumbprint,
23+
test_client_id,
24+
test_site_url,
25+
test_tenant,
26+
)
27+
28+
cert_credentials = {
29+
"tenant": test_tenant,
30+
"client_id": test_client_id,
31+
"thumbprint": test_cert_thumbprint,
32+
"cert_path": "{0}/../selfsignkeyenc.pem".format(os.path.dirname(__file__)),
33+
"passphrase": "Password",
34+
}
35+
ctx = ClientContext(test_site_url).with_client_certificate(**cert_credentials)
36+
current_web = ctx.web.get().execute_query()
37+
print("{0}".format(current_web.url))
+10-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
"""
22
Demonstrates how to create a site field of type Taxonomy
33
"""
4+
import sys
45

56
from office365.sharepoint.client_context import ClientContext
67
from tests import create_unique_name, test_client_credentials, test_team_site_url
78

89
client = ClientContext(test_team_site_url).with_credentials(test_client_credentials)
910

10-
# term_sets = client.taxonomy.term_store.get_term_sets_by_name("Sweden").execute_query()
11+
term_set_id = "3b712032-95c4-4bb5-952d-f85ae9288f99"
12+
# term_sets = client.taxonomy.term_store.get_term_sets_by_name("Countries").execute_query()
13+
# if len(term_sets) == 0:
14+
# sys.exit("No term sets found")
1115

12-
# field_name = create_unique_name("TaxColumn")
13-
# field = client.web.fields.create_taxonomy_field(field_name).execute_query()
14-
# print("Field {0} has been created".format(field.internal_name))
15-
# field.delete_object().execute_query() # clean up
16+
field_name = create_unique_name(create_unique_name("Country"))
17+
field = client.web.fields.create_taxonomy_field(field_name, term_set_id).execute_query()
18+
print("Field {0} has been created".format(field.internal_name))
19+
20+
field.delete_object().execute_query() # clean up

examples/sharepoint/print_version.py

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"""
2+
Prints metadata about the site
3+
"""
14
from office365.sharepoint.client_context import ClientContext
25
from office365.sharepoint.webs.web import Web
36
from tests import test_client_credentials, test_site_url

examples/sharepoint/read_resource_no_model.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
"""
2+
Demonstrates how to construct and submit requests without model involved
3+
"""
4+
15
import json
26

37
from office365.sharepoint.client_context import ClientContext
48
from tests import test_site_url, test_user_credentials
59

610
if __name__ == "__main__":
7-
"""Demonstrates how to construct and submit requests without model involved"""
8-
911
client = ClientContext(test_site_url).with_credentials(test_user_credentials)
1012
response = client.execute_request_direct("web")
1113
response.raise_for_status()

office365/runtime/auth/authentication_context.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def with_client_certificate(
4747
cert_path=None,
4848
private_key=None,
4949
scopes=None,
50+
passphrase=None,
5051
):
5152
"""Initializes a client to acquire a token via certificate credentials
5253
@@ -56,6 +57,7 @@ def with_client_certificate(
5657
:param str or None cert_path: Path to A PEM encoded certificate private key.
5758
:param str or None private_key: A PEM encoded certificate private key.
5859
:param list[str] or None scopes: Scopes requested to access a protected API (a resource)
60+
:param str passphrase: Passphrase if the private_key is encrypted
5961
"""
6062
if scopes is None:
6163
resource = get_absolute_url(self.url)
@@ -70,7 +72,11 @@ def with_client_certificate(
7072

7173
def _acquire_token():
7274
authority_url = "https://login.microsoftonline.com/{0}".format(tenant)
73-
credentials = {"thumbprint": thumbprint, "private_key": private_key}
75+
credentials = {
76+
"thumbprint": thumbprint,
77+
"private_key": private_key,
78+
"passphrase": passphrase,
79+
}
7480
import msal
7581

7682
app = msal.ConfidentialClientApplication(
@@ -187,7 +193,11 @@ def with_credentials(self, credentials, **kwargs):
187193
browser_mode = kwargs.get("browser_mode", False)
188194
environment = kwargs.get("environment")
189195
provider = SamlTokenProvider(
190-
self.url, credentials.userName, credentials.password, browser_mode, environment
196+
self.url,
197+
credentials.userName,
198+
credentials.password,
199+
browser_mode,
200+
environment,
191201
)
192202
else:
193203
raise ValueError("Unknown credential type")

office365/sharepoint/client_context.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,9 @@ def with_client_certificate(
8282
cert_path=None,
8383
private_key=None,
8484
scopes=None,
85+
passphrase=None,
8586
):
86-
# type: (str, str, str, Optional[str], Optional[str], Optional[List[str]]) -> Self
87+
# type: (str, str, str, Optional[str], Optional[str], Optional[List[str]], Optional[str]) -> Self
8788
"""
8889
Creates authenticated SharePoint context via certificate credentials
8990
@@ -93,9 +94,10 @@ def with_client_certificate(
9394
:param str thumbprint: Hex encoded thumbprint of the certificate.
9495
:param str client_id: The OAuth client id of the calling application.
9596
:param list[str] or None scopes: Scopes requested to access a protected API (a resource)
97+
:param str passphrase: Passphrase if the private_key is encrypted
9698
"""
9799
self.authentication_context.with_client_certificate(
98-
tenant, client_id, thumbprint, cert_path, private_key, scopes
100+
tenant, client_id, thumbprint, cert_path, private_key, scopes, passphrase
99101
)
100102
return self
101103

0 commit comments

Comments
 (0)