Skip to content

Commit 1a60ae0

Browse files
Added the Azure.MixedReality.Authentication library (#16714)
This change adds an authentication library for Mixed Reality services, which all currently utilize a custom STS for authentication. Upcoming Mixed Reality client libraries will depend on this library to perform authentication using identities from Azure.Identity. See the added README.md for more information about the library. [ApiView link](https://apiview.dev/Assemblies/Review/986545855b9c499faeff72b25115ab96)
1 parent a286861 commit 1a60ae0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+2411
-0
lines changed

eng/.docsettings.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ known_content_issues:
124124
- ['sdk/core/azure-mgmt-nspkg/README.rst', 'nspkg and common']
125125
- ['sdk/core/azure-nspkg/README.rst', 'nspkg and common']
126126
- ['sdk/keyvault/azure-keyvault-nspkg/README.md', 'nspkg and common']
127+
- ['sdk/mixedreality/azure-mixedreality-nspkg/README.md', 'nspkg and common']
127128
- ['sdk/search/azure-search-nspkg/README.md', 'nspkg and common']
128129
- ['sdk/storage/azure-storage-blob/samples/README.md', 'nspkg and common']
129130
- ['sdk/storage/azure-storage-file-datalake/samples/README.md', 'nspkg and common']
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Release History
2+
3+
## 1.0.0b1 (Unreleased)
4+
5+
- Initial release.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 Microsoft
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
include *.md
2+
include azure/__init__.py
3+
include azure/mixedreality/__init__.py
4+
include LICENSE.txt
5+
recursive-include tests *.py
6+
recursive-include samples *.py *.md
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
[![Build Status](https://dev.azure.com/azure-sdk/public/_apis/build/status/azure-sdk-for-python.client?branchName=master)](https://dev.azure.com/azure-sdk/public/_build/latest?definitionId=46?branchName=master)
2+
3+
# Azure Mixed Reality Authentication Package client library for Python
4+
5+
Mixed Reality services, like Azure Spatial Anchors, Azure Remote Rendering, and others, use the Mixed Reality security
6+
token service (STS) for authentication. This package supports exchanging Mixed Reality account credentials for an access
7+
token from the STS that can be used to access Mixed Reality services.
8+
9+
![Mixed Reality service authentication diagram](https://docs.microsoft.com/azure/spatial-anchors/concepts/media/spatial-anchors-authentication-overview.png)
10+
11+
# Getting started
12+
13+
## Currently supported environments
14+
15+
This package has been tested with Python 2.7, 3.5, 3.6, 3.7, 3.8, and 3.9.
16+
17+
## Prerequisites
18+
19+
- An [Azure subscription][azure_sub].
20+
- You must have an account with an [Azure Mixed Reality service](https://azure.microsoft.com/topic/mixed-reality/):
21+
- [Azure Remote Rendering](https://docs.microsoft.com/azure/remote-rendering/)
22+
- [Azure Spatial Anchors](https://docs.microsoft.com/azure/spatial-anchors/)
23+
- Familiarity with the authentication and credential concepts from the [Azure Identity library][azure_identity].
24+
- Python 2.7, or 3.5 or later is required to use this package.
25+
26+
## Install the package
27+
28+
Install the Azure Mixed Reality Authentication SDK.
29+
30+
```bash
31+
pip install --pre azure-mixedreality-authentication
32+
```
33+
34+
## Create and authenticate a `MixedRealityStsClient`
35+
36+
To create a client object to request an access token for a Mixed Reality service, you will need the `account identifier`
37+
and `account domain` of your Mixed Reality service resource and a `credential`.
38+
39+
Mixed Reality services support a few different forms of authentication:
40+
41+
- Account Key authentication
42+
- Account keys enable you to get started quickly with using Mixed Reality services. But before you deploy your application
43+
to production, we recommend that you update your app to use Azure AD authentication.
44+
- Azure Active Directory (AD) token authentication
45+
- If you're building an enterprise application and your company is using Azure AD as its identity system, you can use
46+
user-based Azure AD authentication in your app. You then grant access to your Mixed Reality accounts by using your
47+
existing Azure AD security groups. You can also grant access directly to users in your organization.
48+
- Otherwise, we recommend that you obtain Azure AD tokens from a web service that supports your app. We recommend this
49+
method for production applications because it allows you to avoid embedding the credentials for access to a Mixed
50+
Reality service in your client application.
51+
52+
See [here][register_aad_app] for detailed instructions and information.
53+
54+
### Using account key authentication
55+
56+
Use the [Azure Portal][azure_portal] to browse to your Mixed Reality service resource and retrieve an `account key`.
57+
58+
Once you have an account key, you can use the `AzureKeyCredential` class to authenticate the client as follows:
59+
60+
```python
61+
from azure.core.credentials import AzureKeyCredential
62+
from azure.mixedreality.authentication import MixedRealityStsClient
63+
64+
account_id = "<ACCOUNTD ID>"
65+
account_domain = "<ACCOUNT_DOMAIN>"
66+
account_key = "<ACCOUNT_KEY>"
67+
key_credential = AzureKeyCredential(account_key)
68+
69+
client = MixedRealityStsClient(account_id, account_domain, key_credential)
70+
```
71+
72+
> Note: Account key authentication is **not recommended** for production applications.
73+
74+
### Using an Azure Active Directory Credential
75+
76+
Account key authentication is used in most of the examples, but you can also authenticate with Azure Active Directory
77+
using the [Azure Identity library][azure_identity]. This is the recommended method for production applications. To use
78+
the [DefaultAzureCredential][defaultazurecredential] provider shown below, or other credential providers provided with
79+
the Azure SDK, please install the `@azure/identity` package:
80+
81+
You will also need to [register a new AAD application][register_aad_app] and grant access to your Mixed Reality resource
82+
by assigning the appropriate role for your Mixed Reality service to your service principal.
83+
84+
```python
85+
from azure.identity import DefaultAzureCredential
86+
from azure.mixedreality.authentication import MixedRealityStsClient
87+
88+
account_id = "<ACCOUNTD ID>"
89+
account_domain = "<ACCOUNT_DOMAIN>"
90+
default_credential = DefaultAzureCredential()
91+
92+
client = MixedRealityStsClient(account_id, account_domain, default_credential)
93+
```
94+
95+
# Key concepts
96+
97+
## MixedRealityStsClient
98+
99+
The `MixedRealityStsClient` is the client library used to access the Mixed Reality STS to get an access token. An access
100+
token can be retrieved by calling `get_token()` on an `MixedRealityStsClient` instance.
101+
102+
Tokens obtained from the Mixed Reality STS have a lifetime of **24 hours**.
103+
104+
### Token result value
105+
106+
The return value for a successful call to `get_token` is an `azure.core.credentials.AccessToken`.
107+
108+
See the authentication examples [above](#authenticate-the-client) or [Azure Identity][azure_identity] for more complex
109+
authentication scenarios.
110+
111+
## Retrieve an access token synchronously
112+
113+
```python
114+
from azure.core.credentials import AzureKeyCredential
115+
from azure.mixedreality.authentication import MixedRealityStsClient
116+
117+
account_id = "<ACCOUNTD ID>"
118+
account_domain = "<ACCOUNT_DOMAIN>"
119+
account_key = "<ACCOUNT_KEY>"
120+
key_credential = AzureKeyCredential(account_key)
121+
122+
client = MixedRealityStsClient(account_id, account_domain, key_credential)
123+
124+
token = client.get_token()
125+
```
126+
127+
## Retrieve an access token asynchronously
128+
129+
```python
130+
from azure.core.credentials import AzureKeyCredential
131+
from azure.mixedreality.authentication.aio import MixedRealityStsClient
132+
133+
account_id = "<ACCOUNTD ID>"
134+
account_domain = "<ACCOUNT_DOMAIN>"
135+
account_key = "<ACCOUNT_KEY>"
136+
key_credential = AzureKeyCredential(account_key)
137+
138+
client = MixedRealityStsClient(account_id, account_domain, key_credential)
139+
140+
token = await client.get_token()
141+
```
142+
143+
# Examples
144+
145+
These are code samples that show common scenario operations with the Azure Mixed Reality Authentication client library.
146+
The async versions of the samples (the python sample files appended with `_async`) show asynchronous operations,
147+
and require Python 3.5 or later.
148+
Before running the sample code, refer to Prerequisites
149+
<!-- [Prerequisites](#Prerequisites) -->
150+
to create a resource, then set some Environment Variables
151+
152+
```bash
153+
set MIXEDREALITY_ACCOUNT_DOMAIN="<the Mixed Reality account domain>"
154+
set MIXEDREALITY_ACCOUNT_ID="<the Mixed Reality account identifier>"
155+
set MIXEDREALITY_ACCOUNT_KEY="<the Mixed Reality account primary or secondary key>"
156+
157+
pip install azure-mixedreality-authentication
158+
159+
python samples\client_sample.py
160+
python samples\client_sample_async.py
161+
```
162+
163+
# Troubleshooting
164+
165+
The [troubleshooting](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/identity/azure-identity#troubleshooting)
166+
section for Azure Identity can be helpful when troubleshooting authentication issues.
167+
168+
# Next steps
169+
170+
## Mixed Reality client libraries
171+
172+
- Coming soon
173+
174+
## Contributing
175+
176+
This project welcomes contributions and suggestions. Most contributions require you to agree to a
177+
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
178+
the rights to use your contribution. For details, visit https://cla.microsoft.com.
179+
180+
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
181+
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
182+
provided by the bot. You will only need to do this once across all repos using our CLA.
183+
184+
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
185+
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
186+
contact [[email protected]](mailto:[email protected]) with any additional questions or comments.
187+
188+
If you'd like to contribute to this library, please read the
189+
[contributing guide](https://github.com/Azure/azure-sdk-for-python/blob/master/CONTRIBUTING.md) to learn more about how to
190+
build and test the code.
191+
192+
![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-python%2Fsdk%2Ftemplate%2Fazure-template%2FREADME.png)
193+
194+
[azure_cli]: https://docs.microsoft.com/cli/azure
195+
[azure_sub]: https://azure.microsoft.com/free/
196+
[azure_portal]: https://portal.azure.com
197+
[azure_identity]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/identity/azure-identity
198+
[register_aad_app]: https://docs.microsoft.com/azure/spatial-anchors/concepts/authentication
199+
[defaultazurecredential]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/identity/azure-identity#defaultazurecredential
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# --------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for
4+
# license information.
5+
# --------------------------------------------------------------------------
6+
7+
__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# --------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for
4+
# license information.
5+
# --------------------------------------------------------------------------
6+
7+
__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# --------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for
4+
# license information.
5+
# --------------------------------------------------------------------------
6+
7+
from ._version import VERSION
8+
from ._client import MixedRealityStsClient
9+
10+
__version__ = VERSION
11+
__all__ = ['MixedRealityStsClient']
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# --------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for
4+
# license information.
5+
# --------------------------------------------------------------------------
6+
from typing import TYPE_CHECKING
7+
8+
try:
9+
from urllib.parse import urlparse
10+
except ImportError:
11+
from urlparse import urlparse # type: ignore
12+
13+
from azure.core.credentials import AzureKeyCredential
14+
from azure.core.tracing.decorator import distributed_trace
15+
from azure.core.pipeline.policies import BearerTokenCredentialPolicy
16+
17+
from ._generated import MixedRealityStsRestClient
18+
from ._generated.models import TokenRequestOptions
19+
from ._version import SDK_MONIKER
20+
from ._shared.authentication_endpoint import construct_endpoint_url
21+
from ._shared.mixedreality_account_key_credential import MixedRealityAccountKeyCredential
22+
from ._utils import convert_to_access_token, generate_cv_base
23+
24+
if TYPE_CHECKING:
25+
# pylint: disable=unused-import,ungrouped-imports
26+
from typing import Any, Union
27+
from azure.core.credentials import TokenCredential
28+
from azure.core.credentials import AccessToken
29+
30+
31+
class MixedRealityStsClient(object):
32+
""" A client to interact with the Mixed Reality STS service.
33+
34+
:param str account_id:
35+
The Mixed Reality service account identifier.
36+
:param str account_domain:
37+
The Mixed Reality service account domain.
38+
:param Union[TokenCredential, AzureKeyCredential] credential:
39+
The credential used to access the Mixed Reality service.
40+
:keyword str custom_endpoint_url:
41+
Override the Mixed Reality STS service endpoint.
42+
"""
43+
44+
def __init__(self, account_id, account_domain, credential, **kwargs):
45+
# type: (str, str, Union[TokenCredential, AzureKeyCredential], Any) -> None
46+
if not account_id:
47+
raise ValueError("account_id must be a non-empty string.")
48+
49+
if not account_domain:
50+
raise ValueError("account_domain must be a non-empty string.")
51+
52+
if not credential:
53+
raise ValueError("credential can not be None.")
54+
55+
self._account_id = account_id
56+
self._account_domain = account_domain
57+
58+
if isinstance(credential, AzureKeyCredential):
59+
credential = MixedRealityAccountKeyCredential(account_id, credential)
60+
61+
self._credential = credential
62+
63+
endpoint_url = kwargs.pop('custom_endpoint_url', construct_endpoint_url(account_domain))
64+
65+
try:
66+
if not endpoint_url.lower().startswith('http'):
67+
endpoint_url = "https://" + endpoint_url
68+
except AttributeError:
69+
raise ValueError("Host URL must be a string.")
70+
71+
parsed_url = urlparse(endpoint_url.rstrip('/'))
72+
if not parsed_url.netloc:
73+
raise ValueError("Invalid URL: {}".format(endpoint_url))
74+
75+
self._endpoint_url = endpoint_url
76+
77+
authentication_policy = BearerTokenCredentialPolicy(credential, endpoint_url + '/.default')
78+
79+
self._client = MixedRealityStsRestClient(
80+
base_url=endpoint_url,
81+
authentication_policy=authentication_policy,
82+
sdk_moniker=SDK_MONIKER,
83+
**kwargs)
84+
85+
@distributed_trace
86+
def get_token(self, **kwargs):
87+
# type: (Any) -> AccessToken
88+
"""
89+
Retrieve a token from the STS service for the specified account identifier asynchronously.
90+
:return: Instance of azure.core.credentials.AccessToken - token and expiry date of it
91+
:rtype: ~azure.core.credentials.AccessToken
92+
"""
93+
token_request_options = TokenRequestOptions()
94+
token_request_options.client_request_id = generate_cv_base()
95+
96+
response = self._client.get_token(
97+
self._account_id,
98+
token_request_options=token_request_options,
99+
**kwargs)
100+
return convert_to_access_token(response)
101+
102+
def close(self):
103+
# type: () -> None
104+
self._client.close()
105+
106+
def __enter__(self):
107+
# type: () -> MixedRealityStsClient
108+
self._client.__enter__() # pylint:disable=no-member
109+
return self
110+
111+
def __exit__(self, *args):
112+
# type: (*Any) -> None
113+
self._client.__exit__(*args) # pylint:disable=no-member

0 commit comments

Comments
 (0)