Skip to content

Commit

Permalink
Merge pull request #794 from DEADSCOP/master
Browse files Browse the repository at this point in the history
Full SharePoint authentication support with GCC High Environments
  • Loading branch information
vgrem authored Dec 7, 2023
2 parents 41fb3a8 + 185ba12 commit 789da26
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 19 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ pip install Office365-REST-Python-Client

### Note
>
>Alternatively the _latest_ version could be directly installed via GitHub:
>```
>pip install git+https://github.com/vgrem/Office365-REST-Python-Client.git
Expand Down Expand Up @@ -175,6 +174,20 @@ The list of examples:

Refer [examples section](examples/sharepoint) for another scenarios

### Support for non-standard SharePoint Online Environments

Support for non-standard SharePoint Environments is currently being implemented. Currently supported:
- GCC High

To enable authentication to GCC High endpoints, add the `environment='GCCH'` parameter when calling the
`ClientContext class` with `.with_user_credentials`, `.with_client_credentials`, or `.with_credentials`

Example:
```python
client_credentials = ClientCredential('{client_id}','{client_secret}')
ctx = ClientContext('{url}').with_credentials(client_credentials, environment='GCCH')
```

# Working with Outlook API

The list of supported APIs:
Expand Down
3 changes: 2 additions & 1 deletion office365/runtime/auth/authentication_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,9 @@ def with_credentials(self, credentials, **kwargs):
:param UserCredential or ClientCredential credentials:
"""
if isinstance(credentials, ClientCredential):
environment = kwargs.get("environment")
provider = ACSTokenProvider(
self.url, credentials.clientId, credentials.clientSecret
self.url, credentials.clientId, credentials.clientSecret, environment
)
elif isinstance(credentials, UserCredential):
allow_ntlm = kwargs.get("allow_ntlm", False)
Expand Down
20 changes: 14 additions & 6 deletions office365/runtime/auth/providers/acs_token_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@


class ACSTokenProvider(AuthenticationProvider, office365.logger.LoggerContext):
def __init__(self, url, client_id, client_secret):
def __init__(self, url, client_id, client_secret, environment='commercial'):
"""
Provider to acquire the access token from a Microsoft Azure Access Control Service (ACS)
:param str client_id: The OAuth client id of the calling application.
:param str client_secret: Secret string that the application uses to prove its identity when requesting a token
:param str url: SharePoint web or site url
:param str environment: The Office 365 Cloud Environment endpoint used for authentication
defaults to 'commercial'.
"""
self.url = url
self.redirect_url = None
Expand All @@ -25,6 +27,7 @@ def __init__(self, url, client_id, client_secret):
self._client_id = client_id
self._client_secret = client_secret
self._cached_token = None
self._environment = environment

def authenticate_request(self, request):
# type: (RequestOptions) -> None
Expand Down Expand Up @@ -62,7 +65,7 @@ def _get_app_only_access_token(self, target_host, target_realm):
self.SharePointPrincipal, target_host, target_realm
)
principal_id = self.get_formatted_principal(self._client_id, None, target_realm)
sts_url = self.get_security_token_service_url(target_realm)
sts_url = self.get_security_token_service_url(target_realm, environment=self._environment)
oauth2_request = {
"grant_type": "client_credentials",
"client_id": principal_id,
Expand Down Expand Up @@ -101,10 +104,15 @@ def get_formatted_principal(principal_name, host_name, realm):
return "{0}@{1}".format(principal_name, realm)

@staticmethod
def get_security_token_service_url(realm):
return "https://accounts.accesscontrol.windows.net/{0}/tokens/OAuth/2".format(
realm
)
def get_security_token_service_url(realm, environment):
if environment == "GCCH":
return "https://login.microsoftonline.us/{0}/tokens/OAuth/2".format(
realm
)
else:
return "https://accounts.accesscontrol.windows.net/{0}/tokens/OAuth/2".format(
realm
)

def _get_authorization_header(self):
return "Bearer {0}".format(self._cached_token.accessToken)
Expand Down
26 changes: 15 additions & 11 deletions office365/sharepoint/client_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def with_client_certificate(
thumbprint,
cert_path=None,
private_key=None,
scopes=None,
scopes=None
):
# type: (str, str, str, Optional[str], Optional[str], Optional[List[str]]) -> Self
"""
Expand All @@ -93,7 +93,6 @@ def with_client_certificate(
:param str thumbprint: Hex encoded thumbprint of the certificate.
:param str client_id: The OAuth client id of the calling application.
:param list[str] or None scopes: Scopes requested to access a protected API (a resource)
"""
self.authentication_context.with_client_certificate(
tenant, client_id, thumbprint, cert_path, private_key, scopes
Expand Down Expand Up @@ -139,15 +138,15 @@ def with_access_token(self, token_func):
def with_user_credentials(
self, username, password, allow_ntlm=False, browser_mode=False, environment='commercial'
):
# type: (str, str, bool, bool, str) -> Self
# type: (str, str, bool, bool, Optional[str]) -> Self
"""
Initializes a client to acquire a token via user credentials.
:param str username: Typically, a UPN in the form of an email address
:param str password: The password
:param bool allow_ntlm: Flag indicates whether NTLM scheme is enabled. Disabled by default
:param bool browser_mode:
:param str environment: The Office 365 Cloud Environment endpoint used for authentication.
By default, this will be set to commercial ('commercial', 'GCCH')
:param str environment: The Office 365 Cloud Environment endpoint used for authentication
defaults to 'commercial'.
"""
self.authentication_context.with_credentials(
UserCredential(username, password),
Expand All @@ -157,8 +156,8 @@ def with_user_credentials(
)
return self

def with_client_credentials(self, client_id, client_secret):
# type: (str, str) -> Self
def with_client_credentials(self, client_id, client_secret, environment='commercial'):
# type: (str, str, Optional[str]) -> Self
"""
Initializes a client to acquire a token via client credentials (SharePoint App-Only)
Expand All @@ -167,19 +166,24 @@ def with_client_credentials(self, client_id, client_secret):
:param str client_id: The OAuth client id of the calling application
:param str client_secret: Secret string that the application uses to prove its identity when requesting a token
:param str environment: The Office 365 Cloud Environment endpoint used for authentication
defaults to 'commercial'.
"""
self.authentication_context.with_credentials(
ClientCredential(client_id, client_secret)
ClientCredential(client_id, client_secret),
environment=environment
)
return self

def with_credentials(self, credentials):
# type: (UserCredential|ClientCredential) -> Self
def with_credentials(self, credentials, environment='commercial'):
# type: (UserCredential|ClientCredential, Optional[str]) -> Self
"""
Initializes a client to acquire a token via user or client credentials
:type credentials: UserCredential or ClientCredential
:param str environment: The Office 365 Cloud Environment endpoint used for authentication
defaults to 'commercial'.
"""
self.authentication_context.with_credentials(credentials)
self.authentication_context.with_credentials(credentials, environment=environment)
return self

def execute_batch(self, items_per_batch=100, success_callback=None):
Expand Down

0 comments on commit 789da26

Please sign in to comment.